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