batframework 1.0.8a9__py3-none-any.whl → 1.0.8a10__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- batFramework/__init__.py +68 -51
- batFramework/action.py +126 -99
- batFramework/actionContainer.py +53 -9
- batFramework/animatedSprite.py +141 -82
- batFramework/audioManager.py +69 -26
- batFramework/camera.py +259 -69
- batFramework/character.py +27 -0
- batFramework/constants.py +16 -54
- batFramework/cutscene.py +39 -29
- batFramework/cutsceneBlocks.py +36 -43
- batFramework/dynamicEntity.py +18 -9
- batFramework/easingController.py +58 -0
- batFramework/entity.py +48 -97
- batFramework/enums.py +113 -0
- batFramework/fontManager.py +65 -0
- batFramework/gui/__init__.py +10 -2
- batFramework/gui/button.py +9 -78
- batFramework/gui/clickableWidget.py +220 -0
- batFramework/gui/constraints/__init__.py +1 -0
- batFramework/gui/constraints/constraints.py +815 -0
- batFramework/gui/container.py +174 -32
- batFramework/gui/debugger.py +131 -43
- batFramework/gui/dialogueBox.py +99 -0
- batFramework/gui/draggableWidget.py +40 -0
- batFramework/gui/image.py +56 -20
- batFramework/gui/indicator.py +38 -21
- batFramework/gui/interactiveWidget.py +192 -13
- batFramework/gui/label.py +309 -74
- batFramework/gui/layout.py +231 -63
- batFramework/gui/meter.py +74 -0
- batFramework/gui/radioButton.py +84 -0
- batFramework/gui/root.py +134 -38
- batFramework/gui/shape.py +237 -57
- batFramework/gui/slider.py +240 -0
- batFramework/gui/style.py +10 -0
- batFramework/gui/styleManager.py +48 -0
- batFramework/gui/textInput.py +247 -0
- batFramework/gui/toggle.py +101 -51
- batFramework/gui/widget.py +358 -250
- batFramework/manager.py +52 -19
- batFramework/object.py +123 -0
- batFramework/particle.py +115 -0
- batFramework/renderGroup.py +67 -0
- batFramework/resourceManager.py +100 -0
- batFramework/scene.py +281 -123
- batFramework/sceneManager.py +178 -116
- batFramework/scrollingSprite.py +114 -0
- batFramework/sprite.py +51 -0
- batFramework/stateMachine.py +11 -8
- batFramework/templates/__init__.py +2 -0
- batFramework/templates/character.py +44 -0
- batFramework/templates/states.py +166 -0
- batFramework/tileset.py +46 -0
- batFramework/time.py +145 -58
- batFramework/transition.py +195 -124
- batFramework/triggerZone.py +1 -1
- batFramework/utils.py +112 -147
- batframework-1.0.8a10.dist-info/LICENCE +21 -0
- batframework-1.0.8a10.dist-info/METADATA +43 -0
- batframework-1.0.8a10.dist-info/RECORD +62 -0
- batFramework/debugger.py +0 -48
- batFramework/easing.py +0 -71
- batFramework/gui/constraints.py +0 -204
- batFramework/gui/frame.py +0 -19
- batFramework/particles.py +0 -77
- batFramework/transitionManager.py +0 -0
- batframework-1.0.8a9.dist-info/METADATA +0 -53
- batframework-1.0.8a9.dist-info/RECORD +0 -42
- {batframework-1.0.8a9.dist-info → batframework-1.0.8a10.dist-info}/WHEEL +0 -0
- {batframework-1.0.8a9.dist-info → batframework-1.0.8a10.dist-info}/top_level.txt +0 -0
batFramework/scene.py
CHANGED
@@ -1,203 +1,333 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
import re
|
3
|
-
from
|
3
|
+
from collections import OrderedDict
|
4
|
+
import itertools
|
5
|
+
|
6
|
+
from typing import TYPE_CHECKING, Any
|
4
7
|
if TYPE_CHECKING:
|
5
8
|
from .manager import Manager
|
9
|
+
from .sceneManager import SceneManager
|
6
10
|
import pygame
|
7
11
|
import batFramework as bf
|
8
12
|
|
9
13
|
|
10
14
|
class Scene:
|
11
|
-
def __init__(
|
12
|
-
self
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
15
|
+
def __init__(
|
16
|
+
self,
|
17
|
+
name: str,
|
18
|
+
hud_convert_alpha: bool = True,
|
19
|
+
world_convert_alpha: bool = False,
|
20
|
+
) -> None:
|
21
|
+
"""
|
22
|
+
Initialize the Scene object.
|
23
|
+
|
24
|
+
Args:
|
25
|
+
name: Name of the scene.
|
26
|
+
enable_alpha (bool, optional): Enable alpha channel for the scene surfaces. Defaults to True.
|
27
|
+
"""
|
28
|
+
self.scene_index = 0
|
29
|
+
self.name = name
|
30
|
+
bf.TimeManager().add_register(self.name,False)
|
17
31
|
self.manager: Manager | None = None
|
32
|
+
self.active = False
|
33
|
+
self.visible = False
|
34
|
+
self.world_entities: OrderedDict[bf.Entity, None] = OrderedDict()
|
35
|
+
self.hud_entities: OrderedDict[bf.Entity, None] = OrderedDict()
|
18
36
|
self.actions: bf.ActionContainer = bf.ActionContainer()
|
19
|
-
self.
|
20
|
-
self.
|
21
|
-
self.hud_camera: bf.Camera = bf.Camera()
|
22
|
-
|
23
|
-
|
24
|
-
|
37
|
+
self.early_actions: bf.ActionContainer = bf.ActionContainer()
|
38
|
+
self.camera: bf.Camera = bf.Camera(convert_alpha=world_convert_alpha)
|
39
|
+
self.hud_camera: bf.Camera = bf.Camera(convert_alpha=hud_convert_alpha)
|
40
|
+
self.should_sort :bool = True
|
41
|
+
self.root: bf.Root = bf.Root(self.hud_camera)
|
42
|
+
self.root.rect.center = self.hud_camera.get_center()
|
43
|
+
self.add_hud_entity(self.root)
|
44
|
+
self.entities_to_remove = []
|
45
|
+
self.entities_to_add = []
|
25
46
|
|
26
|
-
self.camera.set_clear_color((0, 0, 0))
|
27
|
-
self.hud_camera.set_clear_color((0, 0, 0, 0))
|
28
47
|
|
29
|
-
|
30
|
-
|
31
|
-
self.add_hud_entity(self.root)
|
32
|
-
self.blit_calls = 0
|
48
|
+
def __str__(self)->str:
|
49
|
+
return f"Scene({self.name})"
|
33
50
|
|
34
|
-
def
|
51
|
+
def get_world_entity_count(self) -> int:
|
52
|
+
return len(self.world_entities)
|
53
|
+
|
54
|
+
def get_hud_entity_count(self) -> int:
|
55
|
+
n = 0
|
56
|
+
|
57
|
+
def adder(e):
|
58
|
+
nonlocal n
|
59
|
+
n += len(e.children)
|
60
|
+
|
61
|
+
self.root.visit(adder)
|
62
|
+
|
63
|
+
return len(self.hud_entities) + n
|
64
|
+
|
65
|
+
def set_scene_index(self, index: int):
|
66
|
+
"""Set the scene index."""
|
35
67
|
self.scene_index = index
|
36
68
|
|
37
|
-
def get_scene_index(self):
|
69
|
+
def get_scene_index(self) -> int:
|
70
|
+
"""Get the scene index."""
|
38
71
|
return self.scene_index
|
39
72
|
|
40
|
-
def set_sharedVar(self, name, value)->bool:
|
41
|
-
|
73
|
+
def set_sharedVar(self, name: str, value: Any) -> bool:
|
74
|
+
"""
|
75
|
+
Set a shared variable in the manager.
|
76
|
+
|
77
|
+
Args:
|
78
|
+
name: Name of the shared variable.
|
79
|
+
value: Value to set.
|
80
|
+
|
81
|
+
Returns:
|
82
|
+
bool: True if setting was successful, False otherwise.
|
83
|
+
"""
|
84
|
+
if not self.manager:
|
85
|
+
return False
|
42
86
|
return self.manager.set_sharedVar(name, value)
|
43
87
|
|
44
|
-
def get_sharedVar(self, name)->Any:
|
45
|
-
|
46
|
-
|
88
|
+
def get_sharedVar(self, name: str, error_value=None) -> Any:
|
89
|
+
"""
|
90
|
+
Get a shared variable from the manager.
|
91
|
+
|
92
|
+
Args:
|
93
|
+
name: Name of the shared variable.
|
94
|
+
|
95
|
+
Returns:
|
96
|
+
Any: Value of the shared variable.
|
97
|
+
"""
|
98
|
+
if not self.manager:
|
99
|
+
return error_value
|
100
|
+
return self.manager.get_sharedVar(name, error_value)
|
47
101
|
|
48
102
|
def do_when_added(self):
|
49
103
|
pass
|
50
104
|
|
51
|
-
def set_clear_color(self, color: pygame.Color|tuple):
|
105
|
+
def set_clear_color(self, color: pygame.Color | tuple):
|
106
|
+
"""Set the clear color for the camera."""
|
52
107
|
self.camera.set_clear_color(color)
|
53
|
-
# self.hud_camera.set_clear_color(color)
|
54
108
|
|
55
109
|
def set_manager(self, manager_link: Manager):
|
110
|
+
"""Set the manager link for the scene."""
|
56
111
|
self.manager = manager_link
|
112
|
+
self.manager.update_scene_states()
|
57
113
|
|
58
114
|
def set_visible(self, value: bool):
|
59
|
-
|
60
|
-
|
115
|
+
"""Set the visibility of the scene."""
|
116
|
+
self.visible = value
|
117
|
+
if self.manager:
|
118
|
+
self.manager.update_scene_states()
|
61
119
|
|
62
120
|
def set_active(self, value):
|
63
|
-
|
64
|
-
|
121
|
+
"""Set the activity of the scene."""
|
122
|
+
self.active = value
|
123
|
+
if self.manager:
|
124
|
+
self.manager.update_scene_states()
|
65
125
|
|
66
126
|
def is_active(self) -> bool:
|
67
|
-
|
127
|
+
"""Check if the scene is active."""
|
128
|
+
return self.active
|
68
129
|
|
69
130
|
def is_visible(self) -> bool:
|
70
|
-
|
131
|
+
"""Check if the scene is visible."""
|
132
|
+
return self.visible
|
71
133
|
|
72
134
|
def get_name(self) -> str:
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
self.
|
96
|
-
e.
|
97
|
-
|
98
|
-
|
99
|
-
def
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
e
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
135
|
+
"""Get the name of the scene."""
|
136
|
+
return self.name
|
137
|
+
|
138
|
+
def add_world_entity(self, *entities: bf.Entity):
|
139
|
+
"""Add world entities to the scene."""
|
140
|
+
change = False
|
141
|
+
for e in entities:
|
142
|
+
if e not in self.world_entities and e not in self.entities_to_add:
|
143
|
+
change = True
|
144
|
+
# self.world_entities[e] = None
|
145
|
+
self.entities_to_add.append(e)
|
146
|
+
e.set_parent_scene(self)
|
147
|
+
# self.sort_entities()
|
148
|
+
return change
|
149
|
+
|
150
|
+
# Updated remove_world_entity method to add entities to the removal list
|
151
|
+
def remove_world_entity(self, *entities: bf.Entity):
|
152
|
+
"""Mark world entities for removal from the scene."""
|
153
|
+
change = False
|
154
|
+
for e in entities:
|
155
|
+
if e in self.world_entities:
|
156
|
+
change = True
|
157
|
+
self.entities_to_remove.append(e)
|
158
|
+
e.set_parent_scene(None)
|
159
|
+
return change
|
160
|
+
|
161
|
+
def add_hud_entity(self, *entities: bf.Entity):
|
162
|
+
"""Add HUD entities to the scene."""
|
163
|
+
for e in entities:
|
164
|
+
if e not in self.hud_entities:
|
165
|
+
self.hud_entities[e] = None
|
166
|
+
e.set_parent_scene(self)
|
167
|
+
self.sort_entities()
|
168
|
+
return True
|
169
|
+
|
170
|
+
def remove_hud_entity(self, *entities: bf.Entity):
|
171
|
+
"""Remove HUD entities from the scene."""
|
172
|
+
for e in entities:
|
173
|
+
if e in self.hud_entities:
|
174
|
+
e.set_parent_scene(None)
|
175
|
+
self.hud_entities.pop(e)
|
176
|
+
|
177
|
+
def add_actions(self, *action):
|
178
|
+
"""Add actions to the scene."""
|
179
|
+
self.actions.add_actions(*action)
|
180
|
+
|
181
|
+
def add_early_actions(self, *action):
|
182
|
+
"""Add actions to the scene."""
|
183
|
+
self.early_actions.add_actions(*action)
|
108
184
|
|
109
185
|
def get_by_tags(self, *tags):
|
110
|
-
|
186
|
+
"""Get entities by their tags."""
|
187
|
+
res = [
|
111
188
|
entity
|
112
|
-
for entity in
|
113
|
-
|
189
|
+
for entity in itertools.chain(
|
190
|
+
self.world_entities.keys(), self.hud_entities.keys()
|
191
|
+
)
|
192
|
+
if any(entity.has_tags(t) for t in tags)
|
114
193
|
]
|
194
|
+
res.extend(list(self.root.get_by_tags(*tags)))
|
195
|
+
return res
|
115
196
|
|
116
197
|
def get_by_uid(self, uid) -> bf.Entity | None:
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
for entity in self._world_entities + self._hud_entities
|
121
|
-
if entity.uid == uid
|
122
|
-
),
|
123
|
-
None,
|
198
|
+
"""Get an entity by its unique identifier."""
|
199
|
+
res = self._find_entity_by_uid(
|
200
|
+
uid, itertools.chain(self.world_entities.keys(), self.hud_entities.keys())
|
124
201
|
)
|
202
|
+
if res is None:
|
203
|
+
res = self._recursive_search_by_uid(uid, self.root)
|
204
|
+
return res
|
125
205
|
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
206
|
+
def _find_entity_by_uid(self, uid, entities) -> bf.Entity | None:
|
207
|
+
"""Search for entity by uid in a list of entities."""
|
208
|
+
for entity in entities:
|
209
|
+
if entity.uid == uid:
|
210
|
+
return entity
|
211
|
+
return None
|
212
|
+
|
213
|
+
def _recursive_search_by_uid(self, uid, widget) -> bf.Entity | None:
|
214
|
+
"""Recursively search for entity by uid in the widget's children."""
|
215
|
+
if widget.uid == uid:
|
216
|
+
return widget
|
217
|
+
|
218
|
+
for child in widget.children:
|
219
|
+
res = self._recursive_search_by_uid(uid, child)
|
220
|
+
if res is not None:
|
221
|
+
return res
|
222
|
+
|
223
|
+
return None
|
130
224
|
|
131
|
-
# propagates event to all entities
|
132
225
|
def process_event(self, event: pygame.Event):
|
133
226
|
"""
|
134
|
-
Propagates event
|
135
|
-
|
227
|
+
Propagates event while it is not consumed.
|
228
|
+
In order :
|
229
|
+
-do_early_handle_event()
|
230
|
+
-scene early_actions
|
231
|
+
-propagate to scene entities (hud then world)
|
232
|
+
-do_handle_event()
|
233
|
+
-scene actions
|
234
|
+
at each step, if the event is consumed the propagation stops
|
136
235
|
"""
|
137
|
-
if
|
236
|
+
if event.consumed:
|
138
237
|
return
|
139
|
-
|
238
|
+
self.do_early_handle_event(event)
|
239
|
+
if event.consumed:
|
140
240
|
return
|
141
|
-
self.
|
241
|
+
self.early_actions.process_event(event)
|
242
|
+
if event.consumed:
|
243
|
+
return
|
244
|
+
for entity in itertools.chain(
|
245
|
+
self.hud_entities.keys(), self.world_entities.keys()
|
246
|
+
):
|
247
|
+
entity.process_event(event)
|
248
|
+
if event.consumed:
|
249
|
+
return
|
142
250
|
self.do_handle_event(event)
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
251
|
+
if event.consumed:
|
252
|
+
return
|
253
|
+
self.actions.process_event(event)
|
254
|
+
|
255
|
+
# called before process event
|
256
|
+
def do_early_handle_event(self, event: pygame.Event):
|
257
|
+
"""Called early in event propagation"""
|
258
|
+
pass
|
147
259
|
|
148
260
|
def do_handle_event(self, event: pygame.Event):
|
149
261
|
"""called inside process_event but before resetting the scene's action container and propagating event to child entities of the scene"""
|
150
262
|
pass
|
151
263
|
|
152
264
|
def update(self, dt):
|
153
|
-
|
265
|
+
"""Update the scene. Do NOT override"""
|
266
|
+
if self.should_sort:
|
267
|
+
self._sort_entities_internal()
|
268
|
+
|
269
|
+
for entity in itertools.chain(
|
270
|
+
self.hud_entities.keys(), self.world_entities.keys()
|
271
|
+
):
|
154
272
|
entity.update(dt)
|
273
|
+
|
155
274
|
self.do_update(dt)
|
156
275
|
self.camera.update(dt)
|
157
276
|
self.hud_camera.update(dt)
|
277
|
+
self.actions.reset()
|
278
|
+
self.early_actions.reset()
|
279
|
+
|
280
|
+
|
281
|
+
if self.entities_to_add:
|
282
|
+
for e in self.entities_to_add:
|
283
|
+
self.world_entities[e] = None
|
284
|
+
self.entities_to_add.clear()
|
285
|
+
|
286
|
+
# Remove marked entities after updating
|
287
|
+
if self.entities_to_remove:
|
288
|
+
for e in self.entities_to_remove:
|
289
|
+
self.world_entities.pop(e, None)
|
290
|
+
self.entities_to_remove.clear()
|
158
291
|
|
159
292
|
def do_update(self, dt):
|
293
|
+
"""Specific update within the scene."""
|
160
294
|
pass
|
161
295
|
|
162
296
|
def debug_entity(self, entity: bf.Entity, camera: bf.Camera):
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
if isinstance(data,pygame.FRect):
|
297
|
+
def draw_rect(data):
|
298
|
+
if data is None:
|
299
|
+
return
|
300
|
+
if isinstance(data, pygame.FRect) or isinstance(data, pygame.Rect):
|
168
301
|
rect = data
|
169
|
-
color = entity.
|
302
|
+
color = entity.debug_color
|
170
303
|
else:
|
171
304
|
rect = data[0]
|
172
305
|
color = data[1]
|
173
|
-
|
306
|
+
pygame.draw.rect(camera.surface, color, camera.world_to_screen(rect), 1)
|
174
307
|
|
175
|
-
|
176
|
-
|
177
|
-
def draw(self, surface: pygame.Surface):
|
178
|
-
self._world_entities.sort(key=lambda e: (e.z_depth,e.render_order))
|
179
|
-
self._hud_entities.sort(key=lambda e: (e.z_depth,e.render_order))
|
180
|
-
|
181
|
-
total_blit_calls = 0
|
182
|
-
self.camera.clear()
|
183
|
-
self.hud_camera.clear()
|
308
|
+
[draw_rect(data) for data in entity.get_debug_outlines()]
|
184
309
|
|
310
|
+
def sort_entities(self) -> None:
|
311
|
+
self.should_sort = True
|
185
312
|
|
186
|
-
|
187
|
-
|
313
|
+
def _sort_entities_internal(self):
|
314
|
+
"""Sort entities within the scene based on their rendering order."""
|
315
|
+
self.world_entities = OrderedDict(
|
316
|
+
sorted(self.world_entities.items(), key=lambda e: e[0].render_order)
|
188
317
|
)
|
189
|
-
|
190
|
-
|
191
|
-
for entity in self._world_entities:
|
192
|
-
self.debug_entity(entity, self.camera)
|
193
|
-
|
194
|
-
total_blit_calls += sum(
|
195
|
-
entity.draw(self.hud_camera) for entity in self._hud_entities
|
318
|
+
self.hud_entities = OrderedDict(
|
319
|
+
sorted(self.hud_entities.items(), key=lambda e: e[0].render_order)
|
196
320
|
)
|
197
|
-
|
198
|
-
for entity in self._hud_entities:
|
199
|
-
self.debug_entity(entity, self.hud_camera)
|
321
|
+
self.should_sort = False
|
200
322
|
|
323
|
+
def draw(self, surface: pygame.Surface):
|
324
|
+
self.camera.clear()
|
325
|
+
self.hud_camera.clear()
|
326
|
+
|
327
|
+
# Draw all world entities
|
328
|
+
self._draw_camera(self.camera, self.world_entities.keys())
|
329
|
+
# Draw all HUD entities
|
330
|
+
self._draw_camera(self.hud_camera, self.hud_entities.keys())
|
201
331
|
|
202
332
|
self.do_early_draw(surface)
|
203
333
|
self.camera.draw(surface)
|
@@ -205,7 +335,12 @@ class Scene:
|
|
205
335
|
self.hud_camera.draw(surface)
|
206
336
|
self.do_final_draw(surface)
|
207
337
|
|
208
|
-
|
338
|
+
def _draw_camera(self, camera: bf.Camera, entity_list):
|
339
|
+
_ = [entity.draw(camera) for entity in entity_list]
|
340
|
+
debugMode = self.manager.debug_mode
|
341
|
+
# Draw outlines for world entities if required
|
342
|
+
if debugMode == bf.debugMode.OUTLINES:
|
343
|
+
[self.debug_entity(e, camera) for e in entity_list]
|
209
344
|
|
210
345
|
def do_early_draw(self, surface: pygame.Surface):
|
211
346
|
pass
|
@@ -219,8 +354,31 @@ class Scene:
|
|
219
354
|
def on_enter(self):
|
220
355
|
self.set_active(True)
|
221
356
|
self.set_visible(True)
|
357
|
+
self.root.clear_hovered()
|
358
|
+
# self.root.clear_focused()
|
359
|
+
self.root.build()
|
360
|
+
bf.TimeManager().activate_register(self.name)
|
361
|
+
self.do_on_enter()
|
362
|
+
# self.root.visit(lambda e : e.resolve_constraints())
|
222
363
|
|
223
364
|
def on_exit(self):
|
365
|
+
self.root.clear_hovered()
|
366
|
+
# self.root.clear_focused()
|
224
367
|
self.set_active(False)
|
225
368
|
self.set_visible(False)
|
226
369
|
self.actions.hard_reset()
|
370
|
+
self.early_actions.hard_reset()
|
371
|
+
bf.TimeManager().deactivate_register(self.name)
|
372
|
+
self.do_on_exit()
|
373
|
+
|
374
|
+
def do_on_enter(self) -> None:
|
375
|
+
pass
|
376
|
+
|
377
|
+
def do_on_exit(self) -> None:
|
378
|
+
pass
|
379
|
+
|
380
|
+
def do_on_enter_early(self) -> None:
|
381
|
+
pass
|
382
|
+
|
383
|
+
def do_on_exit_early(self) -> None:
|
384
|
+
pass
|