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
batFramework/time.py CHANGED
@@ -1,75 +1,140 @@
1
- import pygame
2
1
  import batFramework as bf
2
+ from typing import Self
3
+
3
4
 
4
5
  class Timer:
5
- _highest_count = 0
6
- def __init__(self, name=None, duration=1000, loop=False, end_callback=None,reusable:bool=False):
7
- # Initialize timer properties
8
- self.start_time = None
9
- self.stopped = True
10
- self.name = name if name is not None else self._highest_count
11
- Timer._highest_count += 1
12
- self.duration = duration
13
- self.loop = loop
14
- self.elapsed_progress = 0.0
6
+ _count: int = 0
7
+
8
+ def __init__(self, duration: float | int, end_callback, loop: bool = False, register="global") -> None:
9
+ self.name: int = Timer._count
10
+ Timer._count += 1
11
+ self.register = register
12
+ self.duration: int | float = duration
15
13
  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
14
 
41
- def stop(self):
42
- # Stop the timer
43
- self.stopped = True
15
+ self.elapsed_time: float = -1
16
+ self.is_over: bool = False
17
+ self.is_looping: bool = loop
18
+ self.is_paused: bool = False
19
+ self.do_delete: bool = False
20
+
21
+ def __bool__(self)->bool:
22
+ return self.elapsed_time==-1 or self.is_over
23
+
24
+ def __repr__(self) -> str:
25
+ return f"Timer ({self.name}) {self.elapsed_time}/{self.duration} | {'loop ' if self.is_looping else ''} {'(D) ' if self.do_delete else ''}"
26
+
27
+ def stop(self) -> Self:
28
+ self.elapsed_time = -1
29
+ self.is_over = False
30
+ self.is_paused = False
31
+ return self
32
+
33
+ def start(self, force: bool = False) -> Self:
34
+ if self.elapsed_time != -1 and not force:
35
+ return self
36
+ if not bf.TimeManager().add_timer(self,self.register):
37
+ return self
38
+ self.elapsed_time = 0
39
+ self.is_paused = False
40
+ self.is_over = False
41
+ return self
42
+
43
+ def pause(self) -> Self:
44
+ self.is_paused = True
45
+ return self
46
+
47
+ def resume(self) -> Self:
48
+ self.is_paused = False
49
+ return self
50
+
51
+ def delete(self) -> Self:
52
+ self.do_delete = True
53
+ return self
54
+
55
+ def has_started(self) -> bool:
56
+ return self.elapsed_time != -1
57
+
58
+ def get_progression(self) -> float:
59
+ if self.elapsed_time < 0:
60
+ return 0
61
+ if self.elapsed_time >= self.duration:
62
+ return 1
63
+ return self.elapsed_time / self.duration
64
+
65
+ def update(self, dt) -> None:
66
+ if self.elapsed_time < 0 or self.is_paused or self.is_over:
67
+ return
68
+ self.elapsed_time += dt
69
+ # print("update :",self.elapsed_time,self.duration)
70
+ if self.get_progression() == 1:
71
+ self.end()
44
72
 
45
73
  def end(self):
46
- self.elapsed_progress = 1
47
- self.stopped = False
48
74
  if self.end_callback:
49
75
  self.end_callback()
76
+ self.elapsed_time = -1
77
+ self.is_over = True
78
+ if self.is_looping:
79
+ self.start()
80
+ return
81
+
82
+ def should_delete(self) -> bool:
83
+ return self.is_over or self.do_delete
84
+
85
+ class SceneTimer(Timer):
86
+ def __init__(self, duration: float | int, end_callback, loop: bool = False, scene_name:str = "global") -> None:
87
+ super().__init__(duration, end_callback, loop, scene_name)
50
88
 
