batframework 1.0.8a7__py3-none-any.whl → 1.0.8a8__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.8a8.dist-info/METADATA +53 -0
- batframework-1.0.8a8.dist-info/RECORD +42 -0
- {batframework-1.0.8a7.dist-info → batframework-1.0.8a8.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.8a8.dist-info}/top_level.txt +0 -0
batFramework/gui/textInput.py
DELETED
@@ -1,247 +0,0 @@
|
|
1
|
-
import batFramework as bf
|
2
|
-
from typing import Self, Callable
|
3
|
-
from .label import Label
|
4
|
-
from .interactiveWidget import InteractiveWidget
|
5
|
-
import pygame
|
6
|
-
|
7
|
-
def find_next_word(s: str, start_index: int) -> int:
|
8
|
-
length = len(s)
|
9
|
-
# Ensure the starting index is within the bounds of the string
|
10
|
-
if start_index < 0 or start_index >= length:
|
11
|
-
raise ValueError("Starting index is out of bounds")
|
12
|
-
index = start_index
|
13
|
-
# If the start_index is at a space, skip leading spaces
|
14
|
-
if s[index] in [' ','\n']:
|
15
|
-
while index < length and s[index] in [' ','\n']:
|
16
|
-
index += 1
|
17
|
-
# If we've reached the end of the string
|
18
|
-
if index >= length:
|
19
|
-
return -1
|
20
|
-
else:
|
21
|
-
# If the start_index is within a word, move to the end of that word
|
22
|
-
while index < length and s[index] not in [' ','\n']:
|
23
|
-
index += 1
|
24
|
-
if index == length:
|
25
|
-
return index
|
26
|
-
# Return the index of the start of the next word or -1 if no more words are found
|
27
|
-
return index if index < length else -1
|
28
|
-
|
29
|
-
def find_prev_word(s: str, start_index: int) -> int:
|
30
|
-
if start_index <= 0 : return 0
|
31
|
-
length = len(s)
|
32
|
-
|
33
|
-
# Ensure the starting index is within the bounds of the string
|
34
|
-
if start_index < 0 or start_index >= length:
|
35
|
-
raise ValueError("Starting index is out of bounds")
|
36
|
-
|
37
|
-
index = start_index
|
38
|
-
|
39
|
-
# If the start_index is at a space, skip trailing spaces
|
40
|
-
if s[index] in [' ', '\n']:
|
41
|
-
while index > 0 and s[index-1] in [' ', '\n']:
|
42
|
-
index -= 1
|
43
|
-
# If we've reached the beginning of the string
|
44
|
-
if index <= 0:
|
45
|
-
return 0 if s[0] not in [' ', '\n'] else -1
|
46
|
-
else:
|
47
|
-
# If the start_index is within a word, move to the start of that word
|
48
|
-
while index > 0 and s[index-1] not in [' ', '\n']:
|
49
|
-
index -= 1
|
50
|
-
if index == 0 and s[index] not in [' ', '\n']:
|
51
|
-
return 0
|
52
|
-
|
53
|
-
# Return the index of the start of the previous word or -1 if no more words are found
|
54
|
-
return index if index > 0 or (index == 0 and s[0] not in [' ', '\n']) else -1
|
55
|
-
|
56
|
-
|
57
|
-
class TextInput(Label, InteractiveWidget):
|
58
|
-
def __init__(self) -> None:
|
59
|
-
self.cursor_position = (0, 0)
|
60
|
-
self.old_key_repeat = (0, 0)
|
61
|
-
self.cursor_timer = bf.Timer(0.3, self._cursor_toggle, loop=True).start()
|
62
|
-
self.cursor_timer.pause()
|
63
|
-
self.show_cursor = False
|
64
|
-
self.on_modify: Callable[[str], str] = None
|
65
|
-
self.set_focusable(True)
|
66
|
-
self.set_outline_color("black")
|
67
|
-
super().__init__("")
|
68
|
-
self.alignment = bf.alignment.TOPLEFT
|
69
|
-
|
70
|
-
def set_modify_callback(self, callback: Callable[[str], str]) -> Self:
|
71
|
-
self.on_modify = callback
|
72
|
-
return self
|
73
|
-
|
74
|
-
def __str__(self) -> str:
|
75
|
-
return f"TextInput({repr(self.text)})"
|
76
|
-
|
77
|
-
def _cursor_toggle(self, value: bool | None = None):
|
78
|
-
if value is None:
|
79
|
-
value = not self.show_cursor
|
80
|
-
self.show_cursor = value
|
81
|
-
self.dirty_surface = True
|
82
|
-
|
83
|
-
def do_on_click_down(self, button):
|
84
|
-
if button != 1:
|
85
|
-
return
|
86
|
-
self.get_focus()
|
87
|
-
|
88
|
-
def do_on_enter(self):
|
89
|
-
pygame.mouse.set_cursor(pygame.SYSTEM_CURSOR_IBEAM)
|
90
|
-
|
91
|
-
def do_on_exit(self):
|
92
|
-
pygame.mouse.set_cursor(bf.const.DEFAULT_CURSOR)
|
93
|
-
|
94
|
-
def do_on_get_focus(self):
|
95
|
-
self.cursor_timer.resume()
|
96
|
-
self._cursor_toggle(True)
|
97
|
-
self.old_key_repeat = pygame.key.get_repeat()
|
98
|
-
pygame.key.set_repeat(200, 50)
|
99
|
-
|
100
|
-
def do_on_lose_focus(self):
|
101
|
-
self.cursor_timer.pause()
|
102
|
-
self._cursor_toggle(False)
|
103
|
-
pygame.key.set_repeat(*self.old_key_repeat)
|
104
|
-
|
105
|
-
def get_line(self, line: int) -> str | None:
|
106
|
-
if line < 0:
|
107
|
-
return None
|
108
|
-
lines = self.text.split('\n')
|
109
|
-
if line >= len(lines):
|
110
|
-
return None
|
111
|
-
return lines[line]
|
112
|
-
|
113
|
-
def set_cursor_position(self, position: tuple[int, int]) -> Self:
|
114
|
-
x, y = position
|
115
|
-
|
116
|
-
lines = self.text.split('\n')
|
117
|
-
y = max(0, min(y, len(lines) - 1))
|
118
|
-
line_length = len(lines[y])
|
119
|
-
x = max(0, min(x, line_length))
|
120
|
-
|
121
|
-
self.cursor_position = (x, y)
|
122
|
-
self.show_cursor = True
|
123
|
-
self.dirty_shape = True
|
124
|
-
return self
|
125
|
-
|
126
|
-
def cursor_to_absolute(self, position: tuple[int, int]) -> int:
|
127
|
-
x, y = position
|
128
|
-
|
129
|
-
y = max(0, min(y, len(self.text.split('\n')) - 1))
|
130
|
-
lines = self.text.split('\n')
|
131
|
-
x = max(0, min(x, len(lines[y])))
|
132
|
-
|
133
|
-
absolute_position = sum(len(line) + 1 for line in lines[:y]) + x
|
134
|
-
return absolute_position
|
135
|
-
|
136
|
-
def absolute_to_cursor(self, absolute: int) -> tuple[int, int]:
|
137
|
-
text = self.text
|
138
|
-
lines = text.split('\n')
|
139
|
-
current_pos = 0
|
140
|
-
|
141
|
-
for line_no, line in enumerate(lines):
|
142
|
-
if absolute <= current_pos + len(line):
|
143
|
-
return (absolute - current_pos, line_no)
|
144
|
-
current_pos += len(line) + 1
|
145
|
-
|
146
|
-
return (len(lines[-1]), len(lines) - 1)
|
147
|
-
|
148
|
-
def do_handle_event(self, event):
|
149
|
-
if not self.is_focused:
|
150
|
-
return
|
151
|
-
|
152
|
-
if event.type not in [pygame.TEXTINPUT, pygame.KEYDOWN]:
|
153
|
-
return
|
154
|
-
|
155
|
-
text = self.get_text()
|
156
|
-
current = self.cursor_to_absolute(self.cursor_position)
|
157
|
-
if event.type == pygame.TEXTINPUT:
|
158
|
-
self.set_text(text[:current] + event.text + text[current:])
|
159
|
-
self.set_cursor_position(self.absolute_to_cursor(current + len(event.text)))
|
160
|
-
elif event.type == pygame.KEYDOWN:
|
161
|
-
pressed = pygame.key.get_pressed()
|
162
|
-
if event.key == pygame.K_ESCAPE:
|
163
|
-
self.lose_focus()
|
164
|
-
elif event.key == pygame.K_BACKSPACE:
|
165
|
-
if current > 0:
|
166
|
-
self.set_text(text[:current - 1] + text[current:])
|
167
|
-
self.set_cursor_position(self.absolute_to_cursor(current - 1))
|
168
|
-
elif event.key == pygame.K_DELETE:
|
169
|
-
if current < len(text):
|
170
|
-
self.set_text(text[:current] + text[current + 1:])
|
171
|
-
elif event.key == pygame.K_RIGHT:
|
172
|
-
if self.cursor_to_absolute(self.cursor_position)>=len(self.text):
|
173
|
-
return
|
174
|
-
if self.cursor_position[0] == len(self.get_line(self.cursor_position[1])):
|
175
|
-
self.set_cursor_position((0, self.cursor_position[1] + 1))
|
176
|
-
else:
|
177
|
-
if pressed[pygame.K_LCTRL] or pressed[pygame.K_RCTRL]:
|
178
|
-
index = find_next_word(self.text,current)
|
179
|
-
if index ==-1 : index = current+1
|
180
|
-
self.set_cursor_position(self.absolute_to_cursor(index))
|
181
|
-
else:
|
182
|
-
self.set_cursor_position(self.absolute_to_cursor(current + 1))
|
183
|
-
elif event.key == pygame.K_LEFT:
|
184
|
-
|
185
|
-
|
186
|
-
if self.cursor_position[0] == 0 and self.cursor_position[1] > 0:
|
187
|
-
self.set_cursor_position((len(self.get_line(self.cursor_position[1] - 1)), self.cursor_position[1] - 1))
|
188
|
-
else:
|
189
|
-
if pressed[pygame.K_LCTRL] or pressed[pygame.K_RCTRL]:
|
190
|
-
index = find_prev_word(self.text,current-1)
|
191
|
-
if index ==-1 : index = current-1
|
192
|
-
self.set_cursor_position(self.absolute_to_cursor(index))
|
193
|
-
else:
|
194
|
-
self.set_cursor_position(self.absolute_to_cursor(current - 1))
|
195
|
-
elif event.key == pygame.K_UP:
|
196
|
-
x, y = self.cursor_position
|
197
|
-
self.set_cursor_position((x, y - 1))
|
198
|
-
elif event.key == pygame.K_DOWN:
|
199
|
-
x, y = self.cursor_position
|
200
|
-
self.set_cursor_position((x, y + 1))
|
201
|
-
elif event.key == pygame.K_RETURN:
|
202
|
-
self.set_text(text[:current] + '\n' + text[current:])
|
203
|
-
self.set_cursor_position(self.absolute_to_cursor(current + 1))
|
204
|
-
else:
|
205
|
-
return
|
206
|
-
else:
|
207
|
-
return
|
208
|
-
|
209
|
-
event.consumed = True
|
210
|
-
|
211
|
-
def set_text(self, text: str) -> Self:
|
212
|
-
if self.on_modify:
|
213
|
-
text = self.on_modify(text)
|
214
|
-
return super().set_text(text)
|
215
|
-
|
216
|
-
def _paint_cursor(self) -> None:
|
217
|
-
if not self.font_object or not self.show_cursor:
|
218
|
-
return
|
219
|
-
|
220
|
-
lines = self.text.split('\n')
|
221
|
-
line_x, line_y = self.cursor_position
|
222
|
-
|
223
|
-
cursor_y = self.padding[1]
|
224
|
-
cursor_y += line_y * self.font_object.get_linesize()
|
225
|
-
cursor_x = self.padding[0]
|
226
|
-
cursor_x += self.font_object.size(lines[line_y][:line_x])[0] if line_x > 0 else 0
|
227
|
-
|
228
|
-
cursor_rect = pygame.Rect(cursor_x, cursor_y, 2, self.font_object.get_height())
|
229
|
-
pygame.draw.rect(self.surface, self.text_color, cursor_rect)
|
230
|
-
|
231
|
-
def paint(self) -> None:
|
232
|
-
super().paint()
|
233
|
-
self._paint_cursor()
|
234
|
-
|
235
|
-
# def set_alignment(self, alignment: bf.alignment) -> Self:
|
236
|
-
# return self
|
237
|
-
|
238
|
-
# def align_text(
|
239
|
-
# self, text_rect: pygame.FRect, area: pygame.FRect, alignment: bf.alignment
|
240
|
-
# ):
|
241
|
-
# if alignment == bf.alignment.LEFT:
|
242
|
-
# alignment = bf.alignment.MIDLEFT
|
243
|
-
# elif alignment == bf.alignment.MIDRIGHT:
|
244
|
-
# alignment = bf.alignment.MIDRIGHT
|
245
|
-
# pos = area.__getattribute__(alignment.value)
|
246
|
-
# text_rect.__setattr__(alignment.value, pos)
|
247
|
-
# return
|
batFramework/object.py
DELETED
@@ -1,123 +0,0 @@
|
|
1
|
-
from typing import Any, Self
|
2
|
-
import pygame
|
3
|
-
import batFramework as bf
|
4
|
-
from typing import TYPE_CHECKING
|
5
|
-
|
6
|
-
if TYPE_CHECKING:
|
7
|
-
from .camera import Camera
|
8
|
-
|
9
|
-
|
10
|
-
class Object:
|
11
|
-
__count = 0
|
12
|
-
__available_uid = set()
|
13
|
-
__used_uid = set()
|
14
|
-
|
15
|
-
def __init__(self) -> None:
|
16
|
-
self.rect = pygame.FRect(0, 0, 0, 0)
|
17
|
-
self.tags: list[str] = []
|
18
|
-
self.parent_scene: bf.Scene | None = None
|
19
|
-
self.debug_color: tuple | str = "red"
|
20
|
-
self.render_order: int = 0
|
21
|
-
self.uid: int = Object.__count
|
22
|
-
Object.__used_uid.add(self.uid)
|
23
|
-
|
24
|
-
if Object.__available_uid:
|
25
|
-
self.name = Object.__available_uid.pop()
|
26
|
-
else:
|
27
|
-
self.name = Object.__count
|
28
|
-
Object.__count += 1
|
29
|
-
|
30
|
-
def __del__(self):
|
31
|
-
Object.__available_uid.add(self.uid)
|
32
|
-
|
33
|
-
def set_position(self, x, y) -> Self:
|
34
|
-
self.rect.topleft = x, y
|
35
|
-
return self
|
36
|
-
|
37
|
-
def set_center(self, x, y) -> Self:
|
38
|
-
self.rect.center = x, y
|
39
|
-
return self
|
40
|
-
|
41
|
-
def get_debug_outlines(self):
|
42
|
-
yield (self.rect, self.debug_color)
|
43
|
-
|
44
|
-
def set_debug_color(self, color) -> Self:
|
45
|
-
self.debug_color = color
|
46
|
-
return self
|
47
|
-
|
48
|
-
def set_parent_scene(self, scene) -> Self:
|
49
|
-
if scene == self.parent_scene:
|
50
|
-
return self
|
51
|
-
if self.parent_scene is not None:
|
52
|
-
self.do_when_removed()
|
53
|
-
self.parent_scene = scene
|
54
|
-
if scene is not None:
|
55
|
-
self.do_when_added()
|
56
|
-
return self
|
57
|
-
|
58
|
-
def do_when_added(self):
|
59
|
-
pass
|
60
|
-
|
61
|
-
def do_when_removed(self):
|
62
|
-
pass
|
63
|
-
|
64
|
-
def set_uid(self, uid: int) -> Self:
|
65
|
-
if uid in Object.__used_uid:
|
66
|
-
print(f"set_uid error : UID '{uid}' is already in use")
|
67
|
-
return self
|
68
|
-
self.uid = uid
|
69
|
-
Object.__used_uid.add(uid)
|
70
|
-
return self
|
71
|
-
|
72
|
-
def add_tags(self, *tags) -> Self:
|
73
|
-
for tag in tags:
|
74
|
-
if tag not in self.tags:
|
75
|
-
self.tags.append(tag)
|
76
|
-
self.tags.sort()
|
77
|
-
return self
|
78
|
-
|
79
|
-
def remove_tags(self, *tags):
|
80
|
-
self.tags = [tag for tag in self.tags if tag not in tags]
|
81
|
-
|
82
|
-
def has_tags(self, *tags) -> bool:
|
83
|
-
return all(tag in self.tags for tag in tags)
|
84
|
-
|
85
|
-
def get_tags(self) -> list[str]:
|
86
|
-
return self.tags
|
87
|
-
|
88
|
-
def process_event(self, event: pygame.Event) -> bool:
|
89
|
-
"""
|
90
|
-
Returns bool : True if the method is blocking (no propagation to next object of the scene)
|
91
|
-
"""
|
92
|
-
if event.consumed:
|
93
|
-
return
|
94
|
-
self.do_process_actions(event)
|
95
|
-
self.do_handle_event(event)
|
96
|
-
|
97
|
-
def do_process_actions(self, event: pygame.Event) -> None:
|
98
|
-
"""
|
99
|
-
Process entity actions you may have set
|
100
|
-
"""
|
101
|
-
|
102
|
-
def do_reset_actions(self) -> None:
|
103
|
-
"""
|
104
|
-
Reset entity actions you may have set
|
105
|
-
"""
|
106
|
-
|
107
|
-
def do_handle_event(self, event: pygame.Event):
|
108
|
-
"""
|
109
|
-
Handle specific events with no action support
|
110
|
-
"""
|
111
|
-
return False
|
112
|
-
|
113
|
-
def update(self, dt: float) -> None:
|
114
|
-
"""
|
115
|
-
Update method to be overriden by subclasses of object (must call do_update and do_reset_actions)
|
116
|
-
"""
|
117
|
-
self.do_update(dt)
|
118
|
-
self.do_reset_actions()
|
119
|
-
|
120
|
-
def do_update(self, dt: float) -> None:
|
121
|
-
"""
|
122
|
-
Update method to be overriden for specific behavior by the end user
|
123
|
-
"""
|
batFramework/particle.py
DELETED
@@ -1,115 +0,0 @@
|
|
1
|
-
import batFramework as bf
|
2
|
-
import pygame
|
3
|
-
from pygame.math import Vector2
|
4
|
-
|
5
|
-
|
6
|
-
class Particle:
|
7
|
-
def __init__(self, *args, **kwargs):
|
8
|
-
self.dead = False
|
9
|
-
self.surface = None
|
10
|
-
self.generator = None
|
11
|
-
|
12
|
-
def do_when_added(self):
|
13
|
-
pass
|
14
|
-
|
15
|
-
def update(self, dt):
|
16
|
-
pass
|
17
|
-
|
18
|
-
def kill(self):
|
19
|
-
self.dead = True
|
20
|
-
|
21
|
-
def update_surface(self):
|
22
|
-
pass
|
23
|
-
|
24
|
-
|
25
|
-
class TimedParticle(Particle):
|
26
|
-
def __init__(self, duration):
|
27
|
-
super().__init__()
|
28
|
-
self.duration = duration
|
29
|
-
|
30
|
-
def do_when_added(self):
|
31
|
-
if self.generator and self.generator.parent_scene:
|
32
|
-
self.timer = bf.SceneTimer(
|
33
|
-
self.duration, end_callback=self.kill,
|
34
|
-
scene_name=self.generator.parent_scene.name).start()
|
35
|
-
else:
|
36
|
-
self.timer = bf.Timer(self.duration, end_callback=self.kill).start()
|
37
|
-
|
38
|
-
|
39
|
-
class BasicParticle(TimedParticle):
|
40
|
-
def __init__(
|
41
|
-
self,
|
42
|
-
start_pos: tuple[float, float],
|
43
|
-
start_vel: tuple[float, float],
|
44
|
-
duration=1,
|
45
|
-
color=None,
|
46
|
-
size: tuple[int, int] = (4, 4),
|
47
|
-
*args,
|
48
|
-
**kwargs,
|
49
|
-
):
|
50
|
-
super().__init__(duration)
|
51
|
-
self.rect = pygame.FRect(0,0, *size)
|
52
|
-
self.rect.center = start_pos
|
53
|
-
self.surface = pygame.Surface(size)
|
54
|
-
self.velocity = Vector2(start_vel)
|
55
|
-
if color:
|
56
|
-
self.surface.fill(color)
|
57
|
-
self.start()
|
58
|
-
|
59
|
-
def start(self):
|
60
|
-
pass
|
61
|
-
|
62
|
-
def update(self, dt):
|
63
|
-
super().update(dt)
|
64
|
-
self.rect.center += self.velocity * dt
|
65
|
-
self.update_surface()
|
66
|
-
|
67
|
-
def update_surface(self):
|
68
|
-
self.surface.set_alpha(255 - int(self.timer.get_progression() * 255))
|
69
|
-
|
70
|
-
|
71
|
-
class DirectionalParticle(BasicParticle):
|
72
|
-
def start(self):
|
73
|
-
self.original_surface = self.surface.copy()
|
74
|
-
|
75
|
-
def update_surface(self):
|
76
|
-
angle = self.velocity.angle_to(Vector2(1, 0))
|
77
|
-
self.surface = pygame.transform.rotate(self.original_surface, angle)
|
78
|
-
super().update_surface()
|
79
|
-
|
80
|
-
|
81
|
-
class ParticleGenerator(bf.Entity):
|
82
|
-
def __init__(self) -> None:
|
83
|
-
super().__init__((0, 0))
|
84
|
-
self.particles: list[Particle] = []
|
85
|
-
|
86
|
-
def get_debug_outlines(self):
|
87
|
-
return
|
88
|
-
for particle in self.particles:
|
89
|
-
yield (
|
90
|
-
particle.rect.move(particle.rect.w // 2, particle.rect.h // 2),
|
91
|
-
"blue",
|
92
|
-
)
|
93
|
-
yield (self.rect, "cyan")
|
94
|
-
|
95
|
-
def add_particle(self, particle:Particle):
|
96
|
-
particle.generator = self
|
97
|
-
particle.do_when_added()
|
98
|
-
self.particles.append(particle)
|
99
|
-
|
100
|
-
def clear(self):
|
101
|
-
self.particles = []
|
102
|
-
|
103
|
-
def update(self, dt: float):
|
104
|
-
particles_to_remove = []
|
105
|
-
for particle in self.particles:
|
106
|
-
particle.update(dt)
|
107
|
-
if particle.dead:
|
108
|
-
particles_to_remove.append(particle)
|
109
|
-
for p in particles_to_remove:
|
110
|
-
self.particles.remove(p)
|
111
|
-
|
112
|
-
def draw(self, camera) -> None:
|
113
|
-
camera.surface.fblits(
|
114
|
-
[(p.surface, camera.world_to_screen(p.rect)) for p in self.particles]
|
115
|
-
)
|
batFramework/renderGroup.py
DELETED
@@ -1,67 +0,0 @@
|
|
1
|
-
import batFramework as bf
|
2
|
-
import pygame
|
3
|
-
from typing import Self, Iterator, Callable
|
4
|
-
|
5
|
-
"""
|
6
|
-
+ same render order
|
7
|
-
+ fblits
|
8
|
-
"""
|
9
|
-
|
10
|
-
|
11
|
-
class RenderGroup(bf.Entity):
|
12
|
-
def __init__(
|
13
|
-
self, entity_iterator: Callable[[], Iterator[bf.Entity]], blit_flags: int = 0
|
14
|
-
) -> None:
|
15
|
-
super().__init__()
|
16
|
-
self.entity_iterator = entity_iterator
|
17
|
-
self.set_blit_flags(blit_flags)
|
18
|
-
self.set_debug_color("white")
|
19
|
-
|
20
|
-
def get_debug_outlines(self):
|
21
|
-
# yield (self.rect, self.debug_color)
|
22
|
-
for e in self.entity_iterator():
|
23
|
-
yield from e.get_debug_outlines()
|
24
|
-
|
25
|
-
def set_parent_scene(self, scene) -> Self:
|
26
|
-
self.parent_scene = scene
|
27
|
-
for e in self.entity_iterator():
|
28
|
-
e.set_parent_scene(scene)
|
29
|
-
return self
|
30
|
-
|
31
|
-
def process_event(self, event: pygame.Event) -> bool:
|
32
|
-
"""
|
33
|
-
Returns bool : True if the method is blocking (no propagation to next children of the scene)
|
34
|
-
"""
|
35
|
-
self.do_process_actions(event)
|
36
|
-
res = self.do_handle_event(event)
|
37
|
-
if res:
|
38
|
-
return res
|
39
|
-
for e in self.entity_iterator():
|
40
|
-
if e.process_event(event):
|
41
|
-
return True
|
42
|
-
return False
|
43
|
-
|
44
|
-
def update(self, dt: float) -> None:
|
45
|
-
"""
|
46
|
-
Update method to be overriden by subclasses of entity
|
47
|
-
"""
|
48
|
-
for e in self.entity_iterator():
|
49
|
-
e.update(dt)
|
50
|
-
# gen = self.entity_iterator()
|
51
|
-
# self.rect = next(gen).rect.unionall([e.rect for e in gen])
|
52
|
-
|
53
|
-
self.do_update(dt)
|
54
|
-
self.do_reset_actions()
|
55
|
-
|
56
|
-
def draw(self, camera: bf.Camera) -> None:
|
57
|
-
"""
|
58
|
-
Draw the entity onto the camera with coordinate transposing
|
59
|
-
"""
|
60
|
-
if not self.visible:
|
61
|
-
return
|
62
|
-
fblits_data = (
|
63
|
-
(e.surface, (e.rect.x - camera.rect.x, e.rect.y - camera.rect.y))
|
64
|
-
for e in self.entity_iterator()
|
65
|
-
if camera.rect.colliderect(e.rect)
|
66
|
-
)
|
67
|
-
camera.surface.fblits(fblits_data, self.blit_flags)
|
batFramework/resourceManager.py
DELETED
@@ -1,100 +0,0 @@
|
|
1
|
-
import batFramework as bf
|
2
|
-
import os
|
3
|
-
import pygame
|
4
|
-
import sys
|
5
|
-
import json
|
6
|
-
from typing import Any
|
7
|
-
from .utils import Singleton
|
8
|
-
|
9
|
-
if getattr(sys, "frozen", False):
|
10
|
-
# If the application is run as a bundle, the PyInstaller bootloader
|
11
|
-
# extends the sys module by a flag frozen=True and sets the app
|
12
|
-
# path into variable _MEIPASS'.
|
13
|
-
application_path = sys._MEIPASS
|
14
|
-
else:
|
15
|
-
application_path = os.getcwd()
|
16
|
-
|
17
|
-
|
18
|
-
class ResourceManager(metaclass=Singleton):
|
19
|
-
def __init__(self):
|
20
|
-
self.shared_variables: dict[str,Any] = {}
|
21
|
-
self.convert_image_cache = {}
|
22
|
-
self.convert_alpha_image_cache = {}
|
23
|
-
self.sound_cache = {}
|
24
|
-
self.RESOURCE_PATH = "."
|
25
|
-
|
26
|
-
def load_dir(self, path) -> None:
|
27
|
-
for root, dirs, files in os.walk(path):
|
28
|
-
files = [f for f in files if not f[0] == "."]
|
29
|
-
dirs[:] = [d for d in dirs if not d[0] == "."]
|
30
|
-
|
31
|
-
for file in files:
|
32
|
-
file_path = os.path.join(root, file)
|
33
|
-
if file.lower().endswith((".png", ".jpg", ".jpeg", ".gif")):
|
34
|
-
self.load_image(file_path)
|
35
|
-
# print(f"Loaded image : '{file_path}'")
|
36
|
-
|
37
|
-
elif file.lower().endswith((".mp3", ".wav")):
|
38
|
-
bf.AudioManager().load_sound(file.split(".")[0], file_path)
|
39
|
-
# print(f"Loaded sound : '{file_path}'")
|
40
|
-
|
41
|
-
elif file.lower().endswith((".ttf", ".otf")):
|
42
|
-
bf.FontManager().load_font(file_path, file.split(".")[0])
|
43
|
-
# print(f"Loaded font : '{file_path}'")
|
44
|
-
|
45
|
-
print(f"Loaded resources in directory : '{path}'")
|
46
|
-
|
47
|
-
def set_resource_path(self, path: str):
|
48
|
-
self.RESOURCE_PATH = os.path.join(application_path, path)
|
49
|
-
print(f"Resource path : '{self.RESOURCE_PATH}'")
|
50
|
-
|
51
|
-
def get_path(self, path: str) -> str:
|
52
|
-
# Normalize path separators
|
53
|
-
normalized_path = path.replace("/", os.sep).replace("\\", os.sep)
|
54
|
-
return os.path.join(self.RESOURCE_PATH, normalized_path)
|
55
|
-
|
56
|
-
def load_image(self, path) -> None:
|
57
|
-
key = self.get_path(path)
|
58
|
-
if key in self.convert_image_cache:
|
59
|
-
return
|
60
|
-
self.convert_image_cache[key] = pygame.image.load(path).convert()
|
61
|
-
self.convert_alpha_image_cache[key] = pygame.image.load(path).convert_alpha()
|
62
|
-
|
63
|
-
def get_image(self, path, convert_alpha: bool = False) -> pygame.Surface | None:
|
64
|
-
key = self.get_path(path)
|
65
|
-
return (
|
66
|
-
self.convert_alpha_image_cache.get(key, None)
|
67
|
-
if convert_alpha
|
68
|
-
else self.convert_image_cache.get(key, None)
|
69
|
-
)
|
70
|
-
|
71
|
-
def load_json_from_file(self, path: str) -> dict | None:
|
72
|
-
try:
|
73
|
-
with open(self.get_path(path), "r") as file:
|
74
|
-
data = json.load(file)
|
75
|
-
return data
|
76
|
-
except FileNotFoundError:
|
77
|
-
print(f"File '{path}' not found")
|
78
|
-
return None
|
79
|
-
|
80
|
-
def save_json_to_file(self, path: str, data) -> bool:
|
81
|
-
try:
|
82
|
-
with open(self.get_path(path), "w") as file:
|
83
|
-
json.dump(data, file, indent=2)
|
84
|
-
return True
|
85
|
-
except FileNotFoundError:
|
86
|
-
return False
|
87
|
-
|
88
|
-
|
89
|
-
def set_sharedVar(self, name, value) -> bool:
|
90
|
-
"""
|
91
|
-
Set a shared variable of any type. This will be accessible (read/write) from any scene
|
92
|
-
"""
|
93
|
-
self.shared_variables[name] = value
|
94
|
-
return True
|
95
|
-
|
96
|
-
def get_sharedVar(self, name, error_value=None):
|
97
|
-
"""
|
98
|
-
Get a shared variable
|
99
|
-
"""
|
100
|
-
return self.shared_variables.get(name, error_value)
|