batframework 1.0.9a10__py3-none-any.whl → 1.1.0__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 (76) hide show
  1. batFramework/__init__.py +52 -76
  2. batFramework/action.py +99 -126
  3. batFramework/actionContainer.py +9 -53
  4. batFramework/animatedSprite.py +114 -56
  5. batFramework/audioManager.py +36 -82
  6. batFramework/camera.py +69 -263
  7. batFramework/constants.py +53 -29
  8. batFramework/cutscene.py +109 -243
  9. batFramework/cutsceneBlocks.py +176 -0
  10. batFramework/debugger.py +48 -0
  11. batFramework/dynamicEntity.py +9 -16
  12. batFramework/easing.py +71 -0
  13. batFramework/entity.py +85 -92
  14. batFramework/gui/__init__.py +3 -14
  15. batFramework/gui/button.py +78 -12
  16. batFramework/gui/constraints.py +204 -0
  17. batFramework/gui/container.py +31 -183
  18. batFramework/gui/debugger.py +43 -126
  19. batFramework/gui/frame.py +19 -0
  20. batFramework/gui/image.py +20 -55
  21. batFramework/gui/indicator.py +22 -95
  22. batFramework/gui/interactiveWidget.py +12 -229
  23. batFramework/gui/label.py +77 -311
  24. batFramework/gui/layout.py +66 -411
  25. batFramework/gui/root.py +35 -203
  26. batFramework/gui/shape.py +57 -247
  27. batFramework/gui/toggle.py +48 -114
  28. batFramework/gui/widget.py +243 -457
  29. batFramework/manager.py +29 -113
  30. batFramework/particles.py +77 -0
  31. batFramework/scene.py +217 -22
  32. batFramework/sceneManager.py +129 -161
  33. batFramework/stateMachine.py +8 -11
  34. batFramework/time.py +75 -0
  35. batFramework/transition.py +124 -129
  36. batFramework/transitionManager.py +0 -0
  37. batFramework/triggerZone.py +4 -4
  38. batFramework/utils.py +144 -266
  39. {batframework-1.0.9a10.dist-info → batframework-1.1.0.dist-info}/METADATA +24 -22
  40. batframework-1.1.0.dist-info/RECORD +43 -0
  41. batFramework/animation.py +0 -77
  42. batFramework/baseScene.py +0 -240
  43. batFramework/cutsceneManager.py +0 -34
  44. batFramework/drawable.py +0 -77
  45. batFramework/easingController.py +0 -58
  46. batFramework/enums.py +0 -135
  47. batFramework/fontManager.py +0 -65
  48. batFramework/gui/animatedLabel.py +0 -89
  49. batFramework/gui/clickableWidget.py +0 -245
  50. batFramework/gui/constraints/__init__.py +0 -1
  51. batFramework/gui/constraints/constraints.py +0 -980
  52. batFramework/gui/draggableWidget.py +0 -44
  53. batFramework/gui/meter.py +0 -96
  54. batFramework/gui/radioButton.py +0 -35
  55. batFramework/gui/selector.py +0 -250
  56. batFramework/gui/slider.py +0 -397
  57. batFramework/gui/style.py +0 -10
  58. batFramework/gui/styleManager.py +0 -54
  59. batFramework/gui/syncedVar.py +0 -49
  60. batFramework/gui/textInput.py +0 -306
  61. batFramework/gui/tooltip.py +0 -30
  62. batFramework/particle.py +0 -118
  63. batFramework/propertyEaser.py +0 -79
  64. batFramework/renderGroup.py +0 -34
  65. batFramework/resourceManager.py +0 -130
  66. batFramework/sceneLayer.py +0 -138
  67. batFramework/scrollingSprite.py +0 -115
  68. batFramework/sprite.py +0 -51
  69. batFramework/templates/__init__.py +0 -1
  70. batFramework/templates/controller.py +0 -97
  71. batFramework/tileset.py +0 -46
  72. batFramework/timeManager.py +0 -213
  73. batframework-1.0.9a10.dist-info/RECORD +0 -67
  74. {batframework-1.0.9a10.dist-info → batframework-1.1.0.dist-info}/LICENSE +0 -0
  75. {batframework-1.0.9a10.dist-info → batframework-1.1.0.dist-info}/WHEEL +0 -0
  76. {batframework-1.0.9a10.dist-info → batframework-1.1.0.dist-info}/top_level.txt +0 -0
