batframework 1.0.8a7__py3-none-any.whl → 1.0.8a9__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.
- batFramework/__init__.py +51 -68
- batFramework/action.py +99 -126
- batFramework/actionContainer.py +9 -53
- batFramework/animatedSprite.py +82 -141
- batFramework/audioManager.py +26 -69
- batFramework/camera.py +69 -259
- batFramework/constants.py +54 -16
- batFramework/cutscene.py +29 -39
- batFramework/cutsceneBlocks.py +43 -36
- batFramework/debugger.py +48 -0
- batFramework/dynamicEntity.py +9 -18
- batFramework/easing.py +71 -0
- batFramework/entity.py +97 -48
- batFramework/gui/__init__.py +2 -10
- batFramework/gui/button.py +78 -9
- batFramework/gui/constraints.py +204 -0
- batFramework/gui/container.py +32 -174
- batFramework/gui/debugger.py +43 -131
- batFramework/gui/frame.py +19 -0
- batFramework/gui/image.py +20 -56
- batFramework/gui/indicator.py +21 -38
- batFramework/gui/interactiveWidget.py +13 -192
- batFramework/gui/label.py +74 -309
- batFramework/gui/layout.py +63 -231
- batFramework/gui/root.py +38 -134
- batFramework/gui/shape.py +57 -237
- batFramework/gui/toggle.py +51 -101
- batFramework/gui/widget.py +250 -358
- batFramework/manager.py +19 -52
- batFramework/particles.py +77 -0
- batFramework/scene.py +123 -281
- batFramework/sceneManager.py +116 -178
- batFramework/stateMachine.py +8 -11
- batFramework/time.py +58 -145
- batFramework/transition.py +124 -195
- batFramework/transitionManager.py +0 -0
- batFramework/triggerZone.py +1 -1
- batFramework/utils.py +147 -112
- batframework-1.0.8a9.dist-info/METADATA +53 -0
- batframework-1.0.8a9.dist-info/RECORD +42 -0
- {batframework-1.0.8a7.dist-info → batframework-1.0.8a9.dist-info}/WHEEL +1 -1
- batFramework/character.py +0 -27
- batFramework/easingController.py +0 -58
- batFramework/enums.py +0 -113
- batFramework/fontManager.py +0 -65
- batFramework/gui/clickableWidget.py +0 -220
- batFramework/gui/constraints/__init__.py +0 -1
- batFramework/gui/constraints/constraints.py +0 -815
- batFramework/gui/dialogueBox.py +0 -99
- batFramework/gui/draggableWidget.py +0 -40
- batFramework/gui/meter.py +0 -74
- batFramework/gui/radioButton.py +0 -84
- batFramework/gui/slider.py +0 -240
- batFramework/gui/style.py +0 -10
- batFramework/gui/styleManager.py +0 -48
- batFramework/gui/textInput.py +0 -247
- batFramework/object.py +0 -123
- batFramework/particle.py +0 -115
- batFramework/renderGroup.py +0 -67
- batFramework/resourceManager.py +0 -100
- batFramework/scrollingSprite.py +0 -114
- batFramework/sprite.py +0 -51
- batFramework/templates/__init__.py +0 -2
- batFramework/templates/character.py +0 -44
- batFramework/templates/states.py +0 -166
- batFramework/tileset.py +0 -46
- batframework-1.0.8a7.dist-info/LICENCE +0 -21
- batframework-1.0.8a7.dist-info/METADATA +0 -43
- batframework-1.0.8a7.dist-info/RECORD +0 -62
- {batframework-1.0.8a7.dist-info → batframework-1.0.8a9.dist-info}/top_level.txt +0 -0
batFramework/transition.py
CHANGED
@@ -1,228 +1,157 @@
|
|
1
|
-
import batFramework as bf
|
2
|
-
from typing import Self
|
3
1
|
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()
|
2
|
+
import batFramework as bf
|
85
3
|
|
86
4
|
|
87
|
-
class
|
5
|
+
class BaseTransition:
|
88
6
|
def __init__(
|
89
7
|
self,
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
easing_function: bf.easing = bf.easing.LINEAR,
|
8
|
+
source_surf: pygame.Surface,
|
9
|
+
dest_surf: pygame.Surface,
|
10
|
+
duration=100,
|
11
|
+
**kwargs,
|
95
12
|
) -> None:
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
self.first = Fade(first_duration)
|
103
|
-
self.second = Fade(second_duration)
|
104
|
-
self.color = color
|
105
|
-
self.middle_duration = middle_duration
|
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
|
106
19
|
self.index = 0
|
107
20
|
|
108
|
-
|
109
|
-
self.
|
110
|
-
self.second.set_end_callback(self.transition_to_end)
|
111
|
-
|
112
|
-
def transition_to_middle(self):
|
113
|
-
self.next_step(self.timer.start)
|
21
|
+
def set_scene_index(self,index):
|
22
|
+
self.index = index
|
114
23
|
|
115
|
-
def
|
116
|
-
self.
|
24
|
+
def set_source_name(self, name):
|
25
|
+
self.source_scene_name = name
|
117
26
|
|
118
|
-
def
|
119
|
-
self.
|
27
|
+
def set_dest_name(self, name):
|
28
|
+
self.dest_scene_name = name
|
120
29
|
|
121
|
-
def
|
122
|
-
|
123
|
-
if callback:
|
124
|
-
callback()
|
30
|
+
def update(self, dt):
|
31
|
+
pass
|
125
32
|
|
126
|
-
def
|
127
|
-
|
128
|
-
self.first.set_source(surface)
|
33
|
+
def draw(self, surface):
|
34
|
+
pass
|
129
35
|
|
130
|
-
def
|
131
|
-
|
132
|
-
self.second.set_dest(surface)
|
36
|
+
def has_ended(self):
|
37
|
+
return False
|
133
38
|
|
134
|
-
def
|
135
|
-
|
136
|
-
self.start_callback()
|
39
|
+
def set_ended(self, val):
|
40
|
+
self.ended = val
|
137
41
|
|
138
|
-
self.color_surf = pygame.Surface(self.source.get_size())
|
139
|
-
self.color_surf.fill(self.color)
|
140
42
|
|
141
|
-
|
142
|
-
|
143
|
-
self
|
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)
|
144
91
|
|
145
92
|
def draw(self, surface):
|
146
|
-
if self.
|
147
|
-
self.
|
148
|
-
|
149
|
-
surface.blit(self.color_surf, (0, 0))
|
150
|
-
else:
|
151
|
-
self.second.draw(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))
|
152
96
|
|
153
|
-
def skip(self, no_callback: bool = False):
|
154
|
-
if not no_callback and self.end_callback:
|
155
|
-
self.end_callback()
|
156
97
|
|
157
|
-
|
158
|
-
|
159
|
-
|
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()
|
160
103
|
|
104
|
+
def update_surface(self,progress):
|
105
|
+
self.source.set_alpha(int(255 - (255 * progress)))
|
106
|
+
self.dest.set_alpha(int(255 * progress))
|
161
107
|
|
162
|
-
|
163
|
-
|
164
|
-
def end(self):
|
165
|
-
self.dest.set_alpha(255)
|
166
|
-
return super().end()
|
108
|
+
def has_ended(self):
|
109
|
+
return self.ended
|
167
110
|
|
168
111
|
def draw(self, surface):
|
169
|
-
dest_alpha = 255 * self.controller.get_value()
|
170
|
-
self.dest.set_alpha(dest_alpha)
|
171
112
|
surface.blit(self.source, (0, 0))
|
172
113
|
surface.blit(self.dest, (0, 0))
|
173
114
|
|
174
115
|
|
175
|
-
class
|
176
|
-
def
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
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),
|
205
146
|
)
|
206
|
-
|
207
|
-
mask.to_surface(surface=surface, setsurface=self.dest, unsetsurface=self.source)
|
147
|
+
self.anim.start()
|
208
148
|
|
149
|
+
def update_offset(self, vec):
|
150
|
+
self.offset.update(vec)
|
209
151
|
|
210
|
-
|
211
|
-
|
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()
|
152
|
+
def has_ended(self):
|
153
|
+
return self.ended
|
217
154
|
|
218
155
|
def draw(self, surface):
|
219
|
-
|
220
|
-
|
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
|
-
|
156
|
+
surface.blit(self.source, (0, 0))
|
157
|
+
surface.blit(self.dest, self.offset)
|
File without changes
|
batFramework/triggerZone.py
CHANGED
@@ -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.
|
7
|
+
self.set_debug_color(bf.color.RIVER_BLUE)
|
8
8
|
self.active = active
|
9
9
|
self.callback = callback
|
10
10
|
self.trigger = trigger
|
batFramework/utils.py
CHANGED
@@ -3,14 +3,9 @@ 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
|
13
6
|
|
7
|
+
MAX_FONT_SIZE = 100
|
8
|
+
MIN_FONT_SIZE = 8
|
14
9
|
|
15
10
|
class Singleton(type):
|
16
11
|
_instances = {}
|
@@ -21,129 +16,169 @@ class Singleton(type):
|
|
21
16
|
return cls._instances[cls]
|
22
17
|
|
23
18
|
|
24
|
-
class
|
19
|
+
class Direction(Enum):
|
20
|
+
HORIZONTAL = "horizontal"
|
21
|
+
VERTICAL = "vertical"
|
25
22
|
|
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
|
45
23
|
|
46
|
-
|
24
|
+
class Alignment(Enum):
|
25
|
+
LEFT = "left"
|
26
|
+
RIGHT = "right"
|
27
|
+
CENTER = "center"
|
28
|
+
TOP = "top"
|
29
|
+
BOTTOM = "bottom"
|
47
30
|
|
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")
|
58
31
|
|
59
|
-
|
60
|
-
|
32
|
+
class Layout(Enum):
|
33
|
+
FILL = "fill"
|
34
|
+
FIT = "fit"
|
61
35
|
|
62
|
-
return filter_function
|
63
36
|
|
37
|
+
class Utils:
|
38
|
+
pygame.font.init()
|
39
|
+
FONTS = {}
|
40
|
+
tilesets = {}
|
64
41
|
|
65
42
|
@staticmethod
|
66
|
-
|
67
|
-
|
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)
|
101
|
-
|
102
|
-
return dest_surf
|
43
|
+
def get_path(path: str):
|
44
|
+
return os.path.join(bf.const.RESOURCE_PATH, path)
|
103
45
|
|
104
46
|
@staticmethod
|
105
|
-
def
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
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)
|
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
|
118
55
|
|
119
56
|
@staticmethod
|
120
|
-
def
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
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)
|
128
74
|
|
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
|
132
75
|
|
133
|
-
|
134
|
-
|
135
|
-
|
76
|
+
@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
|
+
|
136
95
|
|
137
|
-
|
138
|
-
|
96
|
+
@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)]
|
139
142
|
|
140
|
-
|
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
|
158
|
+
|
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
|
141
169
|
|
142
170
|
@staticmethod
|
143
|
-
def
|
144
|
-
|
145
|
-
|
146
|
-
return
|
171
|
+
def get_tileset(name: str) -> Tileset:
|
172
|
+
if name not in Utils.tilesets:
|
173
|
+
return None
|
174
|
+
return Utils.tilesets[name]
|
175
|
+
|
176
|
+
|
147
177
|
|
148
178
|
|
149
179
|
|
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
|