batframework 1.0.8a3__py3-none-any.whl → 1.0.8a6__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 (44) hide show
  1. batFramework/__init__.py +16 -2
  2. batFramework/animatedSprite.py +94 -85
  3. batFramework/audioManager.py +2 -2
  4. batFramework/character.py +27 -0
  5. batFramework/cutscene.py +5 -2
  6. batFramework/cutsceneBlocks.py +3 -5
  7. batFramework/dynamicEntity.py +11 -4
  8. batFramework/enums.py +2 -2
  9. batFramework/fontManager.py +2 -2
  10. batFramework/gui/clickableWidget.py +10 -9
  11. batFramework/gui/constraints/constraints.py +282 -57
  12. batFramework/gui/image.py +14 -14
  13. batFramework/gui/interactiveWidget.py +16 -1
  14. batFramework/gui/label.py +58 -37
  15. batFramework/gui/layout.py +23 -14
  16. batFramework/gui/meter.py +10 -7
  17. batFramework/gui/radioButton.py +1 -1
  18. batFramework/gui/root.py +7 -1
  19. batFramework/gui/shape.py +21 -37
  20. batFramework/gui/slider.py +52 -58
  21. batFramework/gui/textInput.py +161 -51
  22. batFramework/gui/toggle.py +27 -41
  23. batFramework/gui/widget.py +68 -35
  24. batFramework/manager.py +17 -5
  25. batFramework/object.py +17 -8
  26. batFramework/particle.py +22 -8
  27. batFramework/resourceManager.py +18 -2
  28. batFramework/scene.py +50 -20
  29. batFramework/sceneManager.py +52 -28
  30. batFramework/scrollingSprite.py +7 -8
  31. batFramework/stateMachine.py +9 -6
  32. batFramework/templates/__init__.py +2 -0
  33. batFramework/templates/character.py +44 -0
  34. batFramework/templates/states.py +166 -0
  35. batFramework/time.py +54 -28
  36. batFramework/transition.py +25 -12
  37. batFramework/triggerZone.py +1 -1
  38. batFramework/utils.py +92 -2
  39. {batframework-1.0.8a3.dist-info → batframework-1.0.8a6.dist-info}/METADATA +3 -15
  40. batframework-1.0.8a6.dist-info/RECORD +62 -0
  41. {batframework-1.0.8a3.dist-info → batframework-1.0.8a6.dist-info}/WHEEL +1 -1
  42. batframework-1.0.8a3.dist-info/RECORD +0 -58
  43. {batframework-1.0.8a3.dist-info → batframework-1.0.8a6.dist-info}/LICENCE +0 -0
  44. {batframework-1.0.8a3.dist-info → batframework-1.0.8a6.dist-info}/top_level.txt +0 -0
@@ -35,6 +35,8 @@ class Widget(bf.Entity, metaclass=WidgetMeta):
35
35
  self.is_root: bool = False
36
36
  self.autoresize_w, self.autoresize_h = True, True
37
37
  self.__constraint_iteration = 0
38
+ self.__constraints_to_ignore = []
39
+ self.__constraints_capture = None
38
40
 
39
41
  def show(self) -> Self:
40
42
  self.visit(lambda w: w.set_visible(True))
@@ -110,7 +112,7 @@ class Widget(bf.Entity, metaclass=WidgetMeta):
110
112
  ]
111
113
  return self
112
114
 
113
- def set_parent_scene(self, parent_scene: bf.Scene) -> Self:
115
+ def set_parent_scene(self, parent_scene: bf.Scene | None) -> Self:
114
116
  super().set_parent_scene(parent_scene)
115
117
  if parent_scene is None:
116
118
  bf.StyleManager().remove_widget(self)
@@ -122,8 +124,8 @@ class Widget(bf.Entity, metaclass=WidgetMeta):
122
124
  def set_parent(self, parent: "Widget") -> Self:
123
125
  if parent == self.parent:
124
126
  return self
125
- if self.parent is not None:
126
- self.parent.remove(self)
127
+ # if self.parent is not None and self.parent != parent:
128
+ # self.parent.remove(self)
127
129
  self.parent = parent
128
130
  return self
129
131
 
@@ -188,47 +190,75 @@ class Widget(bf.Entity, metaclass=WidgetMeta):
188
190
  seen = set()
