batframework 1.0.8a2__py3-none-any.whl → 1.0.8a3__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 (65) hide show
  1. batFramework/__init__.py +53 -50
  2. batFramework/action.py +126 -99
  3. batFramework/actionContainer.py +53 -9
  4. batFramework/animatedSprite.py +115 -65
  5. batFramework/audioManager.py +69 -26
  6. batFramework/camera.py +259 -69
  7. batFramework/constants.py +16 -54
  8. batFramework/cutscene.py +36 -29
  9. batFramework/cutsceneBlocks.py +37 -42
  10. batFramework/dynamicEntity.py +9 -7
  11. batFramework/easingController.py +58 -0
  12. batFramework/entity.py +48 -97
  13. batFramework/enums.py +113 -0
  14. batFramework/fontManager.py +65 -0
  15. batFramework/gui/__init__.py +10 -2
  16. batFramework/gui/button.py +9 -78
  17. batFramework/gui/clickableWidget.py +219 -0
  18. batFramework/gui/constraints/__init__.py +1 -0
  19. batFramework/gui/constraints/constraints.py +590 -0
  20. batFramework/gui/container.py +174 -32
  21. batFramework/gui/debugger.py +131 -43
  22. batFramework/gui/dialogueBox.py +99 -0
  23. batFramework/gui/draggableWidget.py +40 -0
  24. batFramework/gui/image.py +54 -18
  25. batFramework/gui/indicator.py +38 -21
  26. batFramework/gui/interactiveWidget.py +177 -13
  27. batFramework/gui/label.py +288 -74
  28. batFramework/gui/layout.py +219 -60
  29. batFramework/gui/meter.py +71 -0
  30. batFramework/gui/radioButton.py +84 -0
  31. batFramework/gui/root.py +128 -38
  32. batFramework/gui/shape.py +253 -57
  33. batFramework/gui/slider.py +246 -0
  34. batFramework/gui/style.py +10 -0
  35. batFramework/gui/styleManager.py +48 -0
  36. batFramework/gui/textInput.py +137 -0
  37. batFramework/gui/toggle.py +115 -51
  38. batFramework/gui/widget.py +329 -254
  39. batFramework/manager.py +40 -19
  40. batFramework/object.py +114 -0
  41. batFramework/particle.py +101 -0
  42. batFramework/renderGroup.py +67 -0
  43. batFramework/resourceManager.py +84 -0
  44. batFramework/scene.py +242 -114
  45. batFramework/sceneManager.py +145 -107
  46. batFramework/scrollingSprite.py +115 -0
  47. batFramework/sprite.py +51 -0
  48. batFramework/stateMachine.py +2 -2
  49. batFramework/tileset.py +46 -0
  50. batFramework/time.py +117 -57
  51. batFramework/transition.py +184 -126
  52. batFramework/utils.py +31 -156
  53. batframework-1.0.8a3.dist-info/LICENCE +21 -0
  54. batframework-1.0.8a3.dist-info/METADATA +55 -0
  55. batframework-1.0.8a3.dist-info/RECORD +58 -0
  56. batFramework/debugger.py +0 -48
  57. batFramework/easing.py +0 -71
  58. batFramework/gui/constraints.py +0 -204
  59. batFramework/gui/frame.py +0 -19
  60. batFramework/particles.py +0 -77
  61. batFramework/transitionManager.py +0 -0
  62. batframework-1.0.8a2.dist-info/METADATA +0 -58
  63. batframework-1.0.8a2.dist-info/RECORD +0 -42
  64. {batframework-1.0.8a2.dist-info → batframework-1.0.8a3.dist-info}/WHEEL +0 -0
  65. {batframework-1.0.8a2.dist-info → batframework-1.0.8a3.dist-info}/top_level.txt +0 -0
@@ -2,7 +2,6 @@ import batFramework as bf
2
2
  import pygame
3
3
 
4
4
 
5
-
6
5
  def search_index(target, lst):
7
6
  cumulative_sum = 0
8
7
  for index, value in enumerate(lst):
@@ -13,105 +12,156 @@ def search_index(target, lst):
13
12
 
14
13
 
15
14
  class AnimState:
16
- def __init__(self, file, width, height, frame_length_list:list|int) -> None:
17
- self.frames: list[pygame.Surface] = bf.utils.img_slice(file, width, height)
18
- self.frames_flipX: list[pygame.Surface] = bf.utils.img_slice(
19
- file, width, height, True
15
+ def __init__(
16
+ self,
17
+ name: str,
18
+ surface: pygame.Surface,
19
+ width,
20
+ height,
21
+ duration_list: list | int,
22
+ ) -> None:
23
+ self.frames: list[pygame.Surface] = list(
24
+ bf.utils.split_surface(
25
+ surface, width, height, False, convert_alpha
26
+ ).values()
27
+ )
28
+ self.frames_flipX: list[pygame.Surface] = list(
29
+ bf.utils.split_surface(surface, width, height, True, convert_alpha).values()
20
30
  )
21
31
 
22
- self.frame_length_list = []
23
- self.ffl_length = 0
24
- self.set_frame_length_list(frame_length_list)
32
+ self.name = name
33
+ self.duration_list: list[int] = []
34
+ self.duration_list_length = 0
35
+ self.set_duration_list(duration_list)
25
36
 
26
- def get_frame_index(self, counter:float|int):
27
- return search_index(int(counter % self.ffl_length), self.frame_length_list)
37
+ def __repr__(self):
38
+ return f"AnimState({self.name})"
39
+
40
+ def counter_to_frame(self, counter: float | int) -> int:
41
+ return search_index(
42
+ int(counter % self.duration_list_length), self.duration_list
43
+ )
28
44
 
29
45
  def get_frame(self, counter, flip):
30
- i = self.get_frame_index(counter)
46
+ i = self.counter_to_frame(counter)
31
47
  return self.frames_flipX[i] if flip else self.frames[i]
32
48
 
33
- def set_frame_length_list(self,frame_length_list:list[int]|int):
34
- if isinstance(frame_length_list,int):
35
- frame_length_list = [frame_length_list] * len(self.frames)
36
- if len(frame_length_list) != len(self.frames) :
37
- raise ValueError("frame_length_list should have values for all frames")
38
- self.frame_length_list = frame_length_list
39
- self.ffl_length = sum(self.frame_length_list)
40
-
49
+ def set_duration_list(self, duration_list: list[int] | int):
50
+ if isinstance(duration_list, int):
51
+ duration_list = [duration_list] * len(self.frames)
52
+ if len(duration_list) != len(self.frames):
53
+ raise ValueError("duration_list should have values for all frames")
54
+ self.duration_list = duration_list
55
+ self.duration_list_length = sum(self.duration_list)
56
+
41
57
 
42
58
  class AnimatedSprite(bf.DynamicEntity):
43
59
  def __init__(self, size=None) -> None:
44
60
  super().__init__(size, no_surface=True)
45
- self.float_counter = 0
61
+ self.float_counter: float = 0
46
62
  self.animStates: dict[str, AnimState] = {}
47
- self.current_animState :str = ""
63
+ self.current_state: AnimState | None = None
48
64
  self.flipX = False
49
65
  self._locked = False
66
+ self.paused: bool = False
67
+
68
+ def pause(self) -> None:
69
+ self.paused = True
70
+
71
+ def resume(self) -> None:
72
+ self.paused = False
50
73
 
51
- def set_counter(self,value:float):
74
+ def toggle_pause(self) -> None:
75
+ self.paused = not self.paused
76
+
77
+ def set_counter(self, value: float) -> None:
52
78
  self.float_counter = value
53
-
54
79
 
55
- def lock_animState(self):
80
+ def set_frame(self, frame_index: int) -> None:
81
+ if not self.current_state:
82
+ return
83
+ total = sum(self.current_state.duration_list)
84
+ frame_index = max(0, min(total, frame_index))
85
+ new_counter = 0
86
+ i = 0
87
+ while frame_index < total:
88
+ if self.current_state.counter_to_frame(new_counter) >= frame_index:
89
+ break
90
+ new_counter += self.current_state.duration_list[i]
91
+ i += 1
92
+ self.set_counter(new_counter)
93
+
94
+ def lock(self) -> None:
56
95
  self._locked = True
57
96
 
58
- def unlock_animState(self):
97
+ def unlock(self) -> None:
59
98
  self._locked = False
60
99
 
61
- def set_flipX(self, value):
100
+ def set_flipX(self, value) -> None:
62
101
  self.flipX = value
63
102
 
64
- def remove_animState(self, name:str):
65
- if not name in self.animStates :return
66
- self.animStates.pop(name)
67
- if self.current_animState == name : self.current_animState = list(self.animStates.keys())[0] if self.animStates else ""
103
+ def remove_animState(self, name: str) -> bool:
104
+ if not name in self.animStates:
105
+ return False
106
+ self.animStates.pop(name)
107
+ if self.current_state and self.current_state.name == name:
108
+ self.current_animState = (
109
+ list(self.animStates.keys())[0] if self.animStates else ""
110
+ )
111
+ return True
68
112
 
69
113
  def add_animState(
70
- self, name: str, file: str, size: tuple[int, int], frame_length_list: list[int]
71
- ):
114
+ self,
115
+ name: str,
116
+ surface: pygame.Surface,
117
+ size: tuple[int, int],
118
+ duration_list: list[int],
119
+ convert_alpha: bool = True,
120
+ ) -> bool:
72
121
  if name in self.animStates:
73
- return
74
- self.animStates[name] = AnimState(file, *size, frame_length_list)
75
- if len(self.animStates) == 1 : self.set_animState(name)
122
+ return False
123
+ self.animStates[name] = AnimState(name, surface, *size, duration_list)
124
+ if len(self.animStates) == 1:
125
+ self.set_animState(name)
126
+ return True
76
127
 
77
- def set_animState(self, state:str, reset_counter=True, lock=False):
128
+ def set_animState(self, state: str, reset_counter=True, lock=False) -> bool:
78
129
  if state not in self.animStates or self._locked:
79
130
  return False
80
- self.current_animState = state
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
- ):
131
+
132
+ animState = self.animStates[state]
133
+ self.current_state = animState
134
+
135
+ self.rect = self.current_state.frames[0].get_frect(center=self.rect.center)
136
+
137
+ if reset_counter or self.float_counter > sum(animState.duration_list):
89
138
  self.float_counter = 0
90
139
  if lock:
91
- self.lock_animState()
140
+ self.lock()
92
141
  return True
93
142
 
94
- def get_state(self):
95
- return self.animStates.get(self.current_animState,None)
143
+ def get_animState(self) -> AnimState | None:
144
+ return self.current_state
96
145
 
97
- def get_frame_index(self):
98
- return self.animStates[self.current_animState].get_frame_index(
99
- self.float_counter
100
- )
101
-
102
- def update(self, dt: float):
103
- if not self.animStates : return
104
- self.float_counter += 60 * dt
105
- if self.float_counter > self.get_state().ffl_length:
106
- self.float_counter = 0
146
+ def update(self, dt: float) -> None:
147
+ s = self.get_animState()
148
+ if not self.animStates or s is None:
149
+ return
150
+ if not self.paused:
151
+ self.float_counter += 60 * dt
152
+ if self.float_counter > s.duration_list_length:
153
+ self.float_counter = 0
107
154
  self.do_update(dt)
108
155
 
109
- def draw(self, camera: bf.Camera) -> bool:
110
- if not self.visible or not camera.intersects(self.rect) or not self.animStates:
111
- return False
112
- # pygame.draw.rect(camera.surface,"purple",camera.transpose(self.rect).move(2,2))
156
+ def draw(self, camera: bf.Camera) -> int:
157
+ if (
158
+ not self.visible
159
+ or not camera.rect.colliderect(self.rect)
160
+ or not self.current_state
161
+ ):
162
+ return 0
113
163
  camera.surface.blit(
114
- self.get_state().get_frame(self.float_counter, self.flipX),
115
- camera.transpose(self.rect),
164
+ self.current_state.get_frame(self.float_counter, self.flipX),
165
+ camera.world_to_screen(self.rect),
116
166
  )
117
- return True
167
+ return 1
@@ -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[str : dict[str, pygame.mixer.Sound, bool]] = {}
10
- self.musics: dict[str:str] = {}
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
- to_remove = []
21
- for name, data in self.sounds.items():
22
- if not data["persistent"]:
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
- _ = [self.sounds.pop(i) for i in to_remove]
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 has_sound(self, name):
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.utils.get_path(path)
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 play_sound(self, name, volume=1):
49
- self.sounds[name]["sound"].set_volume(volume * self.sound_volume)
50
- self.sounds[name]["sound"].play()
51
-
52
- def stop_sound(self, name):
53
- if name in self.sounds:
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.utils.get_path(path)
58
-
59
- def play_music(self, name, loop=0, fade=500):
60
- if name in self.musics:
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
- else:
65
- print(f"Music '{name}' not found in AudioManager.")
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