batframework 1.0.8a8__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.
Files changed (70) hide show
  1. batFramework/__init__.py +68 -51
  2. batFramework/action.py +126 -99
  3. batFramework/actionContainer.py +53 -9
  4. batFramework/animatedSprite.py +141 -82
  5. batFramework/audioManager.py +69 -26
  6. batFramework/camera.py +259 -69
  7. batFramework/character.py +27 -0
  8. batFramework/constants.py +16 -54
  9. batFramework/cutscene.py +39 -29
  10. batFramework/cutsceneBlocks.py +36 -43
  11. batFramework/dynamicEntity.py +18 -9
  12. batFramework/easingController.py +58 -0
  13. batFramework/entity.py +48 -97
  14. batFramework/enums.py +113 -0
  15. batFramework/fontManager.py +65 -0
  16. batFramework/gui/__init__.py +10 -2
  17. batFramework/gui/button.py +9 -78
  18. batFramework/gui/clickableWidget.py +220 -0
  19. batFramework/gui/constraints/__init__.py +1 -0
  20. batFramework/gui/constraints/constraints.py +815 -0
  21. batFramework/gui/container.py +174 -32
  22. batFramework/gui/debugger.py +131 -43
  23. batFramework/gui/dialogueBox.py +99 -0
  24. batFramework/gui/draggableWidget.py +40 -0
  25. batFramework/gui/image.py +56 -20
  26. batFramework/gui/indicator.py +38 -21
  27. batFramework/gui/interactiveWidget.py +192 -13
  28. batFramework/gui/label.py +309 -74
  29. batFramework/gui/layout.py +231 -63
  30. batFramework/gui/meter.py +74 -0
  31. batFramework/gui/radioButton.py +84 -0
  32. batFramework/gui/root.py +134 -38
  33. batFramework/gui/shape.py +237 -57
  34. batFramework/gui/slider.py +240 -0
  35. batFramework/gui/style.py +10 -0
  36. batFramework/gui/styleManager.py +48 -0
  37. batFramework/gui/textInput.py +247 -0
  38. batFramework/gui/toggle.py +101 -51
  39. batFramework/gui/widget.py +358 -250
  40. batFramework/manager.py +52 -19
  41. batFramework/object.py +123 -0
  42. batFramework/particle.py +115 -0
  43. batFramework/renderGroup.py +67 -0
  44. batFramework/resourceManager.py +100 -0
  45. batFramework/scene.py +281 -123
  46. batFramework/sceneManager.py +178 -116
  47. batFramework/scrollingSprite.py +114 -0
  48. batFramework/sprite.py +51 -0
  49. batFramework/stateMachine.py +11 -8
  50. batFramework/templates/__init__.py +2 -0
  51. batFramework/templates/character.py +44 -0
  52. batFramework/templates/states.py +166 -0
  53. batFramework/tileset.py +46 -0
  54. batFramework/time.py +145 -58
  55. batFramework/transition.py +195 -124
  56. batFramework/triggerZone.py +1 -1
  57. batFramework/utils.py +112 -147
  58. batframework-1.0.8a10.dist-info/LICENCE +21 -0
  59. batframework-1.0.8a10.dist-info/METADATA +43 -0
  60. batframework-1.0.8a10.dist-info/RECORD +62 -0
  61. batFramework/debugger.py +0 -48
  62. batFramework/easing.py +0 -71
  63. batFramework/gui/constraints.py +0 -204
  64. batFramework/gui/frame.py +0 -19
  65. batFramework/particles.py +0 -77
  66. batFramework/transitionManager.py +0 -0
  67. batframework-1.0.8a8.dist-info/METADATA +0 -53
  68. batframework-1.0.8a8.dist-info/RECORD +0 -42
  69. {batframework-1.0.8a8.dist-info → batframework-1.0.8a10.dist-info}/WHEEL +0 -0
  70. {batframework-1.0.8a8.dist-info → batframework-1.0.8a10.dist-info}/top_level.txt +0 -0
@@ -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 = None,
93
+ second_duration: float | None = 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
+
@@ -4,7 +4,7 @@ import batFramework as bf
4
4
  class TriggerZone(bf.Entity):
5
5
  def __init__(self, size, trigger, callback, active=True) -> None:
6
6
  super().__init__(size, True)
7
- self.set_debug_color(bf.color.RIVER_BLUE)
7
+ self.set_debug_color(bf.color.RED)
8
8
  self.active = active
9
9
  self.callback = callback
10
10
  self.trigger = trigger
batFramework/utils.py CHANGED
@@ -3,9 +3,14 @@ from enum import Enum
3
3
  import os
4
4
  import batFramework as bf
5
5
  import json
6
+ from .enums import *
7
+ import re
8
+ from typing import Callable, TYPE_CHECKING, Any
9
+ from functools import cache
10
+ if TYPE_CHECKING:
11
+ from .object import Object
12
+ from .entity import Entity
6
13
 
7
- MAX_FONT_SIZE = 100
8
- MIN_FONT_SIZE = 8
9
14
 
10
15
  class Singleton(type):
11
16
  _instances = {}
@@ -16,169 +21,129 @@ class Singleton(type):
16
21
  return cls._instances[cls]
17
22
 
18
23
 
19
- class Direction(Enum):
20
- HORIZONTAL = "horizontal"
21
- VERTICAL = "vertical"
22
-
23
-
24
- class Alignment(Enum):
25
- LEFT = "left"
26
- RIGHT = "right"
27
- CENTER = "center"
28
- TOP = "top"
29
- BOTTOM = "bottom"
24
+ class Utils:
30
25
 
26
+ @staticmethod
27
+ def split_surface(
28
+ surface: pygame.Surface, split_size: tuple[int, int], func=None
29
+ ) -> dict[tuple[int, int], pygame.Surface]:
30
+ """
31
+ Splits a surface into subsurfaces and returns a dictionnary of them
32
+ with their tuple coordinates as keys.
33
+ Exemple : '(0,0) : Surface'
34
+ """
35
+ width, height = surface.get_size()
36
+ res = {}
37
+ for iy, y in enumerate(range(0, height, split_size[1])):
38
+ for ix, x in enumerate(range(0, width, split_size[0])):
39
+ sub = surface.subsurface((x, y, split_size[0], split_size[1]))
40
+
41
+ if func is not None:
42
+ sub = func(sub)
43
+
44
+ res[(ix, iy)] = sub
31
45
 
32
- class Layout(Enum):
33
- FILL = "fill"
34
- FIT = "fit"
46
+ return res
35
47
 
48
+ @staticmethod
49
+ def filter_text(text_mode: textMode):
50
+ if text_mode == textMode.ALPHABETICAL:
51
+ pattern = re.compile(r"[^a-zA-Z]")
52
+ elif text_mode == textMode.NUMERICAL:
53
+ pattern = re.compile(r"[^0-9]")
54
+ elif text_mode == textMode.ALPHANUMERICAL:
55
+ pattern = re.compile(r"[^a-zA-Z0-9]")
56
+ else:
57
+ raise ValueError("Unsupported text mode")
36
58
 
37
- class Utils:
38
- pygame.font.init()
39
- FONTS = {}
40
- tilesets = {}
59
+ def filter_function(s: str) -> str:
60
+ return pattern.sub("", s)
41
61
 
42
- @staticmethod
43
- def get_path(path: str):
44
- return os.path.join(bf.const.RESOURCE_PATH, path)
62
+ return filter_function
45
63
 
46
- @staticmethod
47
- def load_json_from_file(path: str) -> dict:
48
- try:
49
- with open(Utils.get_path(path), "r") as file:
50
- data = json.load(file)
51
- return data
52
- except FileNotFoundError:
53
- print(f"File '{path}' not found")
54
- return None
55
64
 
56
65
  @staticmethod