51
- def ended(self):
52
- if self.start_time is None:
53
- return False
54
- return (not self.loop) and (self.elapsed_progress >= 1) and (not self.stopped) and not self.reusable
89
+ class TimeManager(metaclass=bf.Singleton):
90
+ class TimerRegister:
91
+ def __init__(self, active=True):
92
+ self.active = active
93
+ self.timers: dict[int | str, Timer] = {}
55
94
 
95
+ def __iter__(self):
96
+ return iter(self.timers.values())
97
+
98
+ def add_timer(self, timer: Timer):
99
+ self.timers[timer.name] = timer
100
+
101
+ def update(self, dt):
102
+ expired_timers = []
103
+ for timer in list(self.timers.values()):
104
+ if not timer.is_paused:
105
+ timer.update(dt)
106
+ if timer.should_delete():
107
+ expired_timers.append(timer.name)
108
+ for name in expired_timers:
109
+ del self.timers[name]
56
110
 
57
- class Time(metaclass=bf.Singleton):
58
111
  def __init__(self):
59
- # Initialize the Time class with a dictionary of timers
60
- self.timers = {}
112
+ self.registers = {"global": TimeManager.TimerRegister()}
113
+
114
+ def add_register(self, name, active=True):
115
+ if name not in self.registers:
116
+ self.registers[name] = TimeManager.TimerRegister(active)
117
+
118
+ def add_timer(self, timer, register="global") -> bool:
119
+ if register in self.registers:
120
+ self.registers[register].add_timer(timer)
121
+ return True
122
+ print(f"Register '{register}' does not exist.")
123
+ return False
61
124
 
62
- def add_timer(self, timer):
63
- # Add a timer to the dictionary
64
- self.timers[timer.name] = timer
125
+ def get_active_registers(self) -> list[TimerRegister]:
126
+ return [t for t in self.registers.values() if t.active]
65
127
 
66
- def update(self):
67
- # Update all timers and remove completed ones
68
- for timer in list(self.timers.values()):
69
- timer.update()
128
+ def update(self, dt):
129
+ for register_name, register in self.registers.items():
130
+ if register.active:
131
+ register.update(dt)
70
132
 
71
- to_remove = [name for name, timer in self.timers.items() if timer.ended()]
133
+ def activate_register(self, name, active=True):
134
+ if name in self.registers:
135
+ self.registers[name].active = active
136
+ else:
137
+ print(f"Register '{name}' does not exist.")
72
138
 
73
- for name in to_remove:
74
- # print(self.timers.pop(name).name,"removed !")
75
- self.timers.pop(name)
139
+ def deactivate_register(self, name):
140
+ self.activate_register(name, active=False)
@@ -1,157 +1,228 @@
1
- import pygame
2
1
  import batFramework as bf
2
+ from typing import Self
3
+ import pygame
4
+
5
+ """
6
+ Both surfaces to transition need to be the same size
3
7
 
8
+ """
4
9
 