189
191
  result = []
190
192
  for c in self.constraints:
191
- if c.name not in seen:
193
+ if not any(c == o for o in seen):
192
194
  result.append(c)
193
195
  seen.add(c.name)
194
196
  self.constraints = result
195
197
  self.constraints.sort(key=lambda c: c.priority)
196
198
  self.dirty_constraints = True
199
+ self.__constraint_to_ignore = []
200
+
201
+ return self
202
+
203
+
204
+ def remove_constraints(self, *names: str) -> Self:
205
+ for c in self.constraints:
206
+ if c.name in names:
207
+ c.on_removal(self)
208
+ self.constraints = [c for c in self.constraints if c.name not in names]
209
+ self.__constraint_to_ignore = []
197
210
  return self
198
211
 
199
212
  def resolve_constraints(self) -> None:
200
213
  if self.parent is None or not self.constraints:
201
214
  self.dirty_constraints = False
202
215
  return
203
- all_good = False
204
- constraint_iteration = 0
205
- while not all_good:
206
- for constraint in self.constraints:
207
- if not constraint.evaluate(self.parent, self):
208
- constraint.apply(self.parent, self)
209
- # print(constraint.name,"Applied")
210
- constraint_iteration += 1
211
- if all(c.evaluate(self.parent, self) for c in self.constraints):
212
- all_good = True
216
+
217
+ if not self.__constraint_iteration:
218
+ self.__constraints_capture = None
219
+ else:
220
+ capture = tuple([c.priority for c in self.constraints])
221
+ if capture != self.__constraints_capture:
222
+ self.__constraints_capture = capture
223
+ self.__constraint_to_ignore = []
224
+
225
+ constraints = self.constraints.copy()
226
+ # If all are resolved early exit
227
+ if all(c.evaluate(self.parent,self) for c in constraints if c not in self.__constraint_to_ignore):
228
+ self.dirty_constraints = False
229
+ return
230
+
231
+ # # Here there might be a conflict between 2 or more constraints
232
+ # we have to determine which ones causes conflict and ignore the one with least priority
233
+
234
+ stop = False
235
+
236
+ while True:
237
+ stop = True
238
+ # first pass with 2 iterations to sort out the transformative constraints
239
+ for _ in range(2):
240
+ for c in constraints:
241
+ if c in self.__constraints_to_ignore:continue
242
+ if not c.evaluate(self.parent,self) :
243
+ c.apply(self.parent,self)
244
+ # second pass where we check conflicts
245
+ for c in constraints:
246
+ if c in self.__constraints_to_ignore:
247
+ continue
248
+ if not c.evaluate(self.parent,self):
249
+ # first pass invalidated this constraint
250
+ self.__constraints_to_ignore.append(c)
251
+ stop = False
252
+ break
253
+
254
+ if stop:
213
255
  break
214
- elif self.__constraint_iteration > MAX_CONSTRAINTS:
215
- print(
216
- self,
217
- "CONSTRAINTS ERROR",
218
- list(
219
- c.name
220
- for c in self.constraints
221
- if not c.evaluate(self.parent, self)
222
- ),
223
- )
224
- self.dirty_constraints = False
225
- return
226
- # print("DONE")
227
- self.dirty_constraints = False
228
256
 
229
- def remove_constraints(self, *names: str) -> Self:
230
- self.constraints = [c for c in self.constraints if c.name not in names]
231
- return self
257
+ if self.__constraints_to_ignore:
258
+ print("Constraints ignored : ",[str(c) for c in self.__constraints_to_ignore])
259
+
260
+
261
+ self.dirty_constraints = False
232
262
 
233
263
  def has_constraint(self, name: str) -> bool:
234
264
  return any(c.name == name for c in self.constraints)
@@ -236,7 +266,9 @@ class Widget(bf.Entity, metaclass=WidgetMeta):
236
266
  def get_root(self) -> "Root":
237
267
  if self.is_root:
238
268
  return self
239
- return self.parent.get_root()
269
+ if self.parent:
270
+ return self.parent.get_root()
271
+ return None
240
272
 
241
273
  def top_at(self, x: float | int, y: float | int) -> "None|Widget":
242
274
  if self.children:
