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