5
- class BaseTransition:
10
+
11
+ class Transition:
12
+ def __init__(
13
+ self, duration: float, easing_function: bf.easing = bf.easing.LINEAR
14
+ ) -> None:
15
+ """
16
+ duration : time in seconds
17
+ easing function : controls the progression rate
18
+ """
19
+ self.duration: float = duration
20
+ self.controller = bf.EasingController(
21
+ easing_function,
22
+ duration,
23
+ update_callback=self.update,
24
+ end_callback=self.end,
25
+ )
26
+ self.start_callback = None
27
+ self.update_callback = None
28
+ self.end_callback = None
29
+ self.source: pygame.Surface = None
30
+ self.dest: pygame.Surface = None
31
+
32
+ def __repr__(self) -> str:
33
+ return f"Transition {self.__class__},{self.duration}"
34
+
35
+ def set_start_callback(self, func) -> Self:
36
+ self.start_callback = func
37
+ return self
38
+
39
+ def set_update_callback(self, func) -> Self:
40
+ self.update_callback = func
41
+ return self
42
+
43
+ def set_end_callback(self, func) -> Self:
44
+ self.end_callback = func
45
+ return self
46
+
47
+ def set_source(self, surface: pygame.Surface) -> None:
48
+ self.source = surface
49
+
50
+ def set_dest(self, surface: pygame.Surface) -> None:
51
+ self.dest = surface
52
+
53
+ def start(self):
54
+ if self.controller.has_started():
55
+ return
56
+ if self.duration:
57
+ self.controller.start()
58
+ if self.start_callback:
59
+ self.start_callback()
60
+ return
61
+
62
+ self.controller.start()
63
+ if self.start_callback:
64
+ self.start_callback()
65
+ self.controller.end()
66
+ self.update(1)
67
+ self.end()
68
+
69
+ def update(self, progression: float) -> None:
70
+ if self.update_callback:
71
+ self.update_callback(progression)
72
+
73
+ def end(self):
74
+ self.controller.stop()
75
+ if self.end_callback:
76
+ self.end_callback()
77
+
78
+ def draw(self, surface: pygame.Surface) -> None:
79
+ pass
80
+
81
+ def skip(self, no_callback: bool = False):
82
+ self.controller.stop()
83
+ if self.end_callback and (no_callback == False):
84
+ self.end_callback()
85
+
86
+
87
+ class FadeColor(Transition):
6
88
  def __init__(
7
89
  self,
8
- source_surf: pygame.Surface,
9
- dest_surf: pygame.Surface,
10
- duration=100,
11
- **kwargs,
90
+ color: tuple,
91
+ middle_duration: float,
92
+ first_duration: float = None,
93
+ second_duration: float = None,
94
+ easing_function: bf.easing = bf.easing.LINEAR,
12
95
  ) -> None:
13
- self.source = source_surf
14
- self.dest = dest_surf
15
- self.ended = False
16
- self.source_scene_name = ""
17
- self.dest_scene_name = ""
18
- self.duration = duration
96
+ super().__init__(0, easing_function)
97
+ if first_duration is None:
98
+ first_duration = middle_duration
99
+ if second_duration is None:
100
+ second_duration = middle_duration
101
+
102
+ self.first = Fade(first_duration)
103
+ self.second = Fade(second_duration)
104
+ self.color = color
105
+ self.middle_duration = middle_duration
19
106
  self.index = 0
20
107
 
21
- def set_scene_index(self,index):
22
- self.index = index
108
+ self.timer = bf.Timer(middle_duration, self.transition_to_second)
109
+ self.first.set_end_callback(self.transition_to_middle)
110
+ self.second.set_end_callback(self.transition_to_end)
23
111
 
24
- def set_source_name(self, name):
25
- self.source_scene_name = name
112
+ def transition_to_middle(self):
113
+ self.next_step(self.timer.start)
26
114
 
27
- def set_dest_name(self, name):
28
- self.dest_scene_name = name
115
+ def transition_to_second(self):
116
+ self.next_step(self.second.start)
29
117
 
30
- def update(self, dt):
31
- pass
118
+ def transition_to_end(self):
119
+ self.next_step(self.end)
32
120
 
33
- def draw(self, surface):
34
- pass
121
+ def next_step(self, callback=None) -> None:
122
+ self.index += 1
123
+ if callback:
124
+ callback()
35
125
 
36
- def has_ended(self):
37
- return False
126
+ def set_source(self, surface) -> None:
127
+ super().set_source(surface)
128
+ self.first.set_source(surface)
38
129
 
39
- def set_ended(self, val):
40
- self.ended = val
130
+ def set_dest(self, surface) -> None:
131
+ super().set_dest(surface)
132
+ self.second.set_dest(surface)
41
133
 
134
+ def start(self):
135
+ if self.start_callback:
136
+ self.start_callback()
42
137
 