@@ -251,6 +283,7 @@ class Widget(bf.Entity, metaclass=WidgetMeta):
251
283
  self.children.extend(children)
252
284
  i = len(self.children)
253
285
  for child in children:
286
+
254
287
  child.set_render_order(i).set_parent(self).set_parent_scene(
255
288
  self.parent_scene
256
289
  )
@@ -262,8 +295,8 @@ class Widget(bf.Entity, metaclass=WidgetMeta):
262
295
  def remove(self, *children: "Widget") -> Self:
263
296
  for child in self.children:
264
297
  if child in children:
265
- self.children.remove(child)
266
298
  child.set_parent(None).set_parent_scene(None)
299
+ self.children.remove(child)
267
300
  if self.parent:
268
301
  self.parent.do_sort_children = True
269
302
 
@@ -271,9 +304,7 @@ class Widget(bf.Entity, metaclass=WidgetMeta):
271
304
  size = list(size)
272
305
  size[0] = size[0] if self.autoresize_w else None
273
306
  size[1] = size[1] if self.autoresize_h else None
274
-
275
307
  self.set_size(size)
276
-
277
308
  return self
278
309
 
279
310
  def set_size(self, size: tuple) -> Self:
@@ -305,10 +336,12 @@ class Widget(bf.Entity, metaclass=WidgetMeta):
305
336
  def build(self) -> None:
306
337
  new_size = tuple(map(int, self.rect.size))
307
338
  if self.surface.get_size() != new_size:
339
+ old_alpha = self.surface.get_alpha()
308
340
  new_size = [max(0, i) for i in new_size]
309
341
  self.surface = pygame.Surface(new_size, self.surface_flags)
310
342
  if self.convert_alpha:
311
343
  self.surface = self.surface.convert_alpha()
344
+ self.surface.set_alpha(old_alpha)
312
345
 
313
346
  def paint(self) -> None:
314
347
  self.surface.fill((0, 0, 0, 0))
batFramework/manager.py CHANGED
@@ -24,12 +24,24 @@ class Manager(bf.SceneManager):
24
24
  pygame.display.set_icon(surf)
25
25
 
26
26
  def print_status(self):
27
+ """
28
+ Print detailed information about the current state of the scenes, shared variables,
29
+ and additional timers managed by the subclass.
30
+ """
31
+ # Call the parent class's print_status method to include its information
27
32
  super().print_status()
28
- print("TIMERS : ")
29
- for r in self._timeManager.get_active_registers():
30
- # print(r["timers"])
31
- print("\n".join(str(t) for t in r))
32
- print("-" * 40)
33
+
34
+ # Add the timers information in a cohesive manner
35
+ print("\n" + "=" * 50)
36
+ print(" TIMERS".center(50))
37
+ print("=" * 50)
38
+
39
+ # Print the timers information
40
+ print(self._timeManager)
41
+
42
+ # End with a visual separator
43
+ print("=" * 50 + "\n")
44
+
33
45
 
34
46
  def get_fps(self) -> float:
35
47
  return self._clock.get_fps()
batFramework/object.py CHANGED
@@ -8,7 +8,9 @@ if TYPE_CHECKING:
8
8
 
9
9
 
10
10
  class Object:
11
- __instance_count = 0
11
+ __count = 0
12
+ __available_uid = set()
13
+ __used_uid = set()
12
14
 
13
15
  def __init__(self) -> None:
14
16
  self.rect = pygame.FRect(0, 0, 0, 0)
@@ -16,14 +18,17 @@ class Object:
16
18
  self.parent_scene: bf.Scene | None = None
17
19
  self.debug_color: tuple | str = "red"
18
20
  self.render_order: int = 0
19
- self.uid: int = Object.__instance_count
20
- Object.__instance_count += 1
21
+ self.uid: int = Object.__count
22
+ Object.__used_uid.add(self.uid)
21
23
 
22
- @staticmethod
23
- def new_uid() -> int:
24
- i = Object.__instance_count
25
- Object.__instance_count += 1
26
- return i
24
+ if Object.__available_uid:
25
+ self.name = Object.__available_uid.pop()
26
+ else:
27
+ self.name = Object.__count
28
+ Object.__count += 1
29
+
30
+ def __del__(self):
31
+ Object.__available_uid.add(self.uid)
27
32
 