57
- def save_json_to_file(path: str, data) -> bool:
58
- try:
59
- with open(Utils.get_path(path), "w") as file:
60
- json.dump(data, file, indent=2)
61
- return True
62
- except FileNotFoundError:
63
- return False
64
-
65
- @staticmethod
66
- def init_font(raw_path:str):
67
- try :
68
- if raw_path is not None:
69
- Utils.load_font(raw_path if raw_path else None,None)
70
- Utils.load_font(raw_path)
71
- except FileNotFoundError:
72
- Utils.load_sysfont(raw_path)
73
- Utils.load_sysfont(raw_path,None)
66
+ @cache
67
+ def create_spotlight(inside_color, outside_color, radius, radius_stop=None, dest_surf=None,size=None):
68
+ """
69
+ Draws a circle spotlight centered on a surface
70
+ inner color on the center
71
+ gradient towards outside color from radius to radius stop
72
+ surface background is made transparent
73
+ if des_surf is None:
74
+ if size is None : size is radius_stop*radius_stop
75
+ returns the newly created surface of size 'size' with the spotlight drawn
76
+
77
+ """
78
+ if radius_stop is None:
79
+ radius_stop = radius
80
+ diameter = radius_stop * 2
81
+
82
+ if dest_surf is None:
83
+ if size is None:
84
+ size = (diameter,diameter)
85
+ dest_surf = pygame.Surface(size, pygame.SRCALPHA)
86
+
87
+ dest_surf.fill((0,0,0,0))
88
+
89
+
90
+ center = dest_surf.get_rect().center
91
+
92
+ if radius_stop != radius:
93
+ for r in range(radius_stop, radius - 1, -1):
94
+ color = [
95
+ inside_color[i] + (outside_color[i] - inside_color[i]) * (r - radius) / (radius_stop - radius)
96
+ for i in range(3)
97
+ ] + [255] # Preserve the alpha channel as fully opaque
98
+ pygame.draw.circle(dest_surf, color, center, r)
99
+ else:
100
+ pygame.draw.circle(dest_surf, inside_color, center, radius)
74
101
 
102
+ return dest_surf
75
103
 
76
104
  @staticmethod
77
- def load_font(path:str,name:str=''):
78
- if path is not None: path = Utils.get_path(path) # convert path if given
79
- filename = os.path.basename(path).split('.')[0] if path is not None else None # get filename if path is given, else None
80
- if name != '' : filename = name # if name is not given, name is the filename
81
- Utils.FONTS[filename] = {}
82
- # fill the dict
83
- for size in range(MIN_FONT_SIZE, MAX_FONT_SIZE, 2):
84
- Utils.FONTS[filename][size] = pygame.font.Font(path,size=size)
85
-
86
- def load_sysfont(font_name:str,key:str=''):
87
- if key == '' : key = font_name
88
- if pygame.font.match_font(font_name) is None:
89
- raise FileNotFoundError(f"Requested font '{font_namey}' was not found")
90
- Utils.FONTS[font_name] = {}
91
-
92
- for size in range(MIN_FONT_SIZE, MAX_FONT_SIZE, 2):
93
- Utils.FONTS[key][size] = pygame.font.SysFont(font_name,size=size)
94
-
105
+ def draw_spotlight(dest_surf:pygame.Surface,inside_color,outside_color,radius,radius_stop=None,center=None):
106
+ if radius_stop is None:
107
+ radius_stop = radius
108
+ center = dest_surf.get_rect().center if center is None else center
109
+ if radius_stop != radius:
110
+ for r in range(radius_stop, radius - 1, -1):
111
+ color = [
112
+ inside_color[i] + (outside_color[i] - inside_color[i]) * (r - radius) / (radius_stop - radius)
113
+ for i in range(3)
114
+ ] + [255]
115
+ pygame.draw.circle(dest_surf, color, center, r)
116
+ else:
117
+ pygame.draw.circle(dest_surf, inside_color, center, radius)
95
118
 
96
119
  @staticmethod