@@ -1,138 +0,0 @@
1
- from __future__ import annotations
2
- import batFramework as bf
3
- import pygame
4
- from .entity import Entity
5
- from .drawable import Drawable
6
-
7
- from typing import TYPE_CHECKING, Any
8
- if TYPE_CHECKING:
9
- from .baseScene import BaseScene
10
-
11
- class SceneLayer:
12
- """
13
- A scene layer is a 'dimension' bound to a scene
14
- Each layer contains its own entities and camera
15
- One common use would be to separate GUI and game into two separate layers
16
- """
17
- def __init__(self,name:str,convert_alpha:bool = False):
18
- self.scene = None
19
- self.name = name
20
- self.entities : dict[int,Entity] = {}
21
- self.entities_to_add : set[Entity]= set()
22
- self.entities_to_remove : set[Entity]= set()
23
- self.draw_order : list[int] = []
24
- self.camera = bf.Camera(convert_alpha=convert_alpha)
25
-
26
- def set_clear_color(self,color):
27
- self.camera.set_clear_color(color)
28
-
29
- def set_scene(self, scene:BaseScene):
30
- self.scene = scene
31
-
32
- def add(self,*entities:Entity):
33
- for e in entities:
34
- if e.uid not in self.entities and e not in self.entities_to_add:
35
- self.entities_to_add.add(e)
36
-
37
-
38
- def get_by_tags(self,*tags)->list[Entity]:
39
- return [v for v in self.entities.values() if v.has_tags(*tags) ]
40
-
41
- def get_by_uid(self,uid:int)->Entity|None:
42
- return self.entities.get(uid,None)
43
-
44
- def remove(self,*entities:Entity):
45
- for e in entities:
46
- if e.uid in self.entities and e not in self.entities_to_remove:
47
- self.entities_to_remove.add(e)
48
-
49
- def process_event(self,event:pygame.Event):
50
- if event.type == pygame.VIDEORESIZE and not pygame.SCALED & bf.const.FLAGS:
51
- self.camera.set_size(bf.const.RESOLUTION)
52
-
53
- for e in self.entities.values():
54
- e.process_event(event)
55
- if event.consumed : return
56
-
57
- def update(self, dt):
58
- # Update all entities
59
- for e in self.entities.values():
60
- e.update(dt)
61
-
62
- self.flush_entity_changes()
63
-
64
- # Update the camera
65
- self.camera.update(dt)
66
-
67
- def flush_entity_changes(self):
68
- """
69
- Synchronizes entity changes by removing entities marked for removal,
70
- adding new entities, and updating the draw order if necessary.
71
- """
72
-
73
-
74
- # Remove entities marked for removal
75
- for e in self.entities_to_remove:
76
- if e.uid in self.entities.keys():
77
- e.set_parent_scene(None)
78
- self.entities.pop(e.uid)
79
- self.entities_to_remove.clear()
80
-
81
- # Add new entities
82
- reorder = False
83
- for e in self.entities_to_add:
84
- self.entities[e.uid] = e
85
- e.set_parent_layer(self)
86
- e.set_parent_scene(self.scene)
87
- if not reorder and isinstance(e, Drawable):
88
- reorder = True
89
- self.entities_to_add.clear()
90
-
91
- # Reorder draw order if necessary
92
- if reorder:
93
- self.update_draw_order()
94
-
95
- def clear(self):
96
- """
97
- Clear the camera surface
98
- """
99
- self.camera.clear()
100
-
101
- def draw(self, surface: pygame.Surface):
102
- self.camera.clear()
103
- debugMode = bf.ResourceManager().get_sharedVar("debug_mode")
104
- # Draw entities in the correct order
105
- for uid in self.draw_order:
106
- if uid in self.entities and not self.entities[uid].drawn_by_group: # Ensure the entity still exists
107
- self.entities[uid].draw(self.camera)
108
-
109
- # Draw debug outlines if in debug mode
110
- if debugMode == bf.debugMode.OUTLINES:
111
- [self.debug_entity(uid) for uid in self.draw_order if uid in self.entities]
112
-
113
- # Blit the camera surface onto the provided surface
114
- # surface.blit(self.camera.surface, (0, 0))
115
- self.camera.draw(surface)
116
-
117
- def update_draw_order(self):
118
- self.draw_order = sorted(
119
- (k for k,v in self.entities.items() if isinstance(v,Drawable) and not v.drawn_by_group),
120
- key= lambda uid : self.entities[uid].render_order
121
- )
122
-
123
- def debug_entity(self, uid: int):
124
- entity = self.entities[uid]
125
- def draw_rect(data):
126
- if data is None:
127
- return
128
- if isinstance(data, pygame.FRect) or isinstance(data, pygame.Rect):
129
- rect = data
130
- color = entity.debug_color
131
- else:
132
- rect = data[0]
133
- color = data[1]
134
- if self.camera.intersects(rect):
135
- pygame.draw.rect(self.camera.surface, color, self.camera.world_to_screen(rect), 1)
136
-
137
- for data in entity.get_debug_outlines():
138
- draw_rect(data)
@@ -1,115 +0,0 @@
1
- from typing import Self, Iterator
2
- from pygame.math import Vector2
3
- import batFramework as bf
4
- import pygame
5
-
6
-
7
- class ScrollingSprite(bf.Sprite):
8
- def __init__(
9
- self,
10
- data: pygame.Surface | str,
11
- size: None | tuple[int, int] = None,
12
- convert_alpha: bool = True,
13
- ):
14
- self.scroll_value = Vector2(0, 0)
15
- self.auto_scroll = Vector2(0, 0)
16
-
17
- # Use integer values for the starting points, converted from floating point scroll values
18
-
19
- super().__init__(size, data, convert_alpha)
20
- if self.original_surface:
21
- self.original_width, self.original_height = self.original_surface.get_size()
22
-
23
-
24
- def get_debug_outlines(self):
25
- yield from super().get_debug_outlines()
26
- for r in self._get_mosaic_rect_list():
27
- yield r.move(*self.rect.topleft)
28
-
29
-
30
- def set_autoscroll(self, x: float, y: float) -> Self:
31
- self.auto_scroll.update(x, y)
32
- return self
33
-
34
- def set_scroll(self, x: float = None, y: float = None) -> Self:
35
- self.scroll_value.update(
36
- x if x else self.scroll_value.x, y if y else self.scroll_value.y
37
- )
38
- return self
39
-
40
- def scroll(self, x: float, y: float) -> Self:
41
- self.scroll_value += x, y
42
- return self
43
-
44
- def update(self, dt: float) -> None:
45
- if self.auto_scroll:
46
- self.scroll(*self.auto_scroll * dt)
47
- original_width, original_height = self.original_surface.get_size()
48
-
49
- # Use integer values for the starting points, converted from floating point scroll values
50
-
51
- if self.scroll_value.x > self.original_width:
52
- self.scroll_value.x -= self.original_width
53
- if self.scroll_value.y > self.original_height:
54
- self.scroll_value.y -= self.original_height
55
-
56
- super().update(dt)
57
-
58
- def set_size(self, size: tuple[int | None, int | None]) -> Self:
59
- size = list(size)
60
- if size[0] is None:
61
- size[0] = self.rect.w
62
- if size[1] is None:
63
- size[1] = self.rect.h
64
-
65
- self.surface = pygame.Surface(size).convert_alpha()
66
- self.rect = self.surface.get_frect(topleft=self.rect.topleft)
67
- return self
68
-
69
- def _get_mosaic_rect_list(self,camera:bf.Camera=None) -> Iterator[pygame.Rect]:
70
- # Use integer values for the starting points, converted from floating point scroll values
71
- start_x = int(self.scroll_value.x % self.original_width)
72
- start_y = int(self.scroll_value.y % self.original_height)
73
-
74
- # Adjust start_x and start_y to begin tiling off-screen to the top-left, covering all visible area
75
- if start_x != 0:
76
- start_x -= self.original_width
77
- if start_y != 0:
78
- start_y -= self.original_height
79
-
80
- # Set the region in which to tile
81
- end_x = self.rect.w
82
- end_y = self.rect.h
83
-
84
- # Starting y_position for the inner loop
85
- y_position = start_y
86
-
87
- # if self.rect.w-1 < self.scroll_value.x < self.rect.w+1 : print(self.scroll_value.x,int(self.scroll_value.x % self.rect.w),start_x,self.rect.w,original_width)
88
- # Generate all necessary rectangles
89
- x = start_x
90
- while x < end_x:
91
- y = y_position
92
- while y < end_y:
93
- r = pygame.Rect(x, y, self.original_width, self.original_height)
94
-
95
- if camera and camera.rect.colliderect((x+camera.rect.x,y+camera.rect.y,self.original_width,self.original_height)):
96
- yield r
97
- else:
98
- yield r
99
- y += self.original_height
100
- x += self.original_width
101
- return self
102
-
103
- def draw(self, camera: bf.Camera) -> None:
104
- if not (
105
- self.visible
106
- and (self.surface is not None)
107
- and camera.rect.colliderect(self.rect)
108
- ):
109
- return
110
- # self.surface.fill((0, 0, 0, 0))
111
- camera.surface.fblits(
112
- [(self.original_surface, r.move(self.rect.x-camera.rect.x,self.rect.y-camera.rect.y)) for r in self._get_mosaic_rect_list(camera)]
113
- )
114
- # camera.surface.blit(self.surface, camera.world_to_screen(self.rect))
115
- return
batFramework/sprite.py DELETED
@@ -1,51 +0,0 @@
1
- import batFramework as bf
2
- import pygame
3
- from typing import Self
4
-
5
-
6
- class Sprite(bf.Drawable):
7
- def __init__(
8
- self,
9
- path=None,
10
- size: None | tuple[int, int] = None,
11
- convert_alpha: bool = True,
12
- ):
13
- self.original_surface: pygame.Surface = None
14
-
15
- super().__init__(convert_alpha=convert_alpha)
16
- if path is not None:
17
- self.from_path(path)
18
- if size is not None and self.original_surface:
19
- self.set_size(self.original_surface.get_size())
20
-
21
- def set_size(self, size: tuple[float, float]) -> Self:
22
- if size == self.rect.size:
23
- return self
24
- self.rect.size = size
25
- self.surface = pygame.Surface(
26
- (int(self.rect.w), int(self.rect.h)), self.surface_flags
27
- )
28
- if self.convert_alpha:
29
- self.surface = self.surface.convert_alpha()
30
- self.surface.fill((0, 0, 0, 0 if self.convert_alpha else 255))
31
- self.surface.blit(
32
- pygame.transform.scale(self.original_surface, self.rect.size), (0, 0)
33
- )
34
- return self
35
-
36
- def from_path(self, path: str) -> Self:
37
- tmp = bf.ResourceManager().get_image(path, self.convert_alpha)
38
- if tmp is None:
39
- return self
40
- self.original_surface = tmp
41
- size = self.original_surface.get_size()
42
- self.set_size(size)
43
- return self
44
-
45
- def from_surface(self, surface: pygame.Surface) -> Self:
46
- if surface is None:
47
- return self
48
- self.original_surface = surface
49
- size = self.original_surface.get_size()
50
- self.set_size(size)
51
- return self
@@ -1 +0,0 @@
1
- from .controller import *
@@ -1,97 +0,0 @@
1
- import batFramework as bf
2
- import pygame
3
-
4
- class PlatformController(bf.DynamicEntity):
5
- def __init__(self,*args,**kwargs):
6
- super().__init__(*args,**kwargs)
7
- self.control = bf.ActionContainer()
8
- self.speed = 500
9
- self.acceleration = 100
10
- self.jump_force = -500
11
- self.gravity = 1200
12
- self.on_ground = False
13
- self.friction = 0.7
14
-
15
- def do_reset_actions(self):
16
- self.control.reset()
17
-
18
- def do_process_actions(self, event):
19
- self.control.process_event(event)
20
-
21
- def check_collision_y(self):
22
- pass
23
-
24
- def check_collision_x(self):
25
- pass
26
-
27
- def update(self, dt):
28
- super().update(dt)
29
- self.velocity.x *= self.friction
30
- if abs(self.velocity.x) <= 0.01:
31
- self.velocity.x = 0
32
- if not self.on_ground:
33
- self.velocity.y += self.gravity * dt
34
- if self.control.is_active("left"):
35
- self.velocity.x -= self.acceleration
36
- if self.control.is_active("right"):
37
- self.velocity.x += self.acceleration
38
- if self.on_ground and self.control.is_active("jump") :
39
- self.velocity.y = self.jump_force
40
- self.on_ground = False
41
-
42
- self.velocity.x = pygame.math.clamp(self.velocity.x,-self.speed,self.speed)
43
- self.rect.x += self.velocity.x * dt
44
- self.check_collision_x()
45
- self.rect.y += self.velocity.y * dt
46
- self.check_collision_y()
47
-
48
-
49
-
50
- class TopDownController(bf.DynamicEntity):
51
- def __init__(self,*args,**kwargs):
52
- super().__init__(*args,**kwargs)
53
- self.control = bf.ActionContainer()
54
- self.input_velocity = pygame.Vector2()
55
- self.speed = 500
56
- self.acceleration = 100
57
- self.friction = 0
58
-
59
- def do_reset_actions(self):
60
- self.control.reset()
61
-
62
- def do_process_actions(self, event):
63
- self.control.process_event(event)
64
-
65
- def check_collision_y(self):
66
- pass
67
-
68
- def check_collision_x(self):
69
- pass
70
-
71
- def update(self, dt):
72
- super().update(dt)
73
- self.input_velocity.update(0,0)
74
- self.velocity *= self.friction
75
-
76
- if abs(self.velocity.x) <= 0.01:
77
- self.velocity.x = 0
78
- if self.control.is_active("left"):
79
- self.input_velocity[0] = -self.acceleration
80
- if self.control.is_active("right"):
81
- self.input_velocity[0] = self.acceleration
82
- if self.control.is_active("up"):
83
- self.input_velocity[1] = -self.acceleration
84
- if self.control.is_active("down"):
85
- self.input_velocity[1] = self.acceleration
86
-
87
- if self.input_velocity:
88
- self.input_velocity.normalize_ip()
89
-
90
- self.velocity += self.input_velocity * self.acceleration
91
- self.velocity.clamp_magnitude_ip(self.speed)
92
-
93
-
94
- self.rect.x += self.velocity.x * dt
95
- self.check_collision_x()
96
- self.rect.y += self.velocity.y * dt
97
- self.check_collision_y()
batFramework/tileset.py DELETED
@@ -1,46 +0,0 @@
1
- import pygame
2
- from .resourceManager import ResourceManager
3
- import batFramework as bf
4
-
5
-
6
- class Tileset:
7
- def __init__(self, source: pygame.Surface, tilesize: tuple[int, int]) -> None:
8
- self.surface = source
9
- self.tile_size = tilesize
10
- self.tile_width = source.get_width() // tilesize[0]
11
- self.tile_height = source.get_height() // tilesize[1]
12
- # Create flipped versions of the tileset surface
13
- self.flipped_surfaces = {
14
- (False, False): self.surface,
15
- (False, True): pygame.transform.flip(self.surface, False, True),
16
- (True, False): pygame.transform.flip(self.surface, True, False),
17
- (True, True): pygame.transform.flip(self.surface, True, True),
18
- }
19
-
20
- # Split each of the surfaces into tiles
21
- self.tile_dict = {}
22
- for flip_state, surf in self.flipped_surfaces.items():
23
- tiles = bf.utils.split_surface(surf, self.tile_size)
24
- for coord, tile in tiles.items():
25
- if coord not in self.tile_dict:
26
- self.tile_dict[coord] = {}
27
- self.tile_dict[coord][flip_state] = tile
28
-
29
- def __str__(self) -> str:
30
- num_tiles = 0
31
- if self.tile_dict:
32
- num_tiles = len(self.tile_dict.values())
33
- return f"{num_tiles} tiles | Tile size : {self.tile_size}"
34
-
35
- def get_tile(
36
- self, x: int, y: int, flipX=False, flipY=False
37
- ) -> pygame.Surface | None:
38
- if flipX:
39
- x = self.tile_width - 1 - x
40
- if flipY:
41
- y = self.tile_height - 1 - y
42
- tile_data = self.tile_dict.get((x, y), None)
43
- if tile_data is None:
44
- return None
45
-
46
- return tile_data.get((flipX, flipY), None)
@@ -1,213 +0,0 @@
1
- import batFramework as bf
2
- from typing import Callable, Union, Self,Any
3
-
4
- class Timer:
5
- _count: int = 0
6
- _available_ids: set[int] = set()
7
-
8
- def __init__(self, duration: float, end_callback: Callable[[], Any], loop: int = 0, register: str = "global") -> None:
9
- if Timer._available_ids:
10
- self.uid = Timer._available_ids.pop()
11
- else:
12
- self.uid = Timer._count
13
- Timer._count += 1
14
-
15
- self.register = register
16
- self.duration: float = duration
17
- self.end_callback = end_callback
18
-
19
- self.elapsed_time: float = 0
20
- self.is_over: bool = False
21
- self.loop: int = loop # Number of loops (-1 for infinite)
22
- self.is_paused: bool = False
23
- self.do_delete: bool = False
24
- self.is_stopped: bool = True
25
-
26
- def __bool__(self) -> bool:
27
- return self.elapsed_time != -1 and self.is_over
28
-
29
- def __str__(self) -> str:
30
- loop_info = "infinite" if self.loop == -1 else f"{self.loop} loops left"
31
- return f"Timer ({self.uid}) {self.elapsed_time}/{self.duration} | {loop_info} {'(D) ' if self.do_delete else ''}"
32
-
33
- def stop(self) -> Self:
34
- """
35
- Cancels all progression and stops the timer.
36
- Does not mark it for deletion and does not call the end_callback.
37
- Prevents automatic restart if looping.
38
- """
39
- self.is_stopped = True
40
- self.is_paused = False
41
- self.is_over = False
42
- self.elapsed_time = 0
43
- return self
44
-
45
- def start(self, force: bool = False) -> Self:
46
- """
47
- Starts the timer only if not already started (unless force is used, which resets it).
48
- """
49
- if self.elapsed_time > 0 and not force:
50
- return self
51
- if not bf.TimeManager().add_timer(self, self.register):
52
- return self
53
- self.elapsed_time = 0
54
- self.is_paused = False
55
- self.is_over = False
56
- self.is_stopped = False
57
- return self
58
-
59
- def pause(self) -> Self:
60
- """
61
- Momentarily stops the timer until resume is called.
62
- """
63
- self.is_paused = True
64
- return self
65
-
66
- def resume(self) -> Self:
67
- """
68
- Resumes from a paused state.
69
- """
70
- self.is_paused = False
71
- return self
72
-
73
- def delete(self) -> Self:
74
- """
75
- Marks the timer for deletion.
76
- """
77
- self.do_delete = True
78
- return self
79
-
80
- def has_started(self) -> bool:
81
- """
82
- Returns True if the timer has started.
83
- """
84
- return not self.is_stopped
85
-
86
- def get_progression(self) -> float:
87
- """
88
- Returns the progression of the timer (0 to 1) as a float.
89
- """
90
- if self.is_stopped:
91
- return 0
92
- if self.elapsed_time >= self.duration:
93
- return 1
94
- return self.elapsed_time / self.duration
95
-
96
- def update(self, dt) -> None:
97
- if self.is_stopped or self.is_paused or self.is_over:
98
- return
99
- self.elapsed_time += dt
100
- if self.get_progression() == 1:
101
- self.end()
102
-
103
- def end(self):
104
- """
105
- Ends the timer progression (calls the end_callback function).
106
- Is called automatically once the timer is over.
107
- Will not mark the timer for deletion.
108
- If it is looping, it will restart the timer **only if it wasn't stopped**.
109
- """
110
- self.is_over = True
111
- if self.end_callback:
112
- self.end_callback()
113
-
114
- # Handle looping
115
- if self.loop == -1: # Infinite looping
116
- self.elapsed_time = 0
117
- self.start()
118
- return
119
- elif self.loop > 0: # Decrease loop count and restart
120
- self.loop -= 1
121
- self.elapsed_time = 0
122
- self.start()
123
- return
124
-
125
- # Stop the timer if no loops are left
126
- self.is_stopped = True
127
-
128
- def should_delete(self) -> bool:
129
- """
130
- Method that returns if the timer is to be deleted.
131
- Required for timer management.
132
- """
133
- return self.is_over or self.do_delete
134
-
135
- def _release_id(self):
136
- Timer._available_ids.add(self.uid)
137
-
138
- class SceneTimer(Timer):
139
- """
140
- A timer that is only updated while the given scene is active (being updated)
141
- """
142
- def __init__(self, duration: float | int, end_callback, loop: int = 0, scene_name:str = "global") -> None:
143
- super().__init__(duration, end_callback, loop, scene_name)
144
-
145
- class TimeManager(metaclass=bf.Singleton):
146
- class TimerRegister:
147
- def __init__(self, active=True):
148
- self.active = active
149
- self.timers: dict[int | str, Timer] = {}
150
-
151
- def __iter__(self):
152
- return iter(self.timers.values())
153
-
154
- def add_timer(self, timer: Timer):
155
- self.timers[timer.uid] = timer
156
-
157
- def update(self, dt):
158
- expired_timers = []
159
- for timer in list(self.timers.values()):
160
- if not timer.is_paused:
161
- timer.update(dt)
162
- if timer.should_delete():
163
- expired_timers.append(timer.uid)
164
- for uid in expired_timers:
165
- self.timers[uid]._release_id()
166
- del self.timers[uid]
167
-
168
- def __init__(self):
169
- self.registers = {"global": TimeManager.TimerRegister()}
170
-
171
- def add_register(self, name, active=True):
172
- if name not in self.registers:
173
- self.registers[name] = TimeManager.TimerRegister(active)
174
-
175
- def remove_register(self, name):
176
- if name not in self.registers:
177
- return
178
-
179
- self.registers.pop(name)
180
-
181
-
182
- def add_timer(self, timer, register="global") -> bool:
183
- if register in self.registers:
184
- self.registers[register].add_timer(timer)
185
- return True
186
- print(f"Register '{register}' does not exist.")
187
- return False
188
-
189
- def get_active_registers(self) -> list[TimerRegister]:
190
- return [t for t in self.registers.values() if t.active]
191
-
192
- def update(self, dt):
193
- for register in self.registers.values():
194
- if register.active:
195
- register.update(dt)
196
-
197
- def activate_register(self, name, active=True):
198
- if name in self.registers:
199
- self.registers[name].active = active
200
- else:
201
- print(f"Register '{name}' does not exist.")
202
-
203
- def deactivate_register(self, name):
204
- self.activate_register(name, active=False)
205
-
206
- def __str__(self)->str:
207
- res = ""
208
- for name,reg in self.registers.items():
209
- if not reg.timers:continue
210
- res +=name+"\n"
211
- for t in reg.timers.values():
212
- res +="\t"+str(t)+"\n"
213
- return res