28
33
  def set_position(self, x, y) -> Self:
29
34
  self.rect.topleft = x, y
@@ -57,7 +62,11 @@ class Object:
57
62
  pass
58
63
 
59
64
  def set_uid(self, uid: int) -> Self:
65
+ if uid in Object.__used_uid:
66
+ print(f"set_uid error : UID '{uid}' is already in use")
67
+ return self
60
68
  self.uid = uid
69
+ Object.__used_uid.add(uid)
61
70
  return self
62
71
 
63
72
  def add_tags(self, *tags) -> Self:
batFramework/particle.py CHANGED
@@ -7,6 +7,10 @@ class Particle:
7
7
  def __init__(self, *args, **kwargs):
8
8
  self.dead = False
9
9
  self.surface = None
10
+ self.generator = None
11
+
12
+ def do_when_added(self):
13
+ pass
10
14
 
11
15
  def update(self, dt):
12
16
  pass
@@ -21,7 +25,15 @@ class Particle:
21
25
  class TimedParticle(Particle):
22
26
  def __init__(self, duration):
23
27
  super().__init__()
24
- self.timer = bf.Timer(duration, end_callback=self.kill).start()
28
+ self.duration = duration
29
+
30
+ def do_when_added(self):
31
+ if self.generator and self.generator.parent_scene:
32
+ self.timer = bf.SceneTimer(
33
+ self.duration, end_callback=self.kill,
34
+ scene_name=self.generator.parent_scene.name).start()
35
+ else:
36
+ self.timer = bf.Timer(self.duration, end_callback=self.kill).start()
25
37
 
26
38
 
27
39
  class BasicParticle(TimedParticle):
@@ -36,8 +48,9 @@ class BasicParticle(TimedParticle):
36
48
  **kwargs,
37
49
  ):
38
50
  super().__init__(duration)
39
- self.rect = pygame.FRect(*start_pos, *size)
40
- self.surface = pygame.Surface(size).convert()
51
+ self.rect = pygame.FRect(0,0, *size)
52
+ self.rect.center = start_pos
53
+ self.surface = pygame.Surface(size)
41
54
  self.velocity = Vector2(start_vel)
42
55
  if color:
43
56
  self.surface.fill(color)
@@ -57,7 +70,6 @@ class BasicParticle(TimedParticle):
57
70
 
58
71
  class DirectionalParticle(BasicParticle):
59
72
  def start(self):
60
- self.surface = self.surface.convert_alpha()
61
73
  self.original_surface = self.surface.copy()
62
74
 
63
75
  def update_surface(self):
@@ -72,6 +84,7 @@ class ParticleGenerator(bf.Entity):
72
84
  self.particles: list[Particle] = []
73
85
 
74
86
  def get_debug_outlines(self):
87
+ return
75
88
  for particle in self.particles:
