batframework 1.0.8a9__py3-none-any.whl → 1.0.8a11__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- batFramework/__init__.py +68 -51
- batFramework/action.py +126 -99
- batFramework/actionContainer.py +53 -9
- batFramework/animatedSprite.py +141 -82
- batFramework/audioManager.py +69 -26
- batFramework/camera.py +259 -69
- batFramework/character.py +27 -0
- batFramework/constants.py +16 -54
- batFramework/cutscene.py +39 -29
- batFramework/cutsceneBlocks.py +36 -43
- batFramework/dynamicEntity.py +18 -9
- batFramework/easingController.py +58 -0
- batFramework/entity.py +48 -97
- batFramework/enums.py +113 -0
- batFramework/fontManager.py +65 -0
- batFramework/gui/__init__.py +10 -2
- batFramework/gui/button.py +9 -78
- batFramework/gui/clickableWidget.py +220 -0
- batFramework/gui/constraints/__init__.py +1 -0
- batFramework/gui/constraints/constraints.py +815 -0
- batFramework/gui/container.py +174 -32
- batFramework/gui/debugger.py +131 -43
- batFramework/gui/dialogueBox.py +99 -0
- batFramework/gui/draggableWidget.py +40 -0
- batFramework/gui/image.py +56 -20
- batFramework/gui/indicator.py +38 -21
- batFramework/gui/interactiveWidget.py +192 -13
- batFramework/gui/label.py +309 -74
- batFramework/gui/layout.py +231 -63
- batFramework/gui/meter.py +74 -0
- batFramework/gui/radioButton.py +84 -0
- batFramework/gui/root.py +134 -38
- batFramework/gui/shape.py +237 -57
- batFramework/gui/slider.py +240 -0
- batFramework/gui/style.py +10 -0
- batFramework/gui/styleManager.py +48 -0
- batFramework/gui/textInput.py +247 -0
- batFramework/gui/toggle.py +101 -51
- batFramework/gui/widget.py +358 -250
- batFramework/manager.py +90 -19
- batFramework/object.py +123 -0
- batFramework/particle.py +115 -0
- batFramework/renderGroup.py +67 -0
- batFramework/resourceManager.py +100 -0
- batFramework/scene.py +281 -123
- batFramework/sceneManager.py +178 -116
- batFramework/scrollingSprite.py +114 -0
- batFramework/sprite.py +51 -0
- batFramework/stateMachine.py +11 -8
- batFramework/templates/__init__.py +2 -0
- batFramework/templates/character.py +44 -0
- batFramework/templates/states.py +166 -0
- batFramework/tileset.py +46 -0
- batFramework/time.py +145 -58
- batFramework/transition.py +195 -124
- batFramework/triggerZone.py +1 -1
- batFramework/utils.py +112 -147
- batframework-1.0.8a11.dist-info/LICENCE +21 -0
- batframework-1.0.8a11.dist-info/METADATA +43 -0
- batframework-1.0.8a11.dist-info/RECORD +62 -0
- {batframework-1.0.8a9.dist-info → batframework-1.0.8a11.dist-info}/WHEEL +1 -1
- batFramework/debugger.py +0 -48
- batFramework/easing.py +0 -71
- batFramework/gui/constraints.py +0 -204
- batFramework/gui/frame.py +0 -19
- batFramework/particles.py +0 -77
- batFramework/transitionManager.py +0 -0
- batframework-1.0.8a9.dist-info/METADATA +0 -53
- batframework-1.0.8a9.dist-info/RECORD +0 -42
- {batframework-1.0.8a9.dist-info → batframework-1.0.8a11.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,166 @@
|
|
1
|
+
import batFramework as bf
|
2
|
+
from typing import TYPE_CHECKING
|
3
|
+
|
4
|
+
if TYPE_CHECKING:
|
5
|
+
from .character import Platform2DCharacter
|
6
|
+
|
7
|
+
|
8
|
+
class CharacterState(bf.State):
|
9
|
+
def set_parent(self, parent):
|
10
|
+
"""Initialize the parent character."""
|
11
|
+
res = super().set_parent(parent)
|
12
|
+
if res:
|
13
|
+
self.parent: Platform2DCharacter = parent
|
14
|
+
return res
|
15
|
+
|
16
|
+
def on_enter(self):
|
17
|
+
"""Handle state entry."""
|
18
|
+
self.parent.set_animation(self.name)
|
19
|
+
|
20
|
+
def handle_input(self):
|
21
|
+
"""Process input and update movement direction."""
|
22
|
+
if self.parent.actions.is_active("right"):
|
23
|
+
self._apply_horizontal_input(self.parent.acceleration, self.parent.speed)
|
24
|
+
if self.parent.actions.is_active("left"):
|
25
|
+
self._apply_horizontal_input(-self.parent.acceleration, -self.parent.speed)
|
26
|
+
|
27
|
+
if self.parent.velocity.x > 0:
|
28
|
+
self.parent.set_flipX(False)
|
29
|
+
elif self.parent.velocity.x < 0:
|
30
|
+
self.parent.set_flipX(True)
|
31
|
+
|
32
|
+
|
33
|
+
def _apply_horizontal_input(self, acceleration, limit):
|
34
|
+
"""Apply input acceleration and enforce speed limit."""
|
35
|
+
|
36
|
+
self.parent.velocity.x += acceleration
|
37
|
+
if abs(self.parent.velocity.x) > abs(limit):
|
38
|
+
self.parent.velocity.x = limit
|
39
|
+
|
40
|
+
def apply_friction(self):
|
41
|
+
"""Apply friction to horizontal velocity."""
|
42
|
+
if (self.parent.actions.is_active("right") or self.parent.actions.is_active("left")):
|
43
|
+
return
|
44
|
+
|
45
|
+
if abs(self.parent.velocity.x) < 0.01: # Threshold for negligible velocity
|
46
|
+
self.parent.velocity.x = 0
|
47
|
+
else:
|
48
|
+
self.parent.velocity.x *= self.parent.friction
|
49
|
+
|
50
|
+
def apply_gravity(self, dt):
|
51
|
+
"""Apply gravity to vertical velocity."""
|
52
|
+
self.parent.velocity.y += self.parent.gravity * dt
|
53
|
+
self.parent.velocity.y = min(self.parent.velocity.y, self.parent.terminal_velocity)
|
54
|
+
|
55
|
+
def move_character(self, dt):
|
56
|
+
"""Move the character based on velocity."""
|
57
|
+
self.parent.rect.x += self.parent.velocity.x * dt
|
58
|
+
self.parent.rect.y += self.parent.velocity.y * dt
|
59
|
+
|
60
|
+
def update(self, dt):
|
61
|
+
"""Update the character state."""
|
62
|
+
self.handle_input()
|
63
|
+
self.apply_physics(dt)
|
64
|
+
self.handle_collision()
|
65
|
+
|
66
|
+
def apply_physics(self, dt):
|
67
|
+
"""Apply all physics effects."""
|
68
|
+
self.apply_friction()
|
69
|
+
self.move_character(dt)
|
70
|
+
if self.parent.on_ground:
|
71
|
+
self.parent.velocity.y = 0 # Stop downward movement on ground
|
72
|
+
|
73
|
+
def handle_collision(self):
|
74
|
+
"""Placeholder for collision detection and resolution."""
|
75
|
+
pass # Future collision code goes here
|
76
|
+
|
77
|
+
|
78
|
+
class Platform2DIdle(CharacterState):
|
79
|
+
def __init__(self) -> None:
|
80
|
+
super().__init__("idle")
|
81
|
+
|
82
|
+
def on_enter(self):
|
83
|
+
self.parent.jump_counter = 0
|
84
|
+
super().on_enter()
|
85
|
+
|
86
|
+
def update(self, dt):
|
87
|
+
super().update(dt)
|
88
|
+
|
89
|
+
if not self.parent.on_ground:
|
90
|
+
self.parent.set_state("fall")
|
91
|
+
elif self.parent.velocity.x != 0:
|
92
|
+
self.parent.set_state("run")
|
93
|
+
elif self.parent.actions.is_active("jump"):
|
94
|
+
self.parent.set_state("jump")
|
95
|
+
|
96
|
+
|
97
|
+
class Platform2DRun(CharacterState):
|
98
|
+
def __init__(self) -> None:
|
99
|
+
super().__init__("run")
|
100
|
+
|
101
|
+
|
102
|
+
def on_enter(self):
|
103
|
+
self.parent.jump_counter = 0
|
104
|
+
super().on_enter()
|
105
|
+
|
106
|
+
def update(self, dt):
|
107
|
+
super().update(dt)
|
108
|
+
|
109
|
+
if self.parent.velocity.x :
|
110
|
+
if (self.parent.actions.is_active("right") or self.parent.actions.is_active("left")):
|
111
|
+
if self.parent.get_current_animation().name != "run" : self.parent.set_animation("run")
|
112
|
+
else:
|
113
|
+
if self.parent.get_current_animation().name != "idle" : self.parent.set_animation("idle")
|
114
|
+
|
115
|
+
if self.parent.actions.is_active("jump"):
|
116
|
+
self.parent.set_state("jump")
|
117
|
+
elif self.parent.velocity.x == 0:
|
118
|
+
if not (self.parent.actions.is_active("right") or self.parent.actions.is_active("left")):
|
119
|
+
self.parent.set_state("idle")
|
120
|
+
elif not self.parent.on_ground:
|
121
|
+
self.parent.set_state("fall")
|
122
|
+
|
123
|
+
|
124
|
+
|
125
|
+
|
126
|
+
class Platform2DJump(CharacterState):
|
127
|
+
def __init__(self) -> None:
|
128
|
+
super().__init__("jump")
|
129
|
+
|
130
|
+
def on_enter(self):
|
131
|
+
super().on_enter()
|
132
|
+
self.parent.on_ground = False
|
133
|
+
self.parent.velocity.y = -self.parent.jump_force
|
134
|
+
self.parent.jump_counter += 1
|
135
|
+
|
136
|
+
def update(self, dt):
|
137
|
+
super().update(dt)
|
138
|
+
self.apply_gravity(dt)
|
139
|
+
|
140
|
+
|
141
|
+
if self.parent.jump_counter < self.parent.max_jumps:
|
142
|
+
if self.parent.actions.is_active("jump") and (self.parent.velocity.y//10)*10 == 0:
|
143
|
+
self.parent.set_state("jump")
|
144
|
+
return
|
145
|
+
|
146
|
+
|
147
|
+
if self.parent.velocity.y > 0:
|
148
|
+
self.parent.set_state("fall")
|
149
|
+
|
150
|
+
|
151
|
+
class Platform2DFall(CharacterState):
|
152
|
+
def __init__(self) -> None:
|
153
|
+
super().__init__("fall")
|
154
|
+
|
155
|
+
def update(self, dt):
|
156
|
+
super().update(dt)
|
157
|
+
self.apply_gravity(dt)
|
158
|
+
|
159
|
+
if self.parent.on_ground:
|
160
|
+
if abs(self.parent.velocity.x) > 0.01:
|
161
|
+
self.parent.set_state("run")
|
162
|
+
else:
|
163
|
+
self.parent.set_state("idle")
|
164
|
+
|
165
|
+
if self.parent.actions.is_active("jump") and self.parent.jump_counter < self.parent.max_jumps:
|
166
|
+
self.parent.set_state("jump")
|
batFramework/tileset.py
ADDED
@@ -0,0 +1,46 @@
|
|
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/time.py
CHANGED
@@ -1,75 +1,162 @@
|
|
1
|
-
import pygame
|
2
1
|
import batFramework as bf
|
2
|
+
from typing import Self
|
3
|
+
|
4
|
+
|
5
|
+
from typing import Callable, Union, Self
|
6
|
+
|
3
7
|
|
4
8
|
class Timer:
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
9
|
+
_count: int = 0
|
10
|
+
_available_ids: set[int] = set()
|
11
|
+
|
12
|
+
def __init__(self, duration: Union[float, int], end_callback: Callable, loop: bool = False, register: str = "global") -> None:
|
13
|
+
if Timer._available_ids:
|
14
|
+
self.uid = Timer._available_ids.pop()
|
15
|
+
else:
|
16
|
+
self.uid = Timer._count
|
17
|
+
Timer._count += 1
|
18
|
+
|
19
|
+
self.register = register
|
20
|
+
self.duration: int | float = duration
|
15
21
|
self.end_callback = end_callback
|
16
|
-
self.reusable:bool = reusable
|
17
|
-
def start(self):
|
18
|
-
# Start the timer and set the start time
|
19
|
-
if self.start_time is None:
|
20
|
-
Time().add_timer(self)
|
21
|
-
|
22
|
-
self.start_time = pygame.time.get_ticks()
|
23
|
-
self.stopped = False
|
24
|
-
self.elapsed_progress = 0.0
|
25
|
-
|
26
|
-
def update(self):
|
27
|
-
if self.stopped : return False
|
28
|
-
current_time = pygame.time.get_ticks()
|
29
|
-
if self.elapsed_progress < 1:
|
30
|
-
# Calculate elapsed progress
|
31
|
-
self.elapsed_progress = (current_time - self.start_time) / self.duration
|
32
|
-
if self.elapsed_progress >= 1:
|
33
|
-
# Timer has completed
|
34
|
-
self.end()
|
35
|
-
return True
|
36
|
-
elif self.loop:
|
37
|
-
# If looping, restart the timer
|
38
|
-
self.start()
|
39
|
-
return False
|
40
22
|
|
41
|
-
|
42
|
-
|
43
|
-
self.
|
23
|
+
self.elapsed_time: float = -1
|
24
|
+
self.is_over: bool = False
|
25
|
+
self.is_looping: bool = loop
|
26
|
+
self.is_paused: bool = False
|
27
|
+
self.do_delete: bool = False
|
28
|
+
|
29
|
+
def __bool__(self)->bool:
|
30
|
+
return self.elapsed_time==-1 or self.is_over
|
31
|
+
|
32
|
+
def __str__(self) -> str:
|
33
|
+
return f"Timer ({self.uid}) {self.elapsed_time}/{self.duration} | {'loop ' if self.is_looping else ''} {'(D) ' if self.do_delete else ''}"
|
34
|
+
|
35
|
+
def stop(self) -> Self:
|
36
|
+
self.elapsed_time = -1
|
37
|
+
self.is_over = False
|
38
|
+
self.is_paused = False
|
39
|
+
return self
|
40
|
+
|
41
|
+
def start(self, force: bool = False) -> Self:
|
42
|
+
if self.elapsed_time != -1 and not force:
|
43
|
+
return self
|
44
|
+
if not bf.TimeManager().add_timer(self,self.register):
|
45
|
+
return self
|
46
|
+
self.elapsed_time = 0
|
47
|
+
self.is_paused = False
|
48
|
+
self.is_over = False
|
49
|
+
return self
|
50
|
+
|
51
|
+
def pause(self) -> Self:
|
52
|
+
self.is_paused = True
|
53
|
+
return self
|
54
|
+
|
55
|
+
def resume(self) -> Self:
|
56
|
+
self.is_paused = False
|
57
|
+
return self
|
58
|
+
|
59
|
+
def delete(self) -> Self:
|
60
|
+
self.do_delete = True
|
61
|
+
return self
|
62
|
+
|
63
|
+
def has_started(self) -> bool:
|
64
|
+
return self.elapsed_time != -1
|
65
|
+
|
66
|
+
def get_progression(self) -> float:
|
67
|
+
if self.elapsed_time < 0:
|
68
|
+
return 0
|
69
|
+
if self.elapsed_time >= self.duration:
|
70
|
+
return 1
|
71
|
+
return self.elapsed_time / self.duration
|
72
|
+
|
73
|
+
def update(self, dt) -> None:
|
74
|
+
if self.elapsed_time < 0 or self.is_paused or self.is_over:
|
75
|
+
return
|
76
|
+
self.elapsed_time += dt
|
77
|
+
# print("update :",self.elapsed_time,self.duration)
|
78
|
+
if self.get_progression() == 1:
|
79
|
+
self.end()
|
44
80
|
|
45
81
|
def end(self):
|
46
|
-
self.elapsed_progress = 1
|
47
|
-
self.stopped = False
|
48
82
|
if self.end_callback:
|
49
83
|
self.end_callback()
|
84
|
+
self.elapsed_time = -1
|
85
|
+
self.is_over = True
|
86
|
+
if self.is_looping:
|
87
|
+
self.start()
|
88
|
+
return
|
89
|
+
|
90
|
+
def should_delete(self) -> bool:
|
91
|
+
return self.is_over or self.do_delete
|
92
|
+
|
93
|
+
def _release_id(self):
|
94
|
+
Timer._available_ids.add(self.uid)
|
95
|
+
|
96
|
+
|
97
|
+
class SceneTimer(Timer):
|
98
|
+
def __init__(self, duration: float | int, end_callback, loop: bool = False, scene_name:str = "global") -> None:
|
99
|
+
super().__init__(duration, end_callback, loop, scene_name)
|
50
100
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
101
|
+
class TimeManager(metaclass=bf.Singleton):
|
102
|
+
class TimerRegister:
|
103
|
+
def __init__(self, active=True):
|
104
|
+
self.active = active
|
105
|
+
self.timers: dict[int | str, Timer] = {}
|
55
106
|
|
107
|
+
def __iter__(self):
|
108
|
+
return iter(self.timers.values())
|
109
|
+
|
110
|
+
def add_timer(self, timer: Timer):
|
111
|
+
self.timers[timer.uid] = timer
|
112
|
+
|
113
|
+
def update(self, dt):
|
114
|
+
expired_timers = []
|
115
|
+
for timer in list(self.timers.values()):
|
116
|
+
if not timer.is_paused:
|
117
|
+
timer.update(dt)
|
118
|
+
if timer.should_delete():
|
119
|
+
expired_timers.append(timer.uid)
|
120
|
+
for uid in expired_timers:
|
121
|
+
self.timers[uid]._release_id()
|
122
|
+
del self.timers[uid]
|
56
123
|
|
57
|
-
class Time(metaclass=bf.Singleton):
|
58
124
|
def __init__(self):
|
59
|
-
|
60
|
-
|
125
|
+
self.registers = {"global": TimeManager.TimerRegister()}
|
126
|
+
|
127
|
+
def add_register(self, name, active=True):
|
128
|
+
if name not in self.registers:
|
129
|
+
self.registers[name] = TimeManager.TimerRegister(active)
|
130
|
+
|
131
|
+
def add_timer(self, timer, register="global") -> bool:
|
132
|
+
if register in self.registers:
|
133
|
+
self.registers[register].add_timer(timer)
|
134
|
+
return True
|
135
|
+
print(f"Register '{register}' does not exist.")
|
136
|
+
return False
|
137
|
+
|
138
|
+
def get_active_registers(self) -> list[TimerRegister]:
|
139
|
+
return [t for t in self.registers.values() if t.active]
|
61
140
|
|
62
|
-
def
|
63
|
-
|
64
|
-
|
141
|
+
def update(self, dt):
|
142
|
+
for register_name, register in self.registers.items():
|
143
|
+
if register.active:
|
144
|
+
register.update(dt)
|
65
145
|
|
66
|
-
def
|
67
|
-
|
68
|
-
|
69
|
-
|
146
|
+
def activate_register(self, name, active=True):
|
147
|
+
if name in self.registers:
|
148
|
+
self.registers[name].active = active
|
149
|
+
else:
|
150
|
+
print(f"Register '{name}' does not exist.")
|
70
151
|
|
71
|
-
|
152
|
+
def deactivate_register(self, name):
|
153
|
+
self.activate_register(name, active=False)
|
72
154
|
|
73
|
-
|
74
|
-
|
75
|
-
|
155
|
+
def __str__(self)->str:
|
156
|
+
res = ""
|
157
|
+
for name,reg in self.registers.items():
|
158
|
+
if not reg.timers:continue
|
159
|
+
res +=name+"\n"
|
160
|
+
for t in reg.timers.values():
|
161
|
+
res +="\t"+str(t)+"\n"
|
162
|
+
return res
|