mini-arcade-core 0.10.0__py3-none-any.whl → 1.0.0__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.
- mini_arcade_core/__init__.py +43 -60
- mini_arcade_core/backend/__init__.py +0 -5
- mini_arcade_core/backend/backend.py +9 -0
- mini_arcade_core/backend/events.py +1 -1
- mini_arcade_core/{keymaps/sdl.py → backend/sdl_map.py} +1 -1
- mini_arcade_core/engine/__init__.py +0 -0
- mini_arcade_core/engine/commands.py +169 -0
- mini_arcade_core/engine/game.py +354 -0
- mini_arcade_core/engine/render/__init__.py +0 -0
- mini_arcade_core/engine/render/packet.py +56 -0
- mini_arcade_core/engine/render/pipeline.py +39 -0
- mini_arcade_core/managers/__init__.py +0 -22
- mini_arcade_core/managers/cheats.py +71 -240
- mini_arcade_core/managers/inputs.py +5 -1
- mini_arcade_core/runtime/__init__.py +0 -0
- mini_arcade_core/runtime/audio/__init__.py +0 -0
- mini_arcade_core/runtime/audio/audio_adapter.py +13 -0
- mini_arcade_core/runtime/audio/audio_port.py +17 -0
- mini_arcade_core/runtime/capture/__init__.py +0 -0
- mini_arcade_core/runtime/capture/capture_adapter.py +143 -0
- mini_arcade_core/runtime/capture/capture_port.py +32 -0
- mini_arcade_core/runtime/context.py +53 -0
- mini_arcade_core/runtime/file/__init__.py +0 -0
- mini_arcade_core/runtime/file/file_adapter.py +20 -0
- mini_arcade_core/runtime/file/file_port.py +31 -0
- mini_arcade_core/runtime/input/__init__.py +0 -0
- mini_arcade_core/runtime/input/input_adapter.py +49 -0
- mini_arcade_core/runtime/input/input_port.py +31 -0
- mini_arcade_core/runtime/input_frame.py +71 -0
- mini_arcade_core/runtime/scene/__init__.py +0 -0
- mini_arcade_core/runtime/scene/scene_adapter.py +97 -0
- mini_arcade_core/runtime/scene/scene_port.py +149 -0
- mini_arcade_core/runtime/services.py +35 -0
- mini_arcade_core/runtime/window/__init__.py +0 -0
- mini_arcade_core/runtime/window/window_adapter.py +26 -0
- mini_arcade_core/runtime/window/window_port.py +47 -0
- mini_arcade_core/scenes/__init__.py +0 -22
- mini_arcade_core/scenes/autoreg.py +1 -1
- mini_arcade_core/scenes/registry.py +21 -19
- mini_arcade_core/scenes/sim_scene.py +41 -0
- mini_arcade_core/scenes/systems/__init__.py +0 -0
- mini_arcade_core/scenes/systems/base_system.py +40 -0
- mini_arcade_core/scenes/systems/system_pipeline.py +57 -0
- mini_arcade_core/sim/__init__.py +0 -0
- mini_arcade_core/sim/protocols.py +41 -0
- mini_arcade_core/sim/runner.py +222 -0
- mini_arcade_core/spaces/__init__.py +0 -12
- mini_arcade_core/spaces/d2/__init__.py +0 -30
- mini_arcade_core/spaces/d2/collision2d.py +25 -28
- mini_arcade_core/spaces/d2/geometry2d.py +18 -0
- mini_arcade_core/spaces/d2/kinematics2d.py +2 -8
- mini_arcade_core/spaces/d2/physics2d.py +9 -0
- mini_arcade_core/ui/__init__.py +0 -26
- mini_arcade_core/ui/menu.py +265 -84
- mini_arcade_core/utils/__init__.py +10 -0
- mini_arcade_core/utils/deprecated_decorator.py +45 -0
- mini_arcade_core/utils/logging.py +174 -0
- {mini_arcade_core-0.10.0.dist-info → mini_arcade_core-1.0.0.dist-info}/METADATA +1 -1
- mini_arcade_core-1.0.0.dist-info/RECORD +65 -0
- {mini_arcade_core-0.10.0.dist-info → mini_arcade_core-1.0.0.dist-info}/WHEEL +1 -1
- mini_arcade_core/commands.py +0 -84
- mini_arcade_core/entity.py +0 -72
- mini_arcade_core/game.py +0 -287
- mini_arcade_core/keymaps/__init__.py +0 -15
- mini_arcade_core/managers/base.py +0 -132
- mini_arcade_core/managers/entities.py +0 -38
- mini_arcade_core/managers/overlays.py +0 -53
- mini_arcade_core/managers/system.py +0 -26
- mini_arcade_core/scenes/model.py +0 -34
- mini_arcade_core/scenes/runtime.py +0 -29
- mini_arcade_core/scenes/scene.py +0 -109
- mini_arcade_core/scenes/system.py +0 -69
- mini_arcade_core/ui/overlays.py +0 -41
- mini_arcade_core-0.10.0.dist-info/RECORD +0 -40
- /mini_arcade_core/{keymaps → backend}/keys.py +0 -0
- {mini_arcade_core-0.10.0.dist-info → mini_arcade_core-1.0.0.dist-info}/licenses/LICENSE +0 -0
mini_arcade_core/game.py
DELETED
|
@@ -1,287 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Game core module defining the Game class and configuration.
|
|
3
|
-
"""
|
|
4
|
-
|
|
5
|
-
from __future__ import annotations
|
|
6
|
-
|
|
7
|
-
import os
|
|
8
|
-
from dataclasses import dataclass
|
|
9
|
-
from datetime import datetime
|
|
10
|
-
from pathlib import Path
|
|
11
|
-
from time import perf_counter, sleep
|
|
12
|
-
from typing import TYPE_CHECKING, Literal, Union
|
|
13
|
-
|
|
14
|
-
from PIL import Image # type: ignore[import]
|
|
15
|
-
|
|
16
|
-
from mini_arcade_core.backend import Backend
|
|
17
|
-
from mini_arcade_core.scenes.registry import SceneRegistry
|
|
18
|
-
|
|
19
|
-
if TYPE_CHECKING: # avoid runtime circular import
|
|
20
|
-
from mini_arcade_core.scenes import Scene
|
|
21
|
-
|
|
22
|
-
SceneOrId = Union["Scene", str]
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
@dataclass
|
|
26
|
-
class GameConfig:
|
|
27
|
-
"""
|
|
28
|
-
Configuration options for the Game.
|
|
29
|
-
|
|
30
|
-
:ivar width: Width of the game window in pixels.
|
|
31
|
-
:ivar height: Height of the game window in pixels.
|
|
32
|
-
:ivar title: Title of the game window.
|
|
33
|
-
:ivar fps: Target frames per second.
|
|
34
|
-
:ivar background_color: RGB background color.
|
|
35
|
-
:ivar backend: Optional Backend instance to use for rendering and input.
|
|
36
|
-
"""
|
|
37
|
-
|
|
38
|
-
width: int = 800
|
|
39
|
-
height: int = 600
|
|
40
|
-
title: str = "Mini Arcade Game"
|
|
41
|
-
fps: int = 60
|
|
42
|
-
background_color: tuple[int, int, int] = (0, 0, 0)
|
|
43
|
-
backend: Backend | None = None
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
Difficulty = Literal["easy", "normal", "hard", "insane"]
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
@dataclass
|
|
50
|
-
class GameSettings:
|
|
51
|
-
"""
|
|
52
|
-
Game settings that can be modified during gameplay.
|
|
53
|
-
|
|
54
|
-
:ivar difficulty: Current game difficulty level.
|
|
55
|
-
"""
|
|
56
|
-
|
|
57
|
-
difficulty: Difficulty = "normal"
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
@dataclass
|
|
61
|
-
class _StackEntry:
|
|
62
|
-
scene: "Scene"
|
|
63
|
-
as_overlay: bool = False
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
class Game:
|
|
67
|
-
"""Core game object responsible for managing the main loop and active scene."""
|
|
68
|
-
|
|
69
|
-
def __init__(
|
|
70
|
-
self, config: GameConfig, registry: SceneRegistry | None = None
|
|
71
|
-
):
|
|
72
|
-
"""
|
|
73
|
-
:param config: Game configuration options.
|
|
74
|
-
:type config: GameConfig
|
|
75
|
-
|
|
76
|
-
:param registry: Optional SceneRegistry for scene management.
|
|
77
|
-
:type registry: SceneRegistry | None
|
|
78
|
-
|
|
79
|
-
:raises ValueError: If the provided config does not have a valid Backend.
|
|
80
|
-
"""
|
|
81
|
-
self.config = config
|
|
82
|
-
self._current_scene: Scene | None = None
|
|
83
|
-
self._running: bool = False
|
|
84
|
-
|
|
85
|
-
if config.backend is None:
|
|
86
|
-
raise ValueError(
|
|
87
|
-
"GameConfig.backend must be set to a Backend instance"
|
|
88
|
-
)
|
|
89
|
-
self.backend: Backend = config.backend
|
|
90
|
-
self.registry = registry or SceneRegistry(_factories={})
|
|
91
|
-
self._scene_stack: list[_StackEntry] = []
|
|
92
|
-
self.settings = GameSettings()
|
|
93
|
-
|
|
94
|
-
def current_scene(self) -> "Scene | None":
|
|
95
|
-
"""
|
|
96
|
-
Get the currently active scene.
|
|
97
|
-
|
|
98
|
-
:return: The active Scene instance, or None if no scene is active.
|
|
99
|
-
:rtype: Scene | None
|
|
100
|
-
"""
|
|
101
|
-
return self._scene_stack[-1].scene if self._scene_stack else None
|
|
102
|
-
|
|
103
|
-
def change_scene(self, scene: SceneOrId):
|
|
104
|
-
"""
|
|
105
|
-
Swap the active scene. Concrete implementations should call
|
|
106
|
-
``on_exit``/``on_enter`` appropriately.
|
|
107
|
-
|
|
108
|
-
:param scene: The new scene to activate.
|
|
109
|
-
:type scene: SceneOrId
|
|
110
|
-
"""
|
|
111
|
-
scene = self._resolve_scene(scene)
|
|
112
|
-
|
|
113
|
-
while self._scene_stack:
|
|
114
|
-
entry = self._scene_stack.pop()
|
|
115
|
-
entry.scene.on_exit()
|
|
116
|
-
|
|
117
|
-
self._scene_stack.append(_StackEntry(scene=scene, as_overlay=False))
|
|
118
|
-
scene.on_enter()
|
|
119
|
-
|
|
120
|
-
def push_scene(self, scene: SceneOrId, as_overlay: bool = False):
|
|
121
|
-
"""
|
|
122
|
-
Push a scene on top of the current one.
|
|
123
|
-
If as_overlay=True, underlying scene(s) may still be drawn but never updated.
|
|
124
|
-
|
|
125
|
-
:param scene: The scene to push onto the stack.
|
|
126
|
-
:type scene: SceneOrId
|
|
127
|
-
|
|
128
|
-
:param as_overlay: Whether to treat the scene as an overlay.
|
|
129
|
-
:type as_overlay: bool
|
|
130
|
-
"""
|
|
131
|
-
scene = self._resolve_scene(scene)
|
|
132
|
-
|
|
133
|
-
top = self.current_scene()
|
|
134
|
-
if top is not None:
|
|
135
|
-
top.on_pause()
|
|
136
|
-
|
|
137
|
-
self._scene_stack.append(
|
|
138
|
-
_StackEntry(scene=scene, as_overlay=as_overlay)
|
|
139
|
-
)
|
|
140
|
-
scene.on_enter()
|
|
141
|
-
|
|
142
|
-
def pop_scene(self) -> "Scene | None":
|
|
143
|
-
"""
|
|
144
|
-
Pop the top scene. If stack becomes empty, quit.
|
|
145
|
-
|
|
146
|
-
:return: The popped Scene instance, or None if the stack is now empty.
|
|
147
|
-
:rtype: Scene | None
|
|
148
|
-
"""
|
|
149
|
-
if not self._scene_stack:
|
|
150
|
-
return None
|
|
151
|
-
|
|
152
|
-
popped = self._scene_stack.pop()
|
|
153
|
-
popped.scene.on_exit()
|
|
154
|
-
|
|
155
|
-
top = self.current_scene()
|
|
156
|
-
if top is None:
|
|
157
|
-
self.quit()
|
|
158
|
-
return popped.scene
|
|
159
|
-
|
|
160
|
-
top.on_resume()
|
|
161
|
-
return popped.scene
|
|
162
|
-
|
|
163
|
-
def _visible_stack(self) -> list["Scene"]:
|
|
164
|
-
"""
|
|
165
|
-
Return the list of scenes that should be drawn (base + overlays).
|
|
166
|
-
We draw from the top-most non-overlay scene upward.
|
|
167
|
-
"""
|
|
168
|
-
if not self._scene_stack:
|
|
169
|
-
return []
|
|
170
|
-
|
|
171
|
-
# find top-most base scene (as_overlay=False)
|
|
172
|
-
base_idx = 0
|
|
173
|
-
for i in range(len(self._scene_stack) - 1, -1, -1):
|
|
174
|
-
if not self._scene_stack[i].as_overlay:
|
|
175
|
-
base_idx = i
|
|
176
|
-
break
|
|
177
|
-
|
|
178
|
-
return [e.scene for e in self._scene_stack[base_idx:]]
|
|
179
|
-
|
|
180
|
-
def quit(self):
|
|
181
|
-
"""Request that the main loop stops."""
|
|
182
|
-
self._running = False
|
|
183
|
-
|
|
184
|
-
def run(self, initial_scene: SceneOrId):
|
|
185
|
-
"""
|
|
186
|
-
Run the main loop starting with the given scene.
|
|
187
|
-
|
|
188
|
-
This is intentionally left abstract so you can plug pygame, pyglet,
|
|
189
|
-
or another backend.
|
|
190
|
-
|
|
191
|
-
:param initial_scene: The scene to start the game with.
|
|
192
|
-
:type initial_scene: SceneOrId
|
|
193
|
-
"""
|
|
194
|
-
backend = self.backend
|
|
195
|
-
backend.init(self.config.width, self.config.height, self.config.title)
|
|
196
|
-
|
|
197
|
-
br, bg, bb = self.config.background_color
|
|
198
|
-
backend.set_clear_color(br, bg, bb)
|
|
199
|
-
|
|
200
|
-
self.change_scene(initial_scene)
|
|
201
|
-
|
|
202
|
-
self._running = True
|
|
203
|
-
target_dt = 1.0 / self.config.fps if self.config.fps > 0 else 0.0
|
|
204
|
-
last_time = perf_counter()
|
|
205
|
-
|
|
206
|
-
while self._running:
|
|
207
|
-
now = perf_counter()
|
|
208
|
-
dt = now - last_time
|
|
209
|
-
last_time = now
|
|
210
|
-
|
|
211
|
-
top = self.current_scene()
|
|
212
|
-
if top is None:
|
|
213
|
-
break
|
|
214
|
-
|
|
215
|
-
for ev in backend.poll_events():
|
|
216
|
-
top.handle_event(ev)
|
|
217
|
-
|
|
218
|
-
top.update(dt)
|
|
219
|
-
|
|
220
|
-
backend.begin_frame()
|
|
221
|
-
for scene in self._visible_stack():
|
|
222
|
-
scene.draw(backend)
|
|
223
|
-
backend.end_frame()
|
|
224
|
-
|
|
225
|
-
if target_dt > 0 and dt < target_dt:
|
|
226
|
-
sleep(target_dt - dt)
|
|
227
|
-
|
|
228
|
-
# exit remaining scenes
|
|
229
|
-
while self._scene_stack:
|
|
230
|
-
entry = self._scene_stack.pop()
|
|
231
|
-
entry.scene.on_exit()
|
|
232
|
-
|
|
233
|
-
@staticmethod
|
|
234
|
-
def _convert_bmp_to_image(bmp_path: str, out_path: str) -> bool:
|
|
235
|
-
"""
|
|
236
|
-
Convert a BMP file to another image format using Pillow.
|
|
237
|
-
|
|
238
|
-
:param bmp_path: Path to the input BMP file.
|
|
239
|
-
:type bmp_path: str
|
|
240
|
-
|
|
241
|
-
:param out_path: Path to the output image file.
|
|
242
|
-
:type out_path: str
|
|
243
|
-
|
|
244
|
-
:return: True if conversion was successful, False otherwise.
|
|
245
|
-
:rtype: bool
|
|
246
|
-
"""
|
|
247
|
-
try:
|
|
248
|
-
img = Image.open(bmp_path)
|
|
249
|
-
img.save(out_path) # Pillow chooses format from extension
|
|
250
|
-
return True
|
|
251
|
-
# Justification: Pillow can raise various exceptions on failure
|
|
252
|
-
# pylint: disable=broad-exception-caught
|
|
253
|
-
except Exception:
|
|
254
|
-
return False
|
|
255
|
-
# pylint: enable=broad-exception-caught
|
|
256
|
-
|
|
257
|
-
def screenshot(
|
|
258
|
-
self, label: str | None = None, directory: str = "screenshots"
|
|
259
|
-
) -> str | None:
|
|
260
|
-
"""
|
|
261
|
-
Ask backend to save a screenshot. Returns the file path or None.
|
|
262
|
-
|
|
263
|
-
:param label: Optional label to include in the filename.
|
|
264
|
-
:type label: str | None
|
|
265
|
-
|
|
266
|
-
:param directory: Directory to save screenshots in.
|
|
267
|
-
:type directory: str
|
|
268
|
-
|
|
269
|
-
:return: The file path of the saved screenshot, or None on failure.
|
|
270
|
-
:rtype: str | None
|
|
271
|
-
"""
|
|
272
|
-
os.makedirs(directory, exist_ok=True)
|
|
273
|
-
stamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
|
274
|
-
label = label or "shot"
|
|
275
|
-
filename = f"{stamp}_{label}"
|
|
276
|
-
bmp_path = os.path.join(directory, f"{filename}.bmp")
|
|
277
|
-
|
|
278
|
-
if self.backend.capture_frame(bmp_path):
|
|
279
|
-
out_path = Path(directory) / f"{filename}.png"
|
|
280
|
-
self._convert_bmp_to_image(bmp_path, str(out_path))
|
|
281
|
-
return str(out_path)
|
|
282
|
-
return None
|
|
283
|
-
|
|
284
|
-
def _resolve_scene(self, scene: SceneOrId) -> "Scene":
|
|
285
|
-
if isinstance(scene, str):
|
|
286
|
-
return self.registry.create(scene, self)
|
|
287
|
-
return scene
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Keymaps for Mini Arcade Core.
|
|
3
|
-
Includes key definitions and default key mappings.
|
|
4
|
-
"""
|
|
5
|
-
|
|
6
|
-
from __future__ import annotations
|
|
7
|
-
|
|
8
|
-
from .keys import Key, keymap
|
|
9
|
-
from .sdl import SDL_KEYCODE_TO_KEY
|
|
10
|
-
|
|
11
|
-
__all__ = [
|
|
12
|
-
"Key",
|
|
13
|
-
"keymap",
|
|
14
|
-
"SDL_KEYCODE_TO_KEY",
|
|
15
|
-
]
|
|
@@ -1,132 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Base manager classes for handling collections of items.
|
|
3
|
-
"""
|
|
4
|
-
|
|
5
|
-
from __future__ import annotations
|
|
6
|
-
|
|
7
|
-
from dataclasses import dataclass, field
|
|
8
|
-
from typing import Callable, Generic, Iterable, List, Protocol, TypeVar
|
|
9
|
-
|
|
10
|
-
from mini_arcade_core.backend.backend import Backend
|
|
11
|
-
|
|
12
|
-
# ---- shared types ----
|
|
13
|
-
T = TypeVar("T")
|
|
14
|
-
OverlayFunc = Callable[[Backend], None]
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
class Overlay(Protocol):
|
|
18
|
-
"""
|
|
19
|
-
Defines an overlay function.
|
|
20
|
-
|
|
21
|
-
:ivar enabled (bool): Whether the overlay is enabled.
|
|
22
|
-
"""
|
|
23
|
-
|
|
24
|
-
enabled: bool
|
|
25
|
-
|
|
26
|
-
def update(self, dt: float):
|
|
27
|
-
"""
|
|
28
|
-
Update the overlay state.
|
|
29
|
-
|
|
30
|
-
:param dt: Time delta in seconds.
|
|
31
|
-
:type dt: float
|
|
32
|
-
"""
|
|
33
|
-
|
|
34
|
-
def draw(self, surface: "Backend"):
|
|
35
|
-
"""
|
|
36
|
-
Draw the overlay on the given surface.
|
|
37
|
-
|
|
38
|
-
:param surface: The backend surface to draw on.
|
|
39
|
-
:type surface: Backend
|
|
40
|
-
"""
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
class Drawable(Protocol):
|
|
44
|
-
"""Defines a drawable entity."""
|
|
45
|
-
|
|
46
|
-
def draw(self, surface: Backend):
|
|
47
|
-
"""
|
|
48
|
-
Draw the entity on the given surface.
|
|
49
|
-
|
|
50
|
-
:param surface: The backend surface to draw on.
|
|
51
|
-
:type surface: Backend
|
|
52
|
-
"""
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
class Updatable(Protocol):
|
|
56
|
-
"""Defines an updatable entity."""
|
|
57
|
-
|
|
58
|
-
def update(self, dt: float):
|
|
59
|
-
"""
|
|
60
|
-
Update the entity state.
|
|
61
|
-
|
|
62
|
-
:param dt: Time delta in seconds.
|
|
63
|
-
:type dt: float
|
|
64
|
-
"""
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
class EntityLike(Drawable, Updatable, Protocol):
|
|
68
|
-
"""Defines a game entity."""
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
@dataclass
|
|
72
|
-
class ListManager(Generic[T]):
|
|
73
|
-
"""
|
|
74
|
-
Generic manager for a list of items.
|
|
75
|
-
|
|
76
|
-
:ivar items (List[T]): List of managed items.
|
|
77
|
-
"""
|
|
78
|
-
|
|
79
|
-
items: List[T] = field(default_factory=list)
|
|
80
|
-
|
|
81
|
-
def add(self, *items: T):
|
|
82
|
-
"""
|
|
83
|
-
Add one or more items to the manager.
|
|
84
|
-
|
|
85
|
-
:param items: One or more items to add.
|
|
86
|
-
:type items: T
|
|
87
|
-
"""
|
|
88
|
-
self.items.extend(items)
|
|
89
|
-
|
|
90
|
-
def add_many(self, items: Iterable[T]):
|
|
91
|
-
"""
|
|
92
|
-
Add multiple items to the manager.
|
|
93
|
-
|
|
94
|
-
:param items: An iterable of items to add.
|
|
95
|
-
:type items: Iterable[T]
|
|
96
|
-
"""
|
|
97
|
-
self.items.extend(items)
|
|
98
|
-
|
|
99
|
-
def remove(self, item: T):
|
|
100
|
-
"""
|
|
101
|
-
Remove a single item from the manager, if present.
|
|
102
|
-
|
|
103
|
-
:param item: The item to remove.
|
|
104
|
-
:type item: T
|
|
105
|
-
"""
|
|
106
|
-
if item in self.items:
|
|
107
|
-
self.items.remove(item)
|
|
108
|
-
|
|
109
|
-
def get(self, item: T) -> T | None:
|
|
110
|
-
"""
|
|
111
|
-
Get an item from the manager.
|
|
112
|
-
|
|
113
|
-
:param item: The item to get.
|
|
114
|
-
:type item: T
|
|
115
|
-
|
|
116
|
-
:return: The item if found, else None.
|
|
117
|
-
:rtype: T | None
|
|
118
|
-
"""
|
|
119
|
-
for it in self.items:
|
|
120
|
-
if it == item:
|
|
121
|
-
return it
|
|
122
|
-
return None
|
|
123
|
-
|
|
124
|
-
def clear(self):
|
|
125
|
-
"""Clear all items from the manager."""
|
|
126
|
-
self.items.clear()
|
|
127
|
-
|
|
128
|
-
def __iter__(self):
|
|
129
|
-
return iter(self.items)
|
|
130
|
-
|
|
131
|
-
def __len__(self) -> int:
|
|
132
|
-
return len(self.items)
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Entity manager for handling a collection of entities.
|
|
3
|
-
"""
|
|
4
|
-
|
|
5
|
-
from __future__ import annotations
|
|
6
|
-
|
|
7
|
-
from dataclasses import dataclass
|
|
8
|
-
|
|
9
|
-
from mini_arcade_core.backend import Backend
|
|
10
|
-
|
|
11
|
-
from .base import EntityLike, ListManager
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
@dataclass
|
|
15
|
-
class EntityManager(ListManager[EntityLike]):
|
|
16
|
-
"""
|
|
17
|
-
Manages a collection of entities within a scene.
|
|
18
|
-
"""
|
|
19
|
-
|
|
20
|
-
def update(self, dt: float):
|
|
21
|
-
"""
|
|
22
|
-
Update all managed entities.
|
|
23
|
-
|
|
24
|
-
:param dt: Time delta in seconds.
|
|
25
|
-
:type dt: float
|
|
26
|
-
"""
|
|
27
|
-
for ent in list(self.items):
|
|
28
|
-
ent.update(dt)
|
|
29
|
-
|
|
30
|
-
def draw(self, surface: "Backend"):
|
|
31
|
-
"""
|
|
32
|
-
Draw all managed entities.
|
|
33
|
-
|
|
34
|
-
:param surface: The backend surface to draw on.
|
|
35
|
-
:type surface: Backend
|
|
36
|
-
"""
|
|
37
|
-
for ent in list(self.items):
|
|
38
|
-
ent.draw(surface)
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Overlay manager for handling a collection of overlays.
|
|
3
|
-
"""
|
|
4
|
-
|
|
5
|
-
from __future__ import annotations
|
|
6
|
-
|
|
7
|
-
from dataclasses import dataclass
|
|
8
|
-
from typing import Union
|
|
9
|
-
|
|
10
|
-
from mini_arcade_core.backend import Backend
|
|
11
|
-
from mini_arcade_core.managers.base import ListManager, Overlay, OverlayFunc
|
|
12
|
-
|
|
13
|
-
OverlayType = Union[Overlay, OverlayFunc]
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
@dataclass
|
|
17
|
-
class OverlayManager(ListManager[OverlayType]):
|
|
18
|
-
"""
|
|
19
|
-
Manages a collection of overlays within a scene.
|
|
20
|
-
"""
|
|
21
|
-
|
|
22
|
-
def update(self, dt: float):
|
|
23
|
-
"""
|
|
24
|
-
Update all managed overlays.
|
|
25
|
-
|
|
26
|
-
:param dt: Time delta in seconds.
|
|
27
|
-
:type dt: float
|
|
28
|
-
"""
|
|
29
|
-
for ov in list(self.items):
|
|
30
|
-
# class overlays only
|
|
31
|
-
if hasattr(ov, "update") and hasattr(ov, "draw"):
|
|
32
|
-
if getattr(ov, "enabled", True):
|
|
33
|
-
ov.update(dt)
|
|
34
|
-
|
|
35
|
-
def draw(self, surface: "Backend"):
|
|
36
|
-
"""
|
|
37
|
-
Call all overlays. Scenes should call this at the end of draw().
|
|
38
|
-
|
|
39
|
-
:param surface: The backend surface to draw on.
|
|
40
|
-
:type surface: Backend
|
|
41
|
-
"""
|
|
42
|
-
|
|
43
|
-
def prio(o: OverlayType) -> int:
|
|
44
|
-
"""Priority for sorting overlays."""
|
|
45
|
-
return getattr(o, "priority", 0)
|
|
46
|
-
|
|
47
|
-
for ov in sorted(list(self.items), key=prio):
|
|
48
|
-
if hasattr(ov, "draw"):
|
|
49
|
-
if getattr(ov, "enabled", True):
|
|
50
|
-
ov.draw(surface)
|
|
51
|
-
else:
|
|
52
|
-
# function overlay
|
|
53
|
-
ov(surface)
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Manager for scene systems.
|
|
3
|
-
"""
|
|
4
|
-
|
|
5
|
-
from __future__ import annotations
|
|
6
|
-
|
|
7
|
-
from dataclasses import dataclass
|
|
8
|
-
|
|
9
|
-
from mini_arcade_core.managers.base import ListManager
|
|
10
|
-
from mini_arcade_core.scenes.system import BaseSceneSystem
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
@dataclass
|
|
14
|
-
class SystemManager(ListManager[BaseSceneSystem]):
|
|
15
|
-
"""
|
|
16
|
-
Manager for scene systems.
|
|
17
|
-
"""
|
|
18
|
-
|
|
19
|
-
def sorted(self) -> list[BaseSceneSystem]:
|
|
20
|
-
"""
|
|
21
|
-
Get systems sorted by priority.
|
|
22
|
-
|
|
23
|
-
:return: List of systems sorted by priority.
|
|
24
|
-
:rtype: list[BaseSceneSystem]
|
|
25
|
-
"""
|
|
26
|
-
return sorted(self.items, key=lambda s: getattr(s, "priority", 0))
|
mini_arcade_core/scenes/model.py
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Scene base model module.
|
|
3
|
-
Provides the Scene class and related services.
|
|
4
|
-
"""
|
|
5
|
-
|
|
6
|
-
from __future__ import annotations
|
|
7
|
-
|
|
8
|
-
from dataclasses import dataclass, fields
|
|
9
|
-
from typing import Any
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
@dataclass
|
|
13
|
-
class SceneModel:
|
|
14
|
-
"""
|
|
15
|
-
Basic data model for a scene.
|
|
16
|
-
"""
|
|
17
|
-
|
|
18
|
-
@staticmethod
|
|
19
|
-
def _serialize_dataclass(obj) -> dict[str, Any]:
|
|
20
|
-
out = {}
|
|
21
|
-
for f in fields(obj):
|
|
22
|
-
if f.metadata.get("serialize", True) is False:
|
|
23
|
-
continue
|
|
24
|
-
out[f.name] = getattr(obj, f.name)
|
|
25
|
-
return out
|
|
26
|
-
|
|
27
|
-
def to_dict(self) -> dict:
|
|
28
|
-
"""
|
|
29
|
-
Convert the SceneModel to a dictionary.
|
|
30
|
-
|
|
31
|
-
:return: Dictionary representation of the SceneModel.
|
|
32
|
-
:rtype: dict
|
|
33
|
-
"""
|
|
34
|
-
return self._serialize_dataclass(self)
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Container for scene services like entity and overlay managers.
|
|
3
|
-
"""
|
|
4
|
-
|
|
5
|
-
from __future__ import annotations
|
|
6
|
-
|
|
7
|
-
from dataclasses import dataclass, field
|
|
8
|
-
|
|
9
|
-
from mini_arcade_core.managers.entities import EntityManager
|
|
10
|
-
from mini_arcade_core.managers.inputs import InputManager
|
|
11
|
-
from mini_arcade_core.managers.overlays import OverlayManager
|
|
12
|
-
from mini_arcade_core.managers.system import SystemManager
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
@dataclass
|
|
16
|
-
class SceneRuntime:
|
|
17
|
-
"""
|
|
18
|
-
Container for scene services like entity and overlay managers.
|
|
19
|
-
|
|
20
|
-
:ivar input (InputManager): InputManager for handling input bindings and commands.
|
|
21
|
-
:ivar entities (EntityManager): EntityManager for managing scene entities.
|
|
22
|
-
:ivar overlays (OverlayManager): OverlayManager for managing scene overlays.
|
|
23
|
-
:ivar systems (SystemManager): SystemManager for managing scene systems.
|
|
24
|
-
"""
|
|
25
|
-
|
|
26
|
-
input: InputManager = field(default_factory=InputManager)
|
|
27
|
-
entities: EntityManager = field(default_factory=EntityManager)
|
|
28
|
-
overlays: OverlayManager = field(default_factory=OverlayManager)
|
|
29
|
-
systems: SystemManager = field(default_factory=SystemManager)
|