76
89
  yield (
77
90
  particle.rect.move(particle.rect.w // 2, particle.rect.h // 2),
@@ -79,7 +92,9 @@ class ParticleGenerator(bf.Entity):
79
92
  )
80
93
  yield (self.rect, "cyan")
81
94
 
82
- def add_particle(self, particle):
95
+ def add_particle(self, particle:Particle):
96
+ particle.generator = self
97
+ particle.do_when_added()
83
98
  self.particles.append(particle)
84
99
 
85
100
  def clear(self):
@@ -94,8 +109,7 @@ class ParticleGenerator(bf.Entity):
94
109
  for p in particles_to_remove:
95
110
  self.particles.remove(p)
96
111
 
97
- def draw(self, camera) -> bool:
112
+ def draw(self, camera) -> None:
98
113
  camera.surface.fblits(
99
- [(p.surface, camera.world_to_screen(p.rect).center) for p in self.particles]
114
+ [(p.surface, camera.world_to_screen(p.rect)) for p in self.particles]
100
115
  )
101
- return len(self.particles)
@@ -3,6 +3,7 @@ import os
3
3
  import pygame
4
4
  import sys
5
5
  import json
6
+ from typing import Any
6
7
  from .utils import Singleton
7
8
 
8
9
  if getattr(sys, "frozen", False):
@@ -16,6 +17,7 @@ else:
16
17
 
17
18
  class ResourceManager(metaclass=Singleton):
18
19
  def __init__(self):
20
+ self.shared_variables: dict[str,Any] = {}
19
21
  self.convert_image_cache = {}
20
22
  self.convert_alpha_image_cache = {}
21
23
  self.sound_cache = {}
@@ -33,11 +35,11 @@ class ResourceManager(metaclass=Singleton):
33
35
  # print(f"Loaded image : '{file_path}'")
34
36
 
35
37
  elif file.lower().endswith((".mp3", ".wav")):
36
- bf.AudioManager().load_sound(file.lower().split(".")[0], file_path)
38
+ bf.AudioManager().load_sound(file.split(".")[0], file_path)
37
39
  # print(f"Loaded sound : '{file_path}'")
38
40
 
39
41
  elif file.lower().endswith((".ttf", ".otf")):
40
- bf.FontManager().load_font(file_path, file.lower().split(".")[0])
42
+ bf.FontManager().load_font(file_path, file.split(".")[0])
41
43
  # print(f"Loaded font : '{file_path}'")
42
44
 
43
45
  print(f"Loaded resources in directory : '{path}'")
@@ -82,3 +84,17 @@ class ResourceManager(metaclass=Singleton):
82
84
  return True
83
85
  except FileNotFoundError:
84
86
  return False
87
+
88
+
89
+ def set_sharedVar(self, name, value) -> bool:
90
+ """
91
+ Set a shared variable of any type. This will be accessible (read/write) from any scene
92
+ """
93
+ self.shared_variables[name] = value
94
+ return True
95
+
96
+ def get_sharedVar(self, name, error_value=None):
97
+ """
98
+ Get a shared variable
99
+ """
100
+ return self.shared_variables.get(name, error_value)
batFramework/scene.py CHANGED
@@ -1,9 +1,9 @@
1
1
  from __future__ import annotations
2
2
  import re
3
- from typing import TYPE_CHECKING, Any
4
3
  from collections import OrderedDict
5
4
  import itertools
6
5
 
6
+ from typing import TYPE_CHECKING, Any
7
7
  if TYPE_CHECKING:
8
8
  from .manager import Manager
9
9
  from .sceneManager import SceneManager
@@ -27,6 +27,7 @@ class Scene:
27
27
  """
28
28
  self.scene_index = 0
29
29
  self.name = name
30
+ bf.TimeManager().add_register(self.name,False)
30
31
  self.manager: Manager | None = None
31
32
  self.active = False
32
33
  self.visible = False
@@ -36,10 +37,16 @@ class Scene:
36
37
  self.early_actions: bf.ActionContainer = bf.ActionContainer()
37
38
  self.camera: bf.Camera = bf.Camera(convert_alpha=world_convert_alpha)
38
39
  self.hud_camera: bf.Camera = bf.Camera(convert_alpha=hud_convert_alpha)
39
-
40
+ self.should_sort :bool = True
40
41
  self.root: bf.Root = bf.Root(self.hud_camera)
41
42
  self.root.rect.center = self.hud_camera.get_center()
42
43
  self.add_hud_entity(self.root)
44
+ self.entities_to_remove = []
45
+ self.entities_to_add = []
46
+
47
+
48
+ def __str__(self)->str:
49
+ return f"Scene({self.name})"
43
50
 
44
51
  def get_world_entity_count(self) -> int:
45
52
  return len(self.world_entities)
@@ -130,31 +137,33 @@ class Scene:
130
137
 
131
138
  def add_world_entity(self, *entities: bf.Entity):
132
139
  """Add world entities to the scene."""
140
+ change = False
133
141
  for e in entities:
134
- if e not in self.world_entities:
135
- self.world_entities[e] = None
136
- e.parent_scene = self
137
- e.do_when_added()
138
- self.sort_entities()
139
-
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
140
151
  def remove_world_entity(self, *entities: bf.Entity):
141
- """Remove world entities from the scene."""
142
- removed = False
152
+ """Mark world entities for removal from the scene."""
153
+ change = False
143
154
  for e in entities:
144
155
  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
156
+ change = True
157
+ self.entities_to_remove.append(e)
158
+ e.set_parent_scene(None)
159
+ return change
150
160
 
151
161
  def add_hud_entity(self, *entities: bf.Entity):
152
162
  """Add HUD entities to the scene."""
153
163
  for e in entities:
154
164
  if e not in self.hud_entities:
155
165
  self.hud_entities[e] = None
156
- e.parent_scene = self
157
- e.do_when_added()
166
+ e.set_parent_scene(self)
158
167
  self.sort_entities()
159
168
  return True
160
169
 
@@ -162,9 +171,8 @@ class Scene:
162
171
  """Remove HUD entities from the scene."""
163
172
  for e in entities:
164
173
  if e in self.hud_entities:
165
- e.do_when_removed()
166
- e.parent_scene = None
167
- del self.hud_entities[e]
174
+ e.set_parent_scene(None)
175
+ self.hud_entities.pop(e)
168
176
 
169
177
  def add_actions(self, *action):
170
178
  """Add actions to the scene."""
@@ -255,16 +263,32 @@ class Scene:
255
263
 
256
264
  def update(self, dt):
257
265
  """Update the scene. Do NOT override"""
266
+ if self.should_sort:
267
+ self._sort_entities_internal()
268
+
258
269
  for entity in itertools.chain(
259
270
  self.hud_entities.keys(), self.world_entities.keys()
260
271
  ):
261
272
  entity.update(dt)
273
+
262
274
  self.do_update(dt)
263
275
  self.camera.update(dt)
264
276
  self.hud_camera.update(dt)
265
277
  self.actions.reset()
266
278
  self.early_actions.reset()
267
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()
291
+
268
292
  def do_update(self, dt):
269
293
  """Specific update within the scene."""
270
294
  pass
@@ -284,6 +308,9 @@ class Scene:
284
308
  [draw_rect(data) for data in entity.get_debug_outlines()]
285
309
 
286
310
  def sort_entities(self) -> None:
311
+ self.should_sort = True
312
+
313
+ def _sort_entities_internal(self):
287
314
  """Sort entities within the scene based on their rendering order."""
288
315
  self.world_entities = OrderedDict(
289
316
  sorted(self.world_entities.items(), key=lambda e: e[0].render_order)
@@ -291,6 +318,7 @@ class Scene:
291
318
  self.hud_entities = OrderedDict(
292
319
  sorted(self.hud_entities.items(), key=lambda e: e[0].render_order)
293
320
  )
321
+ self.should_sort = False
294
322
 
295
323
  def draw(self, surface: pygame.Surface):
296
324
  self.camera.clear()
@@ -329,6 +357,7 @@ class Scene:
329
357
  self.root.clear_hovered()
330
358
  # self.root.clear_focused()
331
359
  self.root.build()
360
+ bf.TimeManager().activate_register(self.name)
332
361
  self.do_on_enter()
333
362
  # self.root.visit(lambda e : e.resolve_constraints())
334
363
 
@@ -339,6 +368,7 @@ class Scene:
339
368
  self.set_visible(False)
340
369
  self.actions.hard_reset()
341
370
  self.early_actions.hard_reset()
371
+ bf.TimeManager().deactivate_register(self.name)
342
372
  self.do_on_exit()
343
373
 
344
374
  def do_on_enter(self) -> None:
@@ -10,16 +10,15 @@ def swap(lst, index1, index2):
10
10
  class SceneManager:
11
11
  def __init__(self) -> None:
12
12
  self.scenes: list[bf.Scene] = []
13
- self.shared_variables: dict = {}
14
13
  self.shared_events = {pygame.WINDOWRESIZED}
15
14
 
16
15
  self.set_sharedVar("in_cutscene", False)
17
16
  self.set_sharedVar("player_has_control", True)
18
-
17
+ self.old_player_control = True
19
18
  self.debug_mode: bf.enums.debugMode = bf.debugMode.HIDDEN
20
19
  self.current_transitions: dict[str, bf.transition.Transition] = {}
21
20
 
22
- def init_scenes(self, *initial_scenes):
21
+ def init_scenes(self, *initial_scenes:bf.Scene):
23
22
  for index, s in enumerate(initial_scenes):
24
23
  s.set_scene_index(index)
25
24
  for s in reversed(initial_scenes):
@@ -36,33 +35,55 @@ class SceneManager:
36
35
 
37
36
  def print_status(self):
38
37
  """
39
- Print some information about the current state of the scenes.
40
- """
41
- print("-" * 40)
42
- print(
43
- "\n".join(
44
- f" {s.name:<30}\t{'Active' if s.active else 'Inactive'}\t{'Visible' if s.visible else 'Invisible'}\tindex= {s.scene_index}"
45
- for s in self.scenes
46
- )
47
- )
48
- print(f"[Debugging] = {self.debug_mode}")
49
- print("---SHARED VARIABLES---")
50
- for name, value in self.shared_variables.items():
51
- print(f"[{str(name)} = {str(value)}]")
52
- print("-" * 40)
53
-
54
- def set_sharedVar(self, name, value) -> bool:
55
- """
56
- Set a shared variable of any type. This will be accessible (read/write) from any scene
38
+ Print detailed information about the current state of the scenes and shared variables.
57
39
  """
58
- self.shared_variables[name] = value
59
- return True
40
+
41
+ def format_scene_info(scene):
42
+ status = 'Active' if scene.active else 'Inactive'
43
+ visibility = 'Visible' if scene.visible else 'Invisible'
44
+ return f"{scene.name:<30} | {status:<8} | {visibility:<10} | Index={scene.scene_index}"
45
+
46
+ def format_shared_variable(name, value):
47
+ return f"[{name}] = {value}"
48
+
49
+ print("\n" + "=" * 50)
50
+ print(" SCENE STATUS".center(50))
51
+ print("=" * 50)
52
+
53
+ # Print scene information
54
+ if self.scenes:
55
+ header = f"{'Scene Name':<30} | {'Status':<8} | {'Visibility':<10} | {'Index':<7}"
56
+ print(header)
57
+ print("-" * 50)
58
+ print("\n".join(format_scene_info(s) for s in self.scenes))
59
+ else:
60
+ print("No scenes available.")
61
+
62
+ # Print debugging mode status
63
+ print("\n" + "=" * 50)
64
+ print(" DEBUGGING STATUS".center(50))
65
+ print("=" * 50)
66
+ print(f"[Debugging Mode] = {self.debug_mode}")
67
+
68
+ # Print shared variables
69
+ print("\n" + "=" * 50)
70
+ print(" SHARED VARIABLES".center(50))
71
+ print("=" * 50)
72
+
73
+ if bf.ResourceManager().shared_variables:
74
+ for name, value in bf.ResourceManager().shared_variables.items():
75
+ print(format_shared_variable(name, value))
76
+ else:
77
+ print("No shared variables available.")
78
+
79
+ print("=" * 50 + "\n")
80
+
81
+
82
+ def set_sharedVar(self, name, value) -> None:
83
+ bf.ResourceManager().set_sharedVar(name,value)
60
84
 
61
85
  def get_sharedVar(self, name, error_value=None):
62
- """
63
- Get a shared variable
64
- """
65
- return self.shared_variables.get(name, error_value)
86
+ return bf.ResourceManager().get_sharedVar(name, error_value)
66
87
 
67
88
  def get_current_scene_name(self) -> str:
68
89
  """get the name of the current scene"""
@@ -129,11 +150,11 @@ class SceneManager:
129
150
  def _start_transition(self, target_scene: bf.Scene):
130
151
  target_scene.set_active(True)
131
152
  target_scene.set_visible(True)
153
+ self.old_player_control = bool(self.get_sharedVar("player_has_control"))
132
154
  self.set_sharedVar("player_has_control", False)
133
155
 
134
156
  def _end_transition(self, scene_name, index):
135
157
  self.set_scene(scene_name, index, True)
136
- self.set_sharedVar("player_has_control", True)
137
158
  self.current_transitions.clear()
138
159
 
139
160
  def set_scene(self, scene_name, index=0, ignore_early: bool = False):
@@ -156,6 +177,9 @@ class SceneManager:
156
177
  self.scenes[index].do_on_enter_early()
157
178
  target_scene.on_enter()
158
179
 
180
+ self.set_sharedVar("player_has_control", self.old_player_control)
181
+
182
+
159
183
  def cycle_debug_mode(self):
160
184
  current_index = self.debug_mode.value
161
185
  next_index = (current_index + 1) % len(bf.debugMode)