97
- def get_font(name:str|None=None,text_size:int=12) -> pygame.Font:
98
- if not name in Utils.FONTS: return None
99
- if not text_size in Utils.FONTS[name]: return None
100
- return Utils.FONTS[name][text_size]
101
-
102
- class Tileset:
103
- _flip_cache = {} # {"tileset":tileset,"index","flipX","flipY"}
104
-
105
- def __init__(self, surface: pygame.Surface, tilesize) -> None:
106
- self.tile_dict = {}
107
- self.surface = surface
108
- self.tile_size = tilesize
109
- self.split_surface(surface)
110
-
111
- def split_surface(self, surface: pygame.Surface):
112
- width, height = surface.get_size()
113
- num_tiles_x = width // self.tile_size
114
- num_tiles_y = height // self.tile_size
115
- # Iterate over the tiles vertically and horizontally
116
- for y in range(num_tiles_y):
117
- for x in range(num_tiles_x):
118
- # Calculate the coordinates of the current tile in the tileset
119
- tile_x = x * self.tile_size
120
- tile_y = y * self.tile_size
121
- # Create a subsurface for the current tile
122
- tile_surface = surface.subsurface(
123
- pygame.Rect(tile_x, tile_y, self.tile_size, self.tile_size)
124
- )
125
- # Calculate the unique key for the tile (e.g., based on its coordinates)
126
- tile_key = (x, y)
127
- # Store the subsurface in the dictionary with the corresponding key
128
- self.tile_dict[tile_key] = tile_surface
129
- # print(self.tile_dict)
130
-
131
- def get_tile(self, x, y, flipX=False, flipY=False) -> pygame.Surface | None:
132
- if (x, y) not in self.tile_dict:
133
- return None
134
- if flipX or flipY:
135
- key = f"{x}{y}:{flipX}{flipY}"
136
- if not key in self._flip_cache:
137
- self._flip_cache[key] = pygame.transform.flip(
138
- self.tile_dict[(x, y)], flipX, flipY
139
- )
140
- return self._flip_cache[key]
141
- return self.tile_dict[(x, y)]
120
+ def animate_move(entity:"Object", start_pos : tuple[float,float], end_pos:tuple[float,float])->Callable[[float],None]:
121
+ def func(x):
122
+ entity.set_center(start_pos[0]+(end_pos[0]-start_pos[0])*x,start_pos[1]+(end_pos[1]-start_pos[1])*x)
123
+ return func
124
+
125
+ def animate_move_to(entity: "Object", end_pos: tuple[float, float]) -> Callable[[float], None]:
126
+ # Start position will be captured once when the animation starts
127
+ start_pos = [None]
142
128
 
143
- @staticmethod
144
- def img_slice(file, cell_width, cell_height, flipX=False) -> list[pygame.Surface]:
145
- src = pygame.image.load(
146
- os.path.join(bf.const.RESOURCE_PATH, file)
147
- ).convert_alpha()
148
- width, height = src.get_size()
149
- res = []
150
- for y in range(0, height, cell_height):
151
- for x in range(0, width, cell_width):
152
- sub = src.subsurface((x, y, cell_width, cell_height))
153
- if flipX:
154
- sub = pygame.transform.flip(sub, True, False)
155
-
156
- res.append(sub)
157
- return res
129
+ def update_position(progression: float):
130
+ if start_pos[0] is None:
131
+ start_pos[0] = entity.rect.center # Capture the start position at the start of the animation
158
132
 
159
- def load_tileset(path: str, name: str, tilesize):
160
- if name in Utils.tilesets:
161
- return Utils.tilesets[name]
162
- else:
163
- img = pygame.image.load(
164
- os.path.join(bf.const.RESOURCE_PATH, path)
165
- ).convert_alpha()
166
- tileset = Utils.Tileset(img, tilesize)
167
- Utils.tilesets[name] = tileset
168
- return tileset
133
+ # Calculate new position based on progression
134
+ new_x = start_pos[0][0] + (end_pos[0] - start_pos[0][0]) * progression
135
+ new_y = start_pos[0][1] + (end_pos[1] - start_pos[0][1]) * progression
169
136
 
170
- @staticmethod
171
- def get_tileset(name: str) -> Tileset:
172
- if name not in Utils.tilesets:
173
- return None
174
- return Utils.tilesets[name]
137
+ # Set the entity's new position
138
+ entity.set_center(new_x, new_y)
175
139
 
140
+ return update_position
176
141
 
142
+ @staticmethod
143
+ def animate_alpha(entity:"Entity", start : int, end:int)->Callable[[float],None]:
144
+ def func(x):
145
+ entity.set_alpha(int(pygame.math.clamp(start+(end-start)*x,0,255)))
146
+ return func
177
147
 
178
148
 
179
149
 
180
- def move_points(delta, *points):
181
- res = []
182
- for point in points:
183
- res.append((point[0] + delta[0], point[1] + delta[1]))
184
- return res
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) [2023] [TURAN BATURAY]
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.