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.
- batFramework/__init__.py +52 -76
- batFramework/action.py +99 -126
- batFramework/actionContainer.py +9 -53
- batFramework/animatedSprite.py +114 -56
- batFramework/audioManager.py +36 -82
- batFramework/camera.py +69 -263
- batFramework/constants.py +53 -29
- batFramework/cutscene.py +109 -243
- batFramework/cutsceneBlocks.py +176 -0
- batFramework/debugger.py +48 -0
- batFramework/dynamicEntity.py +9 -16
- batFramework/easing.py +71 -0
- batFramework/entity.py +85 -92
- batFramework/gui/__init__.py +3 -14
- batFramework/gui/button.py +78 -12
- batFramework/gui/constraints.py +204 -0
- batFramework/gui/container.py +31 -183
- batFramework/gui/debugger.py +43 -126
- batFramework/gui/frame.py +19 -0
- batFramework/gui/image.py +20 -55
- batFramework/gui/indicator.py +22 -95
- batFramework/gui/interactiveWidget.py +12 -229
- batFramework/gui/label.py +77 -311
- batFramework/gui/layout.py +66 -411
- batFramework/gui/root.py +35 -203
- batFramework/gui/shape.py +57 -247
- batFramework/gui/toggle.py +48 -114
- batFramework/gui/widget.py +243 -457
- batFramework/manager.py +29 -113
- batFramework/particles.py +77 -0
- batFramework/scene.py +217 -22
- batFramework/sceneManager.py +129 -161
- batFramework/stateMachine.py +8 -11
- batFramework/time.py +75 -0
- batFramework/transition.py +124 -129
- batFramework/transitionManager.py +0 -0
- batFramework/triggerZone.py +4 -4
- batFramework/utils.py +144 -266
- {batframework-1.0.9a10.dist-info → batframework-1.1.0.dist-info}/METADATA +24 -22
- batframework-1.1.0.dist-info/RECORD +43 -0
- batFramework/animation.py +0 -77
- batFramework/baseScene.py +0 -240
- batFramework/cutsceneManager.py +0 -34
- batFramework/drawable.py +0 -77
- batFramework/easingController.py +0 -58
- batFramework/enums.py +0 -135
- batFramework/fontManager.py +0 -65
- batFramework/gui/animatedLabel.py +0 -89
- batFramework/gui/clickableWidget.py +0 -245
- batFramework/gui/constraints/__init__.py +0 -1
- batFramework/gui/constraints/constraints.py +0 -980
- batFramework/gui/draggableWidget.py +0 -44
- batFramework/gui/meter.py +0 -96
- batFramework/gui/radioButton.py +0 -35
- batFramework/gui/selector.py +0 -250
- batFramework/gui/slider.py +0 -397
- batFramework/gui/style.py +0 -10
- batFramework/gui/styleManager.py +0 -54
- batFramework/gui/syncedVar.py +0 -49
- batFramework/gui/textInput.py +0 -306
- batFramework/gui/tooltip.py +0 -30
- batFramework/particle.py +0 -118
- batFramework/propertyEaser.py +0 -79
- batFramework/renderGroup.py +0 -34
- batFramework/resourceManager.py +0 -130
- batFramework/sceneLayer.py +0 -138
- batFramework/scrollingSprite.py +0 -115
- batFramework/sprite.py +0 -51
- batFramework/templates/__init__.py +0 -1
- batFramework/templates/controller.py +0 -97
- batFramework/tileset.py +0 -46
- batFramework/timeManager.py +0 -213
- batframework-1.0.9a10.dist-info/RECORD +0 -67
- {batframework-1.0.9a10.dist-info → batframework-1.1.0.dist-info}/LICENSE +0 -0
- {batframework-1.0.9a10.dist-info → batframework-1.1.0.dist-info}/WHEEL +0 -0
- {batframework-1.0.9a10.dist-info → batframework-1.1.0.dist-info}/top_level.txt +0 -0
batFramework/sceneLayer.py
DELETED
@@ -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)
|
batFramework/scrollingSprite.py
DELETED
@@ -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)
|
batFramework/timeManager.py
DELETED
@@ -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
|