batframework 1.0.9a11__py3-none-any.whl → 1.0.9a13__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 +3 -11
- batFramework/action.py +280 -279
- batFramework/actionContainer.py +105 -82
- batFramework/animatedSprite.py +80 -58
- batFramework/animation.py +91 -77
- batFramework/audioManager.py +156 -131
- batFramework/baseScene.py +249 -240
- batFramework/camera.py +245 -317
- batFramework/constants.py +57 -51
- batFramework/cutscene.py +239 -253
- batFramework/cutsceneManager.py +34 -34
- batFramework/drawable.py +107 -77
- batFramework/dynamicEntity.py +30 -30
- batFramework/easingController.py +58 -58
- batFramework/entity.py +130 -130
- batFramework/enums.py +171 -135
- batFramework/fontManager.py +65 -65
- batFramework/gui/__init__.py +28 -25
- batFramework/gui/animatedLabel.py +90 -89
- batFramework/gui/button.py +17 -17
- batFramework/gui/clickableWidget.py +244 -244
- batFramework/gui/collapseContainer.py +98 -0
- batFramework/gui/constraints/__init__.py +1 -1
- batFramework/gui/constraints/constraints.py +1066 -980
- batFramework/gui/container.py +220 -206
- batFramework/gui/debugger.py +140 -130
- batFramework/gui/draggableWidget.py +63 -44
- batFramework/gui/image.py +61 -58
- batFramework/gui/indicator.py +116 -113
- batFramework/gui/interactiveWidget.py +243 -239
- batFramework/gui/label.py +147 -344
- batFramework/gui/layout.py +442 -429
- batFramework/gui/meter.py +155 -96
- batFramework/gui/radioButton.py +43 -35
- batFramework/gui/root.py +228 -228
- batFramework/gui/scrollingContainer.py +282 -0
- batFramework/gui/selector.py +232 -250
- batFramework/gui/shape.py +286 -276
- batFramework/gui/slider.py +353 -397
- batFramework/gui/style.py +10 -10
- batFramework/gui/styleManager.py +49 -54
- batFramework/gui/syncedVar.py +43 -49
- batFramework/gui/textInput.py +331 -306
- batFramework/gui/textWidget.py +308 -0
- batFramework/gui/toggle.py +140 -128
- batFramework/gui/tooltip.py +35 -30
- batFramework/gui/widget.py +546 -521
- batFramework/manager.py +131 -134
- batFramework/particle.py +118 -118
- batFramework/propertyEaser.py +79 -79
- batFramework/renderGroup.py +34 -34
- batFramework/resourceManager.py +130 -130
- batFramework/scene.py +31 -31
- batFramework/sceneLayer.py +134 -138
- batFramework/sceneManager.py +200 -197
- batFramework/scrollingSprite.py +115 -115
- batFramework/sprite.py +46 -51
- batFramework/stateMachine.py +49 -54
- batFramework/templates/__init__.py +2 -1
- batFramework/templates/character.py +15 -0
- batFramework/templates/controller.py +158 -97
- batFramework/templates/stateMachine.py +39 -0
- batFramework/tileset.py +46 -46
- batFramework/timeManager.py +213 -213
- batFramework/transition.py +162 -162
- batFramework/triggerZone.py +22 -22
- batFramework/utils.py +306 -306
- {batframework-1.0.9a11.dist-info → batframework-1.0.9a13.dist-info}/LICENSE +20 -20
- {batframework-1.0.9a11.dist-info → batframework-1.0.9a13.dist-info}/METADATA +24 -17
- batframework-1.0.9a13.dist-info/RECORD +72 -0
- batframework-1.0.9a11.dist-info/RECORD +0 -67
- {batframework-1.0.9a11.dist-info → batframework-1.0.9a13.dist-info}/WHEEL +0 -0
- {batframework-1.0.9a11.dist-info → batframework-1.0.9a13.dist-info}/top_level.txt +0 -0
batFramework/sceneManager.py
CHANGED
@@ -1,197 +1,200 @@
|
|
1
|
-
import batFramework as bf
|
2
|
-
import pygame
|
3
|
-
from typing import Self
|
4
|
-
|
5
|
-
def swap(lst, index1, index2):
|
6
|
-
lst[index1], lst[index2] = lst[index2], lst[index1]
|
7
|
-
|
8
|
-
|
9
|
-
class SceneManager:
|
10
|
-
def __init__(self) -> None:
|
11
|
-
self.scenes: list[bf.BaseScene] = []
|
12
|
-
self.shared_events = {pygame.WINDOWRESIZED}
|
13
|
-
self.current_transition : tuple[str,bf.transition.Transition,int] | None= None
|
14
|
-
|
15
|
-
def init_scenes(self, *initial_scenes:bf.Scene):
|
16
|
-
for index, s in enumerate(initial_scenes):
|
17
|
-
s.set_scene_index(index)
|
18
|
-
for s in reversed(initial_scenes):
|
19
|
-
self.add_scene(s)
|
20
|
-
self.set_scene(initial_scenes[0].get_name())
|
21
|
-
self.update_scene_states()
|
22
|
-
|
23
|
-
def set_shared_event(self, event: pygame.Event) -> None:
|
24
|
-
"""
|
25
|
-
Add an event that will be propagated to all active scenes, not just the one on top.
|
26
|
-
"""
|
27
|
-
self.shared_events.add(event)
|
28
|
-
|
29
|
-
def print_status(self):
|
30
|
-
"""
|
31
|
-
Print detailed information about the current state of the scenes and shared variables.
|
32
|
-
"""
|
33
|
-
|
34
|
-
def format_scene_info(scene:bf.Scene):
|
35
|
-
status = 'Active' if scene.active else 'Inactive'
|
36
|
-
visibility = 'Visible' if scene.visible else 'Invisible'
|
37
|
-
return f"{scene.name:<30} | {status:<8} | {visibility:<10} | Index={scene.scene_index}"
|
38
|
-
|
39
|
-
def format_shared_variable(name, value):
|
40
|
-
return f"[{name}] = {value}"
|
41
|
-
|
42
|
-
print("\n" + "=" * 50)
|
43
|
-
print(" SCENE STATUS".center(50))
|
44
|
-
print("=" * 50)
|
45
|
-
|
46
|
-
# Print scene information
|
47
|
-
if self.scenes:
|
48
|
-
header = f"{'Scene Name':<30} | {'Status':<8} | {'Visibility':<10} | {'Index':<7}"
|
49
|
-
print(header)
|
50
|
-
print("-" * 50)
|
51
|
-
print("\n".join(format_scene_info(s) for s in self.scenes))
|
52
|
-
else:
|
53
|
-
print("No scenes available.")
|
54
|
-
|
55
|
-
# Print debugging mode status
|
56
|
-
print("\n" + "=" * 50)
|
57
|
-
print(" DEBUGGING STATUS".center(50))
|
58
|
-
print("=" * 50)
|
59
|
-
print(f"[Debugging Mode] = {bf.ResourceManager().get_sharedVar('debug_mode')}")
|
60
|
-
|
61
|
-
# Print shared variables
|
62
|
-
print("\n" + "=" * 50)
|
63
|
-
print(" SHARED VARIABLES".center(50))
|
64
|
-
print("=" * 50)
|
65
|
-
|
66
|
-
if bf.ResourceManager().shared_variables:
|
67
|
-
for name, value in bf.ResourceManager().shared_variables.items():
|
68
|
-
print(format_shared_variable(name, value))
|
69
|
-
else:
|
70
|
-
print("No shared variables available.")
|
71
|
-
|
72
|
-
print("=" * 50 + "\n")
|
73
|
-
|
74
|
-
def get_current_scene_name(self) -> str:
|
75
|
-
"""get the name of the current scene"""
|
76
|
-
return self.scenes[0].get_name()
|
77
|
-
|
78
|
-
def get_current_scene(self) -> bf.Scene:
|
79
|
-
return self.scenes[0]
|
80
|
-
|
81
|
-
def update_scene_states(self):
|
82
|
-
self.active_scenes = [s for s in reversed(self.scenes) if s.active]
|
83
|
-
self.visible_scenes = [s for s in reversed(self.scenes) if s.visible]
|
84
|
-
|
85
|
-
def add_scene(self, scene: bf.Scene):
|
86
|
-
if scene in self.scenes and not self.has_scene(scene.name):
|
87
|
-
return
|
88
|
-
scene.set_manager(self)
|
89
|
-
scene.when_added()
|
90
|
-
self.scenes.insert(0, scene)
|
91
|
-
|
92
|
-
def remove_scene(self, name: str):
|
93
|
-
self.scenes = [s for s in self.scenes if s.name != name]
|
94
|
-
|
95
|
-
def has_scene(self, name:str):
|
96
|
-
return any(name == scene.name for scene in self.scenes)
|
97
|
-
|
98
|
-
def get_scene(self, name:str):
|
99
|
-
if not self.has_scene(name):
|
100
|
-
return None
|
101
|
-
for scene in self.scenes:
|
102
|
-
if scene.name == name:
|
103
|
-
return scene
|
104
|
-
|
105
|
-
def get_scene_at(self, index: int) -> bf.Scene | None:
|
106
|
-
if index < 0 or index >= len(self.scenes):
|
107
|
-
return None
|
108
|
-
return self.scenes[index]
|
109
|
-
|
110
|
-
def transition_to_scene(
|
111
|
-
self,
|
112
|
-
scene_name: str,
|
113
|
-
transition: bf.transition.Transition = None,
|
114
|
-
index: int = 0,
|
115
|
-
):
|
116
|
-
if transition is None:
|
117
|
-
transition = bf.transition.Fade(0.1)
|
118
|
-
if not (target_scene := self.get_scene(scene_name)):
|
119
|
-
print(f"Scene '{scene_name}' does not exist")
|
120
|
-
return
|
121
|
-
if not (source_scene := self.get_scene_at(index)):
|
122
|
-
print(f"No scene exists at index {index}.")
|
123
|
-
return
|
124
|
-
|
125
|
-
source_surface = bf.const.SCREEN.copy()
|
126
|
-
dest_surface = bf.const.SCREEN.copy()
|
127
|
-
|
128
|
-
target_scene.draw(dest_surface) # draw at least once to ensure smooth transition
|
129
|
-
target_scene.set_active(True)
|
130
|
-
target_scene.set_visible(True)
|
131
|
-
|
132
|
-
target_scene.do_on_enter_early()
|
133
|
-
source_scene.do_on_exit_early()
|
134
|
-
|
135
|
-
self.current_transition :tuple[str,bf.transition.Transition]=(scene_name,transition,index)
|
136
|
-
transition.set_source(source_surface)
|
137
|
-
transition.set_dest(dest_surface)
|
138
|
-
transition.start()
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
def set_scene(self, scene_name, index=0, ignore_early: bool = False):
|
143
|
-
target_scene = self.get_scene(scene_name)
|
144
|
-
if not target_scene:
|
145
|
-
print(f"'{scene_name}' does not exist")
|
146
|
-
return
|
147
|
-
if len(self.scenes) == 0 or index >= len(self.scenes) or index < 0:
|
148
|
-
return
|
149
|
-
|
150
|
-
# switch
|
151
|
-
if not ignore_early:
|
152
|
-
self.scenes[index].do_on_exit_early()
|
153
|
-
self.scenes[index].on_exit()
|
154
|
-
# re-insert scene at index 0
|
155
|
-
self.scenes.remove(target_scene)
|
156
|
-
self.scenes.insert(index, target_scene)
|
157
|
-
_ = [s.set_scene_index(i) for i, s in enumerate(self.scenes)]
|
158
|
-
if not ignore_early:
|
159
|
-
self.scenes[index].do_on_enter_early()
|
160
|
-
target_scene.on_enter()
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
def cycle_debug_mode(self):
|
165
|
-
current_index = bf.ResourceManager().get_sharedVar("debug_mode").value
|
166
|
-
next_index = (current_index + 1) % len(bf.debugMode)
|
167
|
-
bf.ResourceManager().set_sharedVar("debug_mode", bf.debugMode(next_index))
|
168
|
-
return bf.debugMode(next_index)
|
169
|
-
|
170
|
-
def
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
self.
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
def
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
self.current_transition[1].
|
196
|
-
|
197
|
-
|
1
|
+
import batFramework as bf
|
2
|
+
import pygame
|
3
|
+
from typing import Self
|
4
|
+
|
5
|
+
def swap(lst, index1, index2):
|
6
|
+
lst[index1], lst[index2] = lst[index2], lst[index1]
|
7
|
+
|
8
|
+
|
9
|
+
class SceneManager:
|
10
|
+
def __init__(self) -> None:
|
11
|
+
self.scenes: list[bf.BaseScene] = []
|
12
|
+
self.shared_events = {pygame.WINDOWRESIZED}
|
13
|
+
self.current_transition : tuple[str,bf.transition.Transition,int] | None= None
|
14
|
+
|
15
|
+
def init_scenes(self, *initial_scenes:bf.Scene):
|
16
|
+
for index, s in enumerate(initial_scenes):
|
17
|
+
s.set_scene_index(index)
|
18
|
+
for s in reversed(initial_scenes):
|
19
|
+
self.add_scene(s)
|
20
|
+
self.set_scene(initial_scenes[0].get_name())
|
21
|
+
self.update_scene_states()
|
22
|
+
|
23
|
+
def set_shared_event(self, event: pygame.Event) -> None:
|
24
|
+
"""
|
25
|
+
Add an event that will be propagated to all active scenes, not just the one on top.
|
26
|
+
"""
|
27
|
+
self.shared_events.add(event)
|
28
|
+
|
29
|
+
def print_status(self):
|
30
|
+
"""
|
31
|
+
Print detailed information about the current state of the scenes and shared variables.
|
32
|
+
"""
|
33
|
+
|
34
|
+
def format_scene_info(scene:bf.Scene):
|
35
|
+
status = 'Active' if scene.active else 'Inactive'
|
36
|
+
visibility = 'Visible' if scene.visible else 'Invisible'
|
37
|
+
return f"{scene.name:<30} | {status:<8} | {visibility:<10} | Index={scene.scene_index}"
|
38
|
+
|
39
|
+
def format_shared_variable(name, value):
|
40
|
+
return f"[{name}] = {value}"
|
41
|
+
|
42
|
+
print("\n" + "=" * 50)
|
43
|
+
print(" SCENE STATUS".center(50))
|
44
|
+
print("=" * 50)
|
45
|
+
|
46
|
+
# Print scene information
|
47
|
+
if self.scenes:
|
48
|
+
header = f"{'Scene Name':<30} | {'Status':<8} | {'Visibility':<10} | {'Index':<7}"
|
49
|
+
print(header)
|
50
|
+
print("-" * 50)
|
51
|
+
print("\n".join(format_scene_info(s) for s in self.scenes))
|
52
|
+
else:
|
53
|
+
print("No scenes available.")
|
54
|
+
|
55
|
+
# Print debugging mode status
|
56
|
+
print("\n" + "=" * 50)
|
57
|
+
print(" DEBUGGING STATUS".center(50))
|
58
|
+
print("=" * 50)
|
59
|
+
print(f"[Debugging Mode] = {bf.ResourceManager().get_sharedVar('debug_mode')}")
|
60
|
+
|
61
|
+
# Print shared variables
|
62
|
+
print("\n" + "=" * 50)
|
63
|
+
print(" SHARED VARIABLES".center(50))
|
64
|
+
print("=" * 50)
|
65
|
+
|
66
|
+
if bf.ResourceManager().shared_variables:
|
67
|
+
for name, value in bf.ResourceManager().shared_variables.items():
|
68
|
+
print(format_shared_variable(name, value))
|
69
|
+
else:
|
70
|
+
print("No shared variables available.")
|
71
|
+
|
72
|
+
print("=" * 50 + "\n")
|
73
|
+
|
74
|
+
def get_current_scene_name(self) -> str:
|
75
|
+
"""get the name of the current scene"""
|
76
|
+
return self.scenes[0].get_name()
|
77
|
+
|
78
|
+
def get_current_scene(self) -> bf.Scene:
|
79
|
+
return self.scenes[0]
|
80
|
+
|
81
|
+
def update_scene_states(self):
|
82
|
+
self.active_scenes = [s for s in reversed(self.scenes) if s.active]
|
83
|
+
self.visible_scenes = [s for s in reversed(self.scenes) if s.visible]
|
84
|
+
|
85
|
+
def add_scene(self, scene: bf.Scene):
|
86
|
+
if scene in self.scenes and not self.has_scene(scene.name):
|
87
|
+
return
|
88
|
+
scene.set_manager(self)
|
89
|
+
scene.when_added()
|
90
|
+
self.scenes.insert(0, scene)
|
91
|
+
|
92
|
+
def remove_scene(self, name: str):
|
93
|
+
self.scenes = [s for s in self.scenes if s.name != name]
|
94
|
+
|
95
|
+
def has_scene(self, name:str):
|
96
|
+
return any(name == scene.name for scene in self.scenes)
|
97
|
+
|
98
|
+
def get_scene(self, name:str):
|
99
|
+
if not self.has_scene(name):
|
100
|
+
return None
|
101
|
+
for scene in self.scenes:
|
102
|
+
if scene.name == name:
|
103
|
+
return scene
|
104
|
+
|
105
|
+
def get_scene_at(self, index: int) -> bf.Scene | None:
|
106
|
+
if index < 0 or index >= len(self.scenes):
|
107
|
+
return None
|
108
|
+
return self.scenes[index]
|
109
|
+
|
110
|
+
def transition_to_scene(
|
111
|
+
self,
|
112
|
+
scene_name: str,
|
113
|
+
transition: bf.transition.Transition = None,
|
114
|
+
index: int = 0,
|
115
|
+
):
|
116
|
+
if transition is None:
|
117
|
+
transition = bf.transition.Fade(0.1)
|
118
|
+
if not (target_scene := self.get_scene(scene_name)):
|
119
|
+
print(f"Scene '{scene_name}' does not exist")
|
120
|
+
return
|
121
|
+
if not (source_scene := self.get_scene_at(index)):
|
122
|
+
print(f"No scene exists at index {index}.")
|
123
|
+
return
|
124
|
+
|
125
|
+
source_surface = bf.const.SCREEN.copy()
|
126
|
+
dest_surface = bf.const.SCREEN.copy()
|
127
|
+
|
128
|
+
target_scene.draw(dest_surface) # draw at least once to ensure smooth transition
|
129
|
+
target_scene.set_active(True)
|
130
|
+
target_scene.set_visible(True)
|
131
|
+
|
132
|
+
target_scene.do_on_enter_early()
|
133
|
+
source_scene.do_on_exit_early()
|
134
|
+
|
135
|
+
self.current_transition :tuple[str,bf.transition.Transition]=(scene_name,transition,index)
|
136
|
+
transition.set_source(source_surface)
|
137
|
+
transition.set_dest(dest_surface)
|
138
|
+
transition.start()
|
139
|
+
|
140
|
+
|
141
|
+
|
142
|
+
def set_scene(self, scene_name, index=0, ignore_early: bool = False):
|
143
|
+
target_scene = self.get_scene(scene_name)
|
144
|
+
if not target_scene:
|
145
|
+
print(f"'{scene_name}' does not exist")
|
146
|
+
return
|
147
|
+
if len(self.scenes) == 0 or index >= len(self.scenes) or index < 0:
|
148
|
+
return
|
149
|
+
|
150
|
+
# switch
|
151
|
+
if not ignore_early:
|
152
|
+
self.scenes[index].do_on_exit_early()
|
153
|
+
self.scenes[index].on_exit()
|
154
|
+
# re-insert scene at index 0
|
155
|
+
self.scenes.remove(target_scene)
|
156
|
+
self.scenes.insert(index, target_scene)
|
157
|
+
_ = [s.set_scene_index(i) for i, s in enumerate(self.scenes)]
|
158
|
+
if not ignore_early:
|
159
|
+
self.scenes[index].do_on_enter_early()
|
160
|
+
target_scene.on_enter()
|
161
|
+
|
162
|
+
|
163
|
+
|
164
|
+
def cycle_debug_mode(self):
|
165
|
+
current_index = bf.ResourceManager().get_sharedVar("debug_mode").value
|
166
|
+
next_index = (current_index + 1) % len(bf.debugMode)
|
167
|
+
bf.ResourceManager().set_sharedVar("debug_mode", bf.debugMode(next_index))
|
168
|
+
return bf.debugMode(next_index)
|
169
|
+
|
170
|
+
def set_debug_mode(self,debugMode : bf.debugMode):
|
171
|
+
bf.ResourceManager().set_sharedVar("debug_mode", debugMode)
|
172
|
+
|
173
|
+
def process_event(self, event: pygame.Event):
|
174
|
+
|
175
|
+
if event.type in self.shared_events:
|
176
|
+
[s.process_event(event) for s in self.scenes]
|
177
|
+
else:
|
178
|
+
self.scenes[0].process_event(event)
|
179
|
+
|
180
|
+
def update(self, dt: float) -> None:
|
181
|
+
for scene in self.active_scenes:
|
182
|
+
scene.update(dt)
|
183
|
+
if self.current_transition and self.current_transition[1].is_over:
|
184
|
+
self.set_scene(self.current_transition[0],self.current_transition[2],True)
|
185
|
+
self.current_transition = None
|
186
|
+
self.do_update(dt)
|
187
|
+
|
188
|
+
def do_update(self, dt: float):
|
189
|
+
pass
|
190
|
+
|
191
|
+
def draw(self, surface:pygame.Surface) -> None:
|
192
|
+
for scene in self.visible_scenes:
|
193
|
+
scene.draw(surface)
|
194
|
+
if self.current_transition is not None:
|
195
|
+
self.current_transition[1].set_source(surface)
|
196
|
+
tmp = surface.copy()
|
197
|
+
self.get_scene(self.current_transition[0]).draw(tmp)
|
198
|
+
self.current_transition[1].set_dest(tmp)
|
199
|
+
self.current_transition[1].draw(surface)
|
200
|
+
|
batFramework/scrollingSprite.py
CHANGED
@@ -1,115 +1,115 @@
|
|
1
|
-
from typing import Self, Iterator
|
2
|
-
from pygame.math import Vector2
|
3
|
-
import batFramework as bf
|
4
|
-
import pygame
|
5
|
-
|
6
|
-
|
7
|
-
class ScrollingSprite(bf.Sprite):
|
8
|
-
def __init__(
|
9
|
-
self,
|
10
|
-
data: pygame.Surface | str,
|
11
|
-
size: None | tuple[int, int] = None,
|
12
|
-
convert_alpha: bool = True,
|
13
|
-
):
|
14
|
-
self.scroll_value = Vector2(0, 0)
|
15
|
-
self.auto_scroll = Vector2(0, 0)
|
16
|
-
|
17
|
-
# Use integer values for the starting points, converted from floating point scroll values
|
18
|
-
|
19
|
-
super().__init__(size, data, convert_alpha)
|
20
|
-
if self.original_surface:
|
21
|
-
self.original_width, self.original_height = self.original_surface.get_size()
|
22
|
-
|
23
|
-
|
24
|
-
def get_debug_outlines(self):
|
25
|
-
yield from super().get_debug_outlines()
|
26
|
-
for r in self._get_mosaic_rect_list():
|
27
|
-
yield r.move(*self.rect.topleft)
|
28
|
-
|
29
|
-
|
30
|
-
def set_autoscroll(self, x: float, y: float) -> Self:
|
31
|
-
self.auto_scroll.update(x, y)
|
32
|
-
return self
|
33
|
-
|
34
|
-
def set_scroll(self, x: float = None, y: float = None) -> Self:
|
35
|
-
self.scroll_value.update(
|
36
|
-
x if x else self.scroll_value.x, y if y else self.scroll_value.y
|
37
|
-
)
|
38
|
-
return self
|
39
|
-
|
40
|
-
def scroll(self, x: float, y: float) -> Self:
|
41
|
-
self.scroll_value += x, y
|
42
|
-
return self
|
43
|
-
|
44
|
-
def update(self, dt: float) -> None:
|
45
|
-
if self.auto_scroll:
|
46
|
-
self.scroll(*self.auto_scroll * dt)
|
47
|
-
original_width, original_height = self.original_surface.get_size()
|
48
|
-
|
49
|
-
# Use integer values for the starting points, converted from floating point scroll values
|
50
|
-
|
51
|
-
if self.scroll_value.x > self.original_width:
|
52
|
-
self.scroll_value.x -= self.original_width
|
53
|
-
if self.scroll_value.y > self.original_height:
|
54
|
-
self.scroll_value.y -= self.original_height
|
55
|
-
|
56
|
-
super().update(dt)
|
57
|
-
|
58
|
-
def set_size(self, size: tuple[int | None, int | None]) -> Self:
|
59
|
-
size = list(size)
|
60
|
-
if size[0] is None:
|
61
|
-
size[0] = self.rect.w
|
62
|
-
if size[1] is None:
|
63
|
-
size[1] = self.rect.h
|
64
|
-
|
65
|
-
self.surface = pygame.Surface(size).convert_alpha()
|
66
|
-
self.rect = self.surface.get_frect(topleft=self.rect.topleft)
|
67
|
-
return self
|
68
|
-
|
69
|
-
def _get_mosaic_rect_list(self,camera:bf.Camera=None) -> Iterator[pygame.Rect]:
|
70
|
-
# Use integer values for the starting points, converted from floating point scroll values
|
71
|
-
start_x = int(self.scroll_value.x % self.original_width)
|
72
|
-
start_y = int(self.scroll_value.y % self.original_height)
|
73
|
-
|
74
|
-
# Adjust start_x and start_y to begin tiling off-screen to the top-left, covering all visible area
|
75
|
-
if start_x != 0:
|
76
|
-
start_x -= self.original_width
|
77
|
-
if start_y != 0:
|
78
|
-
start_y -= self.original_height
|
79
|
-
|
80
|
-
# Set the region in which to tile
|
81
|
-
end_x = self.rect.w
|
82
|
-
end_y = self.rect.h
|
83
|
-
|
84
|
-
# Starting y_position for the inner loop
|
85
|
-
y_position = start_y
|
86
|
-
|
87
|
-
# if self.rect.w-1 < self.scroll_value.x < self.rect.w+1 : print(self.scroll_value.x,int(self.scroll_value.x % self.rect.w),start_x,self.rect.w,original_width)
|
88
|
-
# Generate all necessary rectangles
|
89
|
-
x = start_x
|
90
|
-
while x < end_x:
|
91
|
-
y = y_position
|
92
|
-
while y < end_y:
|
93
|
-
r = pygame.Rect(x, y, self.original_width, self.original_height)
|
94
|
-
|
95
|
-
if camera and camera.rect.colliderect((x+camera.rect.x,y+camera.rect.y,self.original_width,self.original_height)):
|
96
|
-
yield r
|
97
|
-
else:
|
98
|
-
yield r
|
99
|
-
y += self.original_height
|
100
|
-
x += self.original_width
|
101
|
-
return self
|
102
|
-
|
103
|
-
def draw(self, camera: bf.Camera) -> None:
|
104
|
-
if not (
|
105
|
-
self.visible
|
106
|
-
and (self.surface is not None)
|
107
|
-
and camera.rect.colliderect(self.rect)
|
108
|
-
):
|
109
|
-
return
|
110
|
-
# self.surface.fill((0, 0, 0, 0))
|
111
|
-
camera.surface.fblits(
|
112
|
-
[(self.original_surface, r.move(self.rect.x-camera.rect.x,self.rect.y-camera.rect.y)) for r in self._get_mosaic_rect_list(camera)]
|
113
|
-
)
|
114
|
-
# camera.surface.blit(self.surface, camera.world_to_screen(self.rect))
|
115
|
-
return
|
1
|
+
from typing import Self, Iterator
|
2
|
+
from pygame.math import Vector2
|
3
|
+
import batFramework as bf
|
4
|
+
import pygame
|
5
|
+
|
6
|
+
|
7
|
+
class ScrollingSprite(bf.Sprite):
|
8
|
+
def __init__(
|
9
|
+
self,
|
10
|
+
data: pygame.Surface | str,
|
11
|
+
size: None | tuple[int, int] = None,
|
12
|
+
convert_alpha: bool = True,
|
13
|
+
):
|
14
|
+
self.scroll_value = Vector2(0, 0)
|
15
|
+
self.auto_scroll = Vector2(0, 0)
|
16
|
+
|
17
|
+
# Use integer values for the starting points, converted from floating point scroll values
|
18
|
+
|
19
|
+
super().__init__(size, data, convert_alpha)
|
20
|
+
if self.original_surface:
|
21
|
+
self.original_width, self.original_height = self.original_surface.get_size()
|
22
|
+
|
23
|
+
|
24
|
+
def get_debug_outlines(self):
|
25
|
+
yield from super().get_debug_outlines()
|
26
|
+
for r in self._get_mosaic_rect_list():
|
27
|
+
yield r.move(*self.rect.topleft)
|
28
|
+
|
29
|
+
|
30
|
+
def set_autoscroll(self, x: float, y: float) -> Self:
|
31
|
+
self.auto_scroll.update(x, y)
|
32
|
+
return self
|
33
|
+
|
34
|
+
def set_scroll(self, x: float = None, y: float = None) -> Self:
|
35
|
+
self.scroll_value.update(
|
36
|
+
x if x else self.scroll_value.x, y if y else self.scroll_value.y
|
37
|
+
)
|
38
|
+
return self
|
39
|
+
|
40
|
+
def scroll(self, x: float, y: float) -> Self:
|
41
|
+
self.scroll_value += x, y
|
42
|
+
return self
|
43
|
+
|
44
|
+
def update(self, dt: float) -> None:
|
45
|
+
if self.auto_scroll:
|
46
|
+
self.scroll(*self.auto_scroll * dt)
|
47
|
+
original_width, original_height = self.original_surface.get_size()
|
48
|
+
|
49
|
+
# Use integer values for the starting points, converted from floating point scroll values
|
50
|
+
|
51
|
+
if self.scroll_value.x > self.original_width:
|
52
|
+
self.scroll_value.x -= self.original_width
|
53
|
+
if self.scroll_value.y > self.original_height:
|
54
|
+
self.scroll_value.y -= self.original_height
|
55
|
+
|
56
|
+
super().update(dt)
|
57
|
+
|
58
|
+
def set_size(self, size: tuple[int | None, int | None]) -> Self:
|
59
|
+
size = list(size)
|
60
|
+
if size[0] is None:
|
61
|
+
size[0] = self.rect.w
|
62
|
+
if size[1] is None:
|
63
|
+
size[1] = self.rect.h
|
64
|
+
|
65
|
+
self.surface = pygame.Surface(size).convert_alpha()
|
66
|
+
self.rect = self.surface.get_frect(topleft=self.rect.topleft)
|
67
|
+
return self
|
68
|
+
|
69
|
+
def _get_mosaic_rect_list(self,camera:bf.Camera=None) -> Iterator[pygame.Rect]:
|
70
|
+
# Use integer values for the starting points, converted from floating point scroll values
|
71
|
+
start_x = int(self.scroll_value.x % self.original_width)
|
72
|
+
start_y = int(self.scroll_value.y % self.original_height)
|
73
|
+
|
74
|
+
# Adjust start_x and start_y to begin tiling off-screen to the top-left, covering all visible area
|
75
|
+
if start_x != 0:
|
76
|
+
start_x -= self.original_width
|
77
|
+
if start_y != 0:
|
78
|
+
start_y -= self.original_height
|
79
|
+
|
80
|
+
# Set the region in which to tile
|
81
|
+
end_x = self.rect.w
|
82
|
+
end_y = self.rect.h
|
83
|
+
|
84
|
+
# Starting y_position for the inner loop
|
85
|
+
y_position = start_y
|
86
|
+
|
87
|
+
# if self.rect.w-1 < self.scroll_value.x < self.rect.w+1 : print(self.scroll_value.x,int(self.scroll_value.x % self.rect.w),start_x,self.rect.w,original_width)
|
88
|
+
# Generate all necessary rectangles
|
89
|
+
x = start_x
|
90
|
+
while x < end_x:
|
91
|
+
y = y_position
|
92
|
+
while y < end_y:
|
93
|
+
r = pygame.Rect(x, y, self.original_width, self.original_height)
|
94
|
+
|
95
|
+
if camera and camera.rect.colliderect((x+camera.rect.x,y+camera.rect.y,self.original_width,self.original_height)):
|
96
|
+
yield r
|
97
|
+
else:
|
98
|
+
yield r
|
99
|
+
y += self.original_height
|
100
|
+
x += self.original_width
|
101
|
+
return self
|
102
|
+
|
103
|
+
def draw(self, camera: bf.Camera) -> None:
|
104
|
+
if not (
|
105
|
+
self.visible
|
106
|
+
and (self.surface is not None)
|
107
|
+
and camera.rect.colliderect(self.rect)
|
108
|
+
):
|
109
|
+
return
|
110
|
+
# self.surface.fill((0, 0, 0, 0))
|
111
|
+
camera.surface.fblits(
|
112
|
+
[(self.original_surface, r.move(self.rect.x-camera.rect.x,self.rect.y-camera.rect.y)) for r in self._get_mosaic_rect_list(camera)]
|
113
|
+
)
|
114
|
+
# camera.surface.blit(self.surface, camera.world_to_screen(self.rect))
|
115
|
+
return
|