batframework 1.0.8a2__py3-none-any.whl → 1.0.8a4__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 +117 -73
  5. batFramework/audioManager.py +69 -26
  6. batFramework/camera.py +259 -69
  7. batFramework/constants.py +16 -54
  8. batFramework/cutscene.py +39 -29
  9. batFramework/cutsceneBlocks.py +36 -43
  10. batFramework/dynamicEntity.py +17 -9
  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 +221 -0
  18. batFramework/gui/constraints/__init__.py +1 -0
  19. batFramework/gui/constraints/constraints.py +730 -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 +292 -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 +134 -38
  32. batFramework/gui/shape.py +259 -57
  33. batFramework/gui/slider.py +230 -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 +103 -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 +100 -0
  44. batFramework/scene.py +281 -123
  45. batFramework/sceneManager.py +141 -108
  46. batFramework/scrollingSprite.py +114 -0
  47. batFramework/sprite.py +51 -0
  48. batFramework/stateMachine.py +2 -2
  49. batFramework/tileset.py +46 -0
  50. batFramework/time.py +123 -58
  51. batFramework/transition.py +195 -124
  52. batFramework/utils.py +87 -151
  53. batframework-1.0.8a4.dist-info/LICENCE +21 -0
  54. batframework-1.0.8a4.dist-info/METADATA +55 -0
  55. batframework-1.0.8a4.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.8a4.dist-info}/WHEEL +0 -0
  65. {batframework-1.0.8a2.dist-info → batframework-1.0.8a4.dist-info}/top_level.txt +0 -0
@@ -1,9 +1,10 @@
1
1
  import batFramework as bf
2
2
  import pygame
3
+ from typing import List, Dict, Tuple, Union, Optional
4
+ from enum import Enum
3
5
 
4
6
 
5
-
6
- def search_index(target, lst):
7
+ def search_index(target: int, lst: List[int]) -> int:
7
8
  cumulative_sum = 0
8
9
  for index, value in enumerate(lst):
9
10
  cumulative_sum += value
@@ -13,105 +14,148 @@ def search_index(target, lst):
13
14
 
14
15
 
15
16
  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
17
+ def __init__(
18
+ self,
19
+ name: str,
20
+ surface: pygame.Surface,
21
+ size: Tuple[int,int],
22
+ duration_list: Union[List[int], int],
23
+ ) -> None:
24
+ self.frames: List[pygame.Surface] = list(
25
+ bf.utils.split_surface(
26
+ surface, size
27
+ ).values()
28
+ )
29
+ self.frames_flipX: List[pygame.Surface] = list(
30
+ bf.utils.split_surface(surface, size,).values()
20
31
  )
21
32
 
22
- self.frame_length_list = []
23
- self.ffl_length = 0
24
- self.set_frame_length_list(frame_length_list)
33
+ self.name = name
34
+ self.set_duration_list(duration_list)
25
35
 
26
- def get_frame_index(self, counter:float|int):
27
- return search_index(int(counter % self.ffl_length), self.frame_length_list)
36
+ def __repr__(self):
37
+ return f"AnimState({self.name})"
38
+
39
+ def counter_to_frame(self, counter: Union[float, int]) -> int:
40
+ return search_index(
41
+ int(counter % self.duration_list_length), self.duration_list
42
+ )
28
43
 
29
- def get_frame(self, counter, flip):
30
- i = self.get_frame_index(counter)
44
+ def get_frame(self, counter: Union[float, int], flip: bool) -> pygame.Surface:
45
+ i = self.counter_to_frame(counter)
31
46
  return self.frames_flipX[i] if flip else self.frames[i]
32
47
 
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
-
41
-
42
- class AnimatedSprite(bf.DynamicEntity):
43
- def __init__(self, size=None) -> None:
48
+ def set_duration_list(self, duration_list: Union[List[int], int]):
49
+ if isinstance(duration_list, int):
50
+ duration_list = [duration_list] * len(self.frames)
51
+ if len(duration_list) != len(self.frames):
52
+ raise ValueError("duration_list should have values for all frames")
53
+ self.duration_list = duration_list
54
+ self.duration_list_length = sum(self.duration_list)
55
+
56
+
57
+ class AnimatedSprite(bf.Entity):
58
+ def __init__(self, size: Optional[Tuple[int, int]] = None) -> None:
44
59
  super().__init__(size, no_surface=True)