43
- class FadeColorTransition(BaseTransition):
44
- def __init__(
45
- self,
46
- source_surf,
47
- dest_surf,
48
- duration=600,
49
- color_duration=200,
50
- color=bf.color.CLOUD_WHITE,
51
- **kwargs,
52
- ) -> None:
53
- super().__init__(source_surf, dest_surf, duration)
54
- self.target_time = duration * 2 + color_duration
55
- self.color_surf = pygame.Surface((source_surf.get_rect().size)).convert_alpha()
56
- self.color_surf.fill(color)
57
- self.ease_out = bf.EasingAnimation(
58
- easing_function=bf.Easing.EASE_IN,
59
- duration=(duration-color_duration)//2,
60
- update_callback = lambda x: self.color_surf.set_alpha(int(255 - (255 * x))),
61
- end_callback=lambda: self.set_ended(True))
62
-
63
- self.color_timer = bf.Timer(
64
- duration=color_duration,
65
- end_callback=lambda: self.set_state("out"))
66
- self.ease_in = bf.EasingAnimation(
67
- easing_function=bf.Easing.EASE_IN,
68
- duration=(duration-color_duration)//2,
69
- update_callback=lambda x: self.color_surf.set_alpha(int(255 * x)),
70
- # update_callback=lambda x: print(x),
71
- end_callback=lambda: self.set_state("color"))
72
- self.state = None
73
-
74
- self.state = "in"
75
- self.ease_in.start()
76
-
77
- def set_state(self, state: str):
78
- self.state = state
79
- if state == "in":
80
- self.ease_in.start()
81
- elif state == "color":
82
- self.color_timer.start()
83
- elif state == "out":
84
- self.ease_out.start()
85
-
86
- def has_ended(self):
87
- return self.ended
88
-
89
- def set_ended(self, val):
90
- super().set_ended(val)
138
+ self.color_surf = pygame.Surface(self.source.get_size())
139
+ self.color_surf.fill(self.color)
140
+
141
+ self.first.set_dest(self.color_surf)
142
+ self.second.set_source(self.color_surf)
143
+ self.first.start()
91
144
 
92
145
  def draw(self, surface):
93
- if self.state != "color":
94
- surface.blit(self.source if self.state == "in" else self.dest, (0, 0))
95
- surface.blit(self.color_surf, (0, 0))
146
+ if self.index == 0:
147
+ self.first.draw(surface)
148
+ elif self.index == 1:
149
+ surface.blit(self.color_surf, (0, 0))
150
+ else:
151
+ self.second.draw(surface)
96
152
 
153
+ def skip(self, no_callback: bool = False):
154
+ if not no_callback and self.end_callback:
155
+ self.end_callback()
97
156
 
98
- class FadeTransition(BaseTransition):
99
- def __init__(self, source_surf, dest_surf, duration=500) -> None:
100
- super().__init__(source_surf, dest_surf)
101
- self.anim = bf.EasingAnimation(None,bf.Easing.EASE_IN_OUT,duration,self.update_surface,lambda : self.set_ended(True))
102
- self.anim.start()
157
+ self.first.controller.stop()
158
+ self.timer.stop()
159
+ self.second.controller.stop()
103
160
 
104
- def update_surface(self,progress):
105
- self.source.set_alpha(int(255 - (255 * progress)))
106
- self.dest.set_alpha(int(255 * progress))
107
161
 
108
- def has_ended(self):
109
- return self.ended
162
+
163
+ class Fade(Transition):
164
+ def end(self):
165
+ self.dest.set_alpha(255)
166
+ return super().end()
110
167
 
111
168
  def draw(self, surface):
169
+ dest_alpha = 255 * self.controller.get_value()
170
+ self.dest.set_alpha(dest_alpha)
112
171
  surface.blit(self.source, (0, 0))
113
172
  surface.blit(self.dest, (0, 0))
114
173
 
115
174
 
