batframework 1.0.8a9__py3-none-any.whl → 1.0.8a10__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 +52 -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.8a10.dist-info/LICENCE +21 -0
- batframework-1.0.8a10.dist-info/METADATA +43 -0
- batframework-1.0.8a10.dist-info/RECORD +62 -0
- 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.8a10.dist-info}/WHEEL +0 -0
- {batframework-1.0.8a9.dist-info → batframework-1.0.8a10.dist-info}/top_level.txt +0 -0
batFramework/animatedSprite.py
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
import batFramework as bf
|
2
2
|
import pygame
|
3
|
+
from typing import List, Dict, Tuple, Union, Optional, Self
|
3
4
|
|
4
5
|
|
5
|
-
|
6
|
-
def search_index(target, lst):
|
6
|
+
def search_index(target: int, lst: List[int]) -> int:
|
7
7
|
cumulative_sum = 0
|
8
8
|
for index, value in enumerate(lst):
|
9
9
|
cumulative_sum += value
|
@@ -12,106 +12,165 @@ def search_index(target, lst):
|
|
12
12
|
return -1
|
13
13
|
|
14
14
|
|
15
|
-
class
|
16
|
-
def __init__(
|
17
|
-
self
|
18
|
-
|
19
|
-
|
15
|
+
class Animation:
|
16
|
+
def __init__(
|
17
|
+
self,
|
18
|
+
name: str
|
19
|
+
) -> None:
|
20
|
+
self.name = name
|
21
|
+
self.frames: list[pygame.Surface] = []
|
22
|
+
self.frames_flipX : list[pygame.Surface] = []
|
23
|
+
self.duration_list = []
|
24
|
+
self.duration_list_length = 1
|
25
|
+
|
26
|
+
def from_surface(self,surface:pygame.Surface,size : Tuple[int,int])->Self:
|
27
|
+
self.frames : List[pygame.Surface] = list(bf.utils.split_surface(surface, size).values())
|
28
|
+
self.frames_flipX : List[pygame.Surface] = list(bf.utils.split_surface(surface, size,func=lambda s : pygame.transform.flip(s,True,False)).values())
|
29
|
+
return self
|
30
|
+
|
31
|
+
def __repr__(self):
|
32
|
+
return f"Animation({self.name})"
|
33
|
+
|
34
|
+
def counter_to_frame(self, counter: Union[float, int]) -> int:
|
35
|
+
if not self.frames :
|
36
|
+
raise ValueError("Animation has no frames")
|
37
|
+
return search_index(
|
38
|
+
int(counter % self.duration_list_length), self.duration_list
|
20
39
|
)
|
21
40
|
|
22
|
-
|
23
|
-
|
24
|
-
self.set_frame_length_list(frame_length_list)
|
25
|
-
|
26
|
-
def get_frame_index(self, counter:float|int):
|
27
|
-
return search_index(int(counter % self.ffl_length), self.frame_length_list)
|
28
|
-
|
29
|
-
def get_frame(self, counter, flip):
|
30
|
-
i = self.get_frame_index(counter)
|
41
|
+
def get_frame(self, counter: Union[float, int], flip: bool) -> pygame.Surface:
|
42
|
+
i = self.counter_to_frame(counter)
|
31
43
|
return self.frames_flipX[i] if flip else self.frames[i]
|
32
44
|
|
33
|
-
def
|
34
|
-
if isinstance(
|
35
|
-
|
36
|
-
if len(
|
37
|
-
raise ValueError("
|
38
|
-
self.
|
39
|
-
self.
|
40
|
-
|
41
|
-
|
42
|
-
class AnimatedSprite(bf.
|
43
|
-
def __init__(self, size=None) -> None:
|
45
|
+
def set_duration_list(self, duration_list: Union[List[int], int]) -> Self:
|
46
|
+
if isinstance(duration_list, int):
|
47
|
+
duration_list = [duration_list] * len(self.frames)
|
48
|
+
if len(duration_list) != len(self.frames):
|
49
|
+
raise ValueError("duration_list should have values for all frames")
|
50
|
+
self.duration_list = duration_list
|
51
|
+
self.duration_list_length = sum(self.duration_list)
|
52
|
+
return self
|
53
|
+
|
54
|
+
class AnimatedSprite(bf.Entity):
|
55
|
+
def __init__(self, size: Optional[Tuple[int, int]] = None) -> None:
|
44
56
|
super().__init__(size, no_surface=True)
|
45
|
-
self.float_counter = 0
|
46
|
-
self.
|
47
|
-
self.
|
48
|
-
self.flipX = False
|
49
|
-
self._locked = False
|
50
|
-
|
51
|
-
|
57
|
+
self.float_counter: float = 0
|
58
|
+
self.animations: Dict[str, Animation] = {}
|
59
|
+
self.current_state: Optional[Animation] = None
|
60
|
+
self.flipX: bool = False
|
61
|
+
self._locked: bool = False
|
62
|
+
self._paused: bool = False
|
63
|
+
self.animation_end_callback = None
|
64
|
+
self.transition_end_animation = None
|
65
|
+
|
66
|
+
def set_animation_end_callback(self,callback)->Self:
|
67
|
+
self.animation_end_callback = callback
|
68
|
+
return self
|
69
|
+
|
70
|
+
@property
|
71
|
+
def paused(self) -> bool:
|
72
|
+
return self._paused
|
73
|
+
|
74
|
+
@paused.setter
|
75
|
+
def paused(self, value: bool) -> None:
|
76
|
+
self._paused = value
|
77
|
+
|
78
|
+
def toggle_pause(self) -> None:
|
79
|
+
self.paused = not self.paused
|
80
|
+
|
81
|
+
def set_counter(self, value: float) -> None:
|
52
82
|
self.float_counter = value
|
53
|
-
|
54
83
|
|
55
|
-
def
|
84
|
+
def set_frame(self, frame_index: int) -> None:
|
85
|
+
if not self.current_state:
|
86
|
+
return
|
87
|
+
self.set_counter(sum(self.current_state.duration_list[:frame_index]))
|
88
|
+
|
89
|
+
def lock(self) -> None:
|
56
90
|
self._locked = True
|
57
91
|
|
58
|
-
def
|
92
|
+
def unlock(self) -> None:
|
59
93
|
self._locked = False
|
60
94
|
|
61
|
-
def set_flipX(self, value):
|
95
|
+
def set_flipX(self, value: bool) -> None:
|
62
96
|
self.flipX = value
|
63
97
|
|
64
|
-
def
|
65
|
-
if not
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
return
|
74
|
-
self.animStates[name] = AnimState(file, *size, frame_length_list)
|
75
|
-
if len(self.animStates) == 1 : self.set_animState(name)
|
98
|
+
def remove_animation(self, name: str) -> bool:
|
99
|
+
if name not in self.animations:
|
100
|
+
return False
|
101
|
+
self.animations.pop(name)
|
102
|
+
if self.current_state and self.current_state.name == name:
|
103
|
+
self.current_state = (
|
104
|
+
list(self.animations.values())[0] if self.animations else None
|
105
|
+
)
|
106
|
+
return True
|
76
107
|
|
77
|
-
def
|
78
|
-
|
108
|
+
def add_animation(
|
109
|
+
self,
|
110
|
+
animation:Animation
|
111
|
+
) -> bool:
|
112
|
+
if animation.name in self.animations:
|
79
113
|
return False
|
80
|
-
self.
|
81
|
-
self.rect = (
|
82
|
-
self.animStates[self.current_animState]
|
83
|
-
.frames[0]
|
84
|
-
.get_frect(center=self.rect.center)
|
85
|
-
)
|
86
|
-
if reset_counter or self.float_counter > sum(
|
87
|
-
self.get_state().frame_length_list
|
88
|
-
):
|
89
|
-
self.float_counter = 0
|
90
|
-
if lock:
|
91
|
-
self.lock_animState()
|
114
|
+
self.animations[animation.name] = animation
|
92
115
|
return True
|
93
116
|
|
94
|
-
def
|
95
|
-
|
117
|
+
def set_animation(
|
118
|
+
self, state: str, reset_counter: bool = True, lock: bool = False
|
119
|
+
) -> bool:
|
120
|
+
if state not in self.animations or self._locked:
|
121
|
+
return False
|
122
|
+
|
123
|
+
animation = self.animations[state]
|
124
|
+
self.current_state = animation
|
96
125
|
|
97
|
-
|
98
|
-
|
99
|
-
self.float_counter
|
100
|
-
)
|
126
|
+
if self.current_state.frames:
|
127
|
+
self.rect = self.current_state.frames[0].get_frect(center=self.rect.center)
|
101
128
|
|
102
|
-
|
103
|
-
if not self.animStates : return
|
104
|
-
self.float_counter += 60 * dt
|
105
|
-
if self.float_counter > self.get_state().ffl_length:
|
129
|
+
if reset_counter or (self.float_counter > animation.duration_list_length):
|
106
130
|
self.float_counter = 0
|
107
|
-
self.do_update(dt)
|
108
131
|
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
132
|
+
if lock:
|
133
|
+
self.lock()
|
134
|
+
|
135
|
+
if self.transition_end_animation is not None:
|
136
|
+
self.transition_end_animation = None
|
137
|
+
return True
|
138
|
+
|
139
|
+
def transition_to_animation(self,transition:str,animation:str)->Self:
|
140
|
+
self.set_animation(transition)
|
141
|
+
self.transition_end_animation = animation
|
142
|
+
return self
|
143
|
+
|
144
|
+
def get_current_animation(self) -> Optional[Animation]:
|
145
|
+
return self.current_state
|
146
|
+
|
147
|
+
def update(self, dt: float) -> None:
|
148
|
+
s = self.get_current_animation()
|
149
|
+
if self.animations and s is not None:
|
150
|
+
if not self.paused:
|
151
|
+
self.float_counter += 60 * dt
|
152
|
+
if self.float_counter > s.duration_list_length:
|
153
|
+
if self.transition_end_animation is not None:
|
154
|
+
# print(f"{self.transition_end_animation=}, {self.get_current_animation()=}")
|
155
|
+
self.set_animation(self.transition_end_animation)
|
156
|
+
if self.animation_end_callback is not None:
|
157
|
+
self.animation_end_callback()
|
158
|
+
self.float_counter = 0
|
159
|
+
super().update(dt)
|
160
|
+
|
161
|
+
|
162
|
+
def get_current_frame(self)->pygame.Surface:
|
163
|
+
return self.current_state.get_frame(self.float_counter, self.flipX)
|
164
|
+
|
165
|
+
def draw(self, camera: bf.Camera) -> None:
|
166
|
+
if (
|
167
|
+
not self.visible
|
168
|
+
or not camera.rect.colliderect(self.rect)
|
169
|
+
or not self.current_state
|
170
|
+
):
|
171
|
+
return
|
113
172
|
camera.surface.blit(
|
114
|
-
self.
|
115
|
-
camera.
|
173
|
+
self.get_current_frame(),
|
174
|
+
camera.world_to_screen(self.rect),
|
116
175
|
)
|
117
|
-
return
|
176
|
+
return
|
batFramework/audioManager.py
CHANGED
@@ -5,24 +5,25 @@ pygame.mixer.init()
|
|
5
5
|
|
6
6
|
|
7
7
|
class AudioManager(metaclass=bf.Singleton):
|
8
|
-
def __init__(self):
|
9
|
-
self.sounds: dict
|
10
|
-
self.musics: dict
|
11
|
-
self.current_music = None
|
12
|
-
self.music_volume = 1
|
13
|
-
self.sound_volume = 1
|
8
|
+
def __init__(self) -> None:
|
9
|
+
self.sounds: dict = {}
|
10
|
+
self.musics: dict = {}
|
11
|
+
self.current_music: str | None = None
|
12
|
+
self.music_volume: float = 1
|
13
|
+
self.sound_volume: float = 1
|
14
14
|
pygame.mixer_music.set_endevent(bf.const.MUSIC_END_EVENT)
|
15
15
|
|
16
|
-
def free_sounds(self, force=False):
|
16
|
+
def free_sounds(self, force: bool = False):
|
17
17
|
if force:
|
18
18
|
self.sounds = {}
|
19
19
|
return
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
to_remove.append(name)
|
20
|
+
self.sounds: dict = {
|
21
|
+
key: value for key, value in self.sounds.items() if value["persistent"]
|
22
|
+
}
|
24
23
|
|
25
|
-
|
24
|
+
def free_music(self):
|
25
|
+
if self.current_music:
|
26
|
+
pygame.mixer.music.unload(self.current_music)
|
26
27
|
|
27
28
|
def set_sound_volume(self, volume: float):
|
28
29
|
self.sound_volume = volume
|
@@ -31,13 +32,19 @@ class AudioManager(metaclass=bf.Singleton):
|
|
31
32
|
self.music_volume = volume
|
32
33
|
pygame.mixer_music.set_volume(volume)
|
33
34
|
|
34
|
-
def
|
35
|
+
def get_music_volume(self) -> float:
|
36
|
+
return self.music_volume
|
37
|
+
|
38
|
+
def get_sound_volume(self) -> float:
|
39
|
+
return self.sound_volume
|
40
|
+
|
41
|
+
def has_sound(self, name: str):
|
35
42
|
return name in self.sounds
|
36
43
|
|
37
44
|
def load_sound(self, name, path, persistent=False) -> pygame.mixer.Sound:
|
38
45
|
if name in self.sounds:
|
39
46
|
return self.sounds[name]["sound"]
|
40
|
-
path = bf.
|
47
|
+
path = bf.ResourceManager().get_path(path)
|
41
48
|
self.sounds[name] = {
|
42
49
|
"path": path,
|
43
50
|
"sound": pygame.mixer.Sound(path),
|
@@ -45,24 +52,57 @@ class AudioManager(metaclass=bf.Singleton):
|
|
45
52
|
}
|
46
53
|
return self.sounds[name]["sound"]
|
47
54
|
|
48
|
-
def
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
55
|
+
def load_sounds(self, sound_data_list: list[tuple[str, str, bool]]) -> None:
|
56
|
+
for data in sound_data_list:
|
57
|
+
self.load_sound(*data)
|
58
|
+
return
|
59
|
+
|
60
|
+
def play_sound(self, name, volume=1) -> bool:
|
61
|
+
"""
|
62
|
+
Play the sound file with the given name.
|
63
|
+
returns True if the sound was played
|
64
|
+
|
65
|
+
"""
|
66
|
+
try:
|
67
|
+
self.sounds[name]["sound"].set_volume(volume * self.sound_volume)
|
68
|
+
self.sounds[name]["sound"].play()
|
69
|
+
return True
|
70
|
+
except KeyError:
|
71
|
+
print(f"Sound '{name}' not loaded in AudioManager.")
|
72
|
+
return False
|
73
|
+
|
74
|
+
def stop_sound(self, name) -> bool:
|
75
|
+
try:
|
54
76
|
self.sounds[name]["sound"].stop()
|
77
|
+
return True
|
78
|
+
except KeyError:
|
79
|
+
return False
|
80
|
+
print(f"Sound '{name}' not loaded in AudioManager.")
|
55
81
|
|
56
82
|
def load_music(self, name, path):
|
57
|
-
self.musics[name] = bf.
|
58
|
-
|
59
|
-
|
60
|
-
|
83
|
+
self.musics[name] = bf.ResourceManager().get_path(path)
|
84
|
+
return
|
85
|
+
|
86
|
+
def load_musics(self, music_data_list: list[tuple[str, str]]):
|
87
|
+
for data in music_data_list:
|
88
|
+
self.load_music(*data)
|
89
|
+
return
|
90
|
+
|
91
|
+
def play_music(self, name, loop=0, fade=500) -> bool:
|
92
|
+
"""
|
93
|
+
Play the sound file with the given 'name'.
|
94
|
+
Fades with the given 'fade' time in ms.
|
95
|
+
Music will loop 'loop' times (indefinitely if -1).
|
96
|
+
returns True if the sound was played
|
97
|
+
"""
|
98
|
+
try:
|
61
99
|
pygame.mixer_music.load(self.musics[name])
|
62
100
|
pygame.mixer_music.play(loop, fade_ms=fade)
|
63
101
|
self.current_music = name
|
64
|
-
|
65
|
-
|
102
|
+
return True
|
103
|
+
except KeyError:
|
104
|
+
return False
|
105
|
+
# print(f"Music '{name}' not loaded in AudioManager.")
|
66
106
|
|
67
107
|
def stop_music(self):
|
68
108
|
if not self.current_music:
|
@@ -83,3 +123,6 @@ class AudioManager(metaclass=bf.Singleton):
|
|
83
123
|
if not self.current_music:
|
84
124
|
return
|
85
125
|
pygame.mixer_music.unpause()
|
126
|
+
|
127
|
+
def get_current_music(self) -> str | None:
|
128
|
+
return self.current_music
|