45
- self.float_counter = 0
46
- self.animStates: dict[str, AnimState] = {}
47
- self.current_animState :str = ""
48
- self.flipX = False
49
- self._locked = False
60
+ self.float_counter: float = 0
61
+ self.animStates: Dict[str, AnimState] = {}
62
+ self.current_state: Optional[AnimState] = None
63
+ self.flipX: bool = False
64
+ self._locked: bool = False
65
+ self._paused: bool = False
66
+
67
+ @property
68
+ def paused(self) -> bool:
69
+ return self._paused
50
70
 
51
- def set_counter(self,value:float):
71
+ @paused.setter
72
+ def paused(self, value: bool) -> None:
73
+ self._paused = value
74
+
75
+ def toggle_pause(self) -> None:
76
+ self.paused = not self.paused
77
+
78
+ def set_counter(self, value: float) -> None:
52
79
  self.float_counter = value
53
-
54
80
 
55
- def lock_animState(self):
81
+ def set_frame(self, frame_index: int) -> None:
82
+ if not self.current_state:
83
+ return
84
+ self.set_counter(sum(self.current_state.duration_list[:frame_index]))
85
+
86
+ def lock(self) -> None:
56
87
  self._locked = True
57
88
 
58
- def unlock_animState(self):
89
+ def unlock(self) -> None:
59
90
  self._locked = False
60
91
 
61
- def set_flipX(self, value):
92
+ def set_flipX(self, value: bool) -> None:
62
93
  self.flipX = value
63
94
 
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 ""
95
+ def remove_animState(self, name: str) -> bool:
96
+ if name not in self.animStates:
97
+ return False
98
+ self.animStates.pop(name)
99
+ if self.current_state and self.current_state.name == name:
100
+ self.current_state = (
101
+ list(self.animStates.values())[0] if self.animStates else None
102
+ )
103
+ return True
68
104
 
69
105
  def add_animState(
70
- self, name: str, file: str, size: tuple[int, int], frame_length_list: list[int]
71
- ):
106
+ self,
107
+ name: str,
108
+ surface: pygame.Surface,
109
+ size: Tuple[int, int],
110
+ duration_list: Union[List[int], int],
111
+ ) -> bool:
72
112
  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)
113
+ return False
114
+ self.animStates[name] = AnimState(
115
+ name, surface, size, duration_list
116
+ )
117
+ if len(self.animStates) == 1:
118
+ self.set_animState(name)
119
+ return True
76
120
 
77
- def set_animState(self, state:str, reset_counter=True, lock=False):
121
+ def set_animState(
122
+ self, state: str, reset_counter: bool = True, lock: bool = False
123
+ ) -> bool:
78
124
  if state not in self.animStates or self._locked:
79
125
  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
- ):
126
+
127
+ animState = self.animStates[state]
128
+ self.current_state = animState
129
+
130
+ self.rect = self.current_state.frames[0].get_rect(center=self.rect.center)
131
+
132
+ if reset_counter or self.float_counter > animState.duration_list_length:
89
133
  self.float_counter = 0
90
134
  if lock:
91
- self.lock_animState()
135
+ self.lock()
92
136
  return True
93
137
 
94
- def get_state(self):
95
- return self.animStates.get(self.current_animState,None)
138
+ def get_animState(self) -> Optional[AnimState]:
139
+ return self.current_state
96
140
 
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
141
+ def update(self, dt: float) -> None:
142
+ s = self.get_animState()
143
+ if self.animStates and s is not None:
144
+ if not self.paused:
145
+ self.float_counter += 60 * dt
146
+ if self.float_counter > s.duration_list_length:
147
+ self.float_counter = 0
107
148
  self.do_update(dt)
108
149
 
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))
150
+ def draw(self, camera: bf.Camera) -> None:
151
+ if (
152
+ not self.visible
153
+ or not camera.rect.colliderect(self.rect)
154
+ or not self.current_state
155
+ ):
156
+ return
113
157
  camera.surface.blit(
114
- self.get_state().get_frame(self.float_counter, self.flipX),
115
- camera.transpose(self.rect),
158
+ self.current_state.get_frame(self.float_counter, self.flipX),
159
+ camera.world_to_screen(self.rect),
116
160
  )
117
- return True
161
+ return
@@ -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