116
- class SlideTransition(BaseTransition):
117
- def __init__(
118
- self,
119
- source_surf,
120
- dest_surf,
121
- duration=1000,
122
- source_alignment: bf.Alignment = bf.Alignment.BOTTOM,
123
- easing: bf.Easing = bf.Easing.EASE_IN_OUT,
124
- **kwargs,
125
- ) -> None:
126
- super().__init__(source_surf, dest_surf, duration)
127
- self.offset = pygame.Vector2(0, 0)
128
- if source_alignment in [bf.Alignment.TOP, bf.Alignment.BOTTOM]:
129
- self.offset.y = bf.const.RESOLUTION[1]
130
- if source_alignment == bf.Alignment.TOP:
131
- self.offset.y *= -1
132
- elif source_alignment in [bf.Alignment.LEFT, bf.Alignment.RIGHT]:
133
- self.offset.x = bf.const.RESOLUTION[0]
134
- if source_alignment == bf.Alignment.LEFT:
135
- self.offset.x *= -1
136
- else:
137
- self.offset.x = -bf.const.RESOLUTION[0]
138
- print(
139
- f"Unsupported Alignment : {source_alignment.value}, set to default : {bf.Alignment.LEFT.value} "
140
- )
141
- self.anim = bf.EasingAnimation(
142
- easing_function=easing,
143
- duration=duration,
144
- update_callback =lambda x: self.update_offset(self.offset.lerp((0, 0), x)),
145
- end_callback =lambda: self.set_ended(True),
175
+ class GlideRight(Transition):
176
+ def draw(self, surface):
177
+ width = surface.get_width()
178
+ source_x = -self.controller.get_value() * width
179
+ surface.blit(self.source, (source_x, 0))
180
+ surface.blit(self.dest, (width + source_x, 0))
181
+
182
+
183
+ class GlideLeft(Transition):
184
+ def draw(self, surface):
185
+ width = surface.get_width()
186
+ source_x = self.controller.get_value() * width
187
+ surface.blit(self.source, (source_x, 0))
188
+ surface.blit(self.dest, (source_x - width, 0))
189
+
190
+
191
+ class CircleOut(Transition):
192
+ def start(self):
193
+ super().start()
194
+ self.circle_surf = self.source.copy()
195
+ self.circle_surf.set_colorkey((0, 0, 0))
196
+ self.circle_surf.fill((0, 0, 0))
197
+ self.surface_width = self.circle_surf.get_width()
198
+
199
+ def draw(self, surface):
200
+ v = self.controller.get_value()
201
+
202
+ radius = self.surface_width * v
203
+ pygame.draw.circle(
204
+ self.circle_surf, "white", self.circle_surf.get_rect().center, radius
146
205
  )
147
- self.anim.start()
206
+ mask = pygame.mask.from_surface(self.circle_surf)
207
+ mask.to_surface(surface=surface, setsurface=self.dest, unsetsurface=self.source)
148
208
 
149
- def update_offset(self, vec):
150
- self.offset.update(vec)
151
209
 
152
- def has_ended(self):
153
- return self.ended
210
+ class CircleIn(Transition):
211
+ def start(self):
212
+ super().start()
213
+ self.circle_surf = self.source.copy()
214
+ self.circle_surf.set_colorkey((0, 0, 0))
215
+ self.circle_surf.fill((0, 0, 0))
216
+ self.surface_width = self.circle_surf.get_width()
154
217
 
155
218
  def draw(self, surface):
156
- surface.blit(self.source, (0, 0))
157
- surface.blit(self.dest, self.offset)
219
+ v = self.controller.get_value()
220
+ radius = self.surface_width - (self.surface_width * v)
221
+ self.circle_surf.fill((0, 0, 0))
222
+ pygame.draw.circle(
223
+ self.circle_surf, "white", self.circle_surf.get_rect().center, radius
224
+ )
225
+ mask = pygame.mask.from_surface(self.circle_surf)
226
+ mask.to_surface(surface=surface, setsurface=self.source, unsetsurface=self.dest)
227
+
228
+