mini-arcade-core 0.9.9__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 +44 -80
- 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/bus.py +57 -0
- 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 -14
- mini_arcade_core/managers/cheats.py +186 -0
- mini_arcade_core/managers/inputs.py +286 -0
- 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 -12
- 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 -0
- mini_arcade_core/spaces/d2/__init__.py +0 -0
- mini_arcade_core/{two_d → spaces/d2}/collision2d.py +25 -28
- mini_arcade_core/{two_d → spaces/d2}/geometry2d.py +18 -0
- mini_arcade_core/{two_d → spaces/d2}/kinematics2d.py +5 -8
- mini_arcade_core/{two_d → spaces/d2}/physics2d.py +9 -0
- mini_arcade_core/ui/__init__.py +0 -14
- mini_arcade_core/ui/menu.py +415 -56
- 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.9.9.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.9.9.dist-info → mini_arcade_core-1.0.0.dist-info}/WHEEL +1 -1
- mini_arcade_core/cheats.py +0 -235
- mini_arcade_core/entity.py +0 -71
- mini_arcade_core/game.py +0 -287
- mini_arcade_core/keymaps/__init__.py +0 -15
- mini_arcade_core/managers/base.py +0 -91
- mini_arcade_core/managers/entity_manager.py +0 -38
- mini_arcade_core/managers/overlay_manager.py +0 -33
- mini_arcade_core/scenes/scene.py +0 -93
- mini_arcade_core/two_d/__init__.py +0 -30
- mini_arcade_core-0.9.9.dist-info/RECORD +0 -31
- /mini_arcade_core/{keymaps → backend}/keys.py +0 -0
- /mini_arcade_core/{two_d → spaces/d2}/boundaries2d.py +0 -0
- {mini_arcade_core-0.9.9.dist-info → mini_arcade_core-1.0.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Input frame data structure for capturing input state per frame.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
from dataclasses import dataclass, field
|
|
8
|
+
from typing import Dict, FrozenSet, Tuple
|
|
9
|
+
|
|
10
|
+
from mini_arcade_core.backend.keys import Key
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@dataclass(frozen=True)
|
|
14
|
+
class ButtonState:
|
|
15
|
+
"""
|
|
16
|
+
State of a single action button.
|
|
17
|
+
|
|
18
|
+
:ivar down (bool): Whether the button is currently held down.
|
|
19
|
+
:ivar pressed (bool): Whether the button was pressed this frame.
|
|
20
|
+
:ivar released (bool): Whether the button was released this frame.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
down: bool
|
|
24
|
+
pressed: bool
|
|
25
|
+
released: bool
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
# TODO: Solve too-many-instance-attributes warning later
|
|
29
|
+
# Justification: This data class needs multiple attributes to capture input state.
|
|
30
|
+
# pylint: disable=too-many-instance-attributes
|
|
31
|
+
@dataclass(frozen=True)
|
|
32
|
+
class InputFrame:
|
|
33
|
+
"""
|
|
34
|
+
Snapshot of input state for a single frame.
|
|
35
|
+
|
|
36
|
+
:ivar frame_index (int): Sequential index of the frame.
|
|
37
|
+
:ivar dt (float): Delta time since the last frame in seconds.
|
|
38
|
+
:ivar keys_down (FrozenSet[Key]): Set of currently held down keys.
|
|
39
|
+
:ivar keys_pressed (FrozenSet[Key]): Set of keys pressed this frame.
|
|
40
|
+
:ivar keys_released (FrozenSet[Key]): Set of keys released this frame.
|
|
41
|
+
:ivar buttons (Dict[str, ButtonState]): Mapping of action button names to their states.
|
|
42
|
+
:ivar axes (Dict[str, float]): Mapping of axis names to their float values.
|
|
43
|
+
:ivar mouse_pos (Tuple[int, int]): Current mouse position (x, y).
|
|
44
|
+
:ivar mouse_delta (Tuple[int, int]): Mouse movement delta (dx, dy)
|
|
45
|
+
:ivar text_input (str): Text input entered this frame.
|
|
46
|
+
:ivar quit (bool): Whether a quit request was made this frame.
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
frame_index: int
|
|
50
|
+
dt: float
|
|
51
|
+
|
|
52
|
+
# Physical keys (device-level snapshot) – supports cheats & replay
|
|
53
|
+
keys_down: FrozenSet[Key] = frozenset()
|
|
54
|
+
keys_pressed: FrozenSet[Key] = frozenset()
|
|
55
|
+
keys_released: FrozenSet[Key] = frozenset()
|
|
56
|
+
|
|
57
|
+
# action buttons (jump, confirm, pause, etc.)
|
|
58
|
+
buttons: Dict[str, ButtonState] = field(default_factory=dict)
|
|
59
|
+
# axes (move_y, aim_x, etc.)
|
|
60
|
+
axes: Dict[str, float] = field(default_factory=dict)
|
|
61
|
+
|
|
62
|
+
# optional: pass through for UI needs
|
|
63
|
+
mouse_pos: Tuple[int, int] = (0, 0)
|
|
64
|
+
mouse_delta: Tuple[int, int] = (0, 0)
|
|
65
|
+
text_input: str = ""
|
|
66
|
+
|
|
67
|
+
# Window/OS quit request
|
|
68
|
+
quit: bool = False
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
# pylint: enable=too-many-instance-attributes
|
|
File without changes
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Module providing runtime adapters for window and scene management.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
from mini_arcade_core.runtime.context import RuntimeContext
|
|
8
|
+
from mini_arcade_core.runtime.scene.scene_port import (
|
|
9
|
+
SceneEntry,
|
|
10
|
+
ScenePolicy,
|
|
11
|
+
ScenePort,
|
|
12
|
+
StackItem,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class SceneAdapter(ScenePort):
|
|
17
|
+
"""
|
|
18
|
+
Manages multiple scenes (not implemented).
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
def __init__(self, registry, game):
|
|
22
|
+
self._registry = registry
|
|
23
|
+
self._stack = []
|
|
24
|
+
self._game = game
|
|
25
|
+
|
|
26
|
+
@property
|
|
27
|
+
def current_scene(self):
|
|
28
|
+
return self._stack[-1].entry.scene if self._stack else None
|
|
29
|
+
|
|
30
|
+
@property
|
|
31
|
+
def visible_stack(self):
|
|
32
|
+
return [e.scene for e in self.visible_entries()]
|
|
33
|
+
|
|
34
|
+
def change(self, scene_id):
|
|
35
|
+
self.clean()
|
|
36
|
+
self.push(scene_id, as_overlay=False)
|
|
37
|
+
|
|
38
|
+
def push(
|
|
39
|
+
self,
|
|
40
|
+
scene_id,
|
|
41
|
+
*,
|
|
42
|
+
as_overlay=False,
|
|
43
|
+
policy=None,
|
|
44
|
+
):
|
|
45
|
+
# default policy based on overlay vs base
|
|
46
|
+
if policy is None:
|
|
47
|
+
# base scenes: do not block anything by default
|
|
48
|
+
policy = ScenePolicy()
|
|
49
|
+
runtime_context = RuntimeContext.from_game(self._game)
|
|
50
|
+
scene = self._registry.create(
|
|
51
|
+
scene_id, runtime_context
|
|
52
|
+
) # or whatever your factory call is
|
|
53
|
+
scene.on_enter()
|
|
54
|
+
|
|
55
|
+
entry = SceneEntry(
|
|
56
|
+
scene_id=scene_id,
|
|
57
|
+
scene=scene,
|
|
58
|
+
is_overlay=as_overlay,
|
|
59
|
+
policy=policy,
|
|
60
|
+
)
|
|
61
|
+
self._stack.append(StackItem(entry=entry))
|
|
62
|
+
|
|
63
|
+
def pop(self):
|
|
64
|
+
if not self._stack:
|
|
65
|
+
return
|
|
66
|
+
item = self._stack.pop()
|
|
67
|
+
item.entry.scene.on_exit()
|
|
68
|
+
|
|
69
|
+
def clean(self):
|
|
70
|
+
while self._stack:
|
|
71
|
+
self.pop()
|
|
72
|
+
|
|
73
|
+
def quit(self):
|
|
74
|
+
self._game.quit()
|
|
75
|
+
|
|
76
|
+
def visible_entries(self):
|
|
77
|
+
entries = [i.entry for i in self._stack]
|
|
78
|
+
# find highest opaque from top down; render starting there
|
|
79
|
+
for idx in range(len(entries) - 1, -1, -1):
|
|
80
|
+
if entries[idx].policy.is_opaque:
|
|
81
|
+
return entries[idx:]
|
|
82
|
+
return entries
|
|
83
|
+
|
|
84
|
+
def update_entries(self):
|
|
85
|
+
vis = self.visible_entries()
|
|
86
|
+
if not vis:
|
|
87
|
+
return []
|
|
88
|
+
out = []
|
|
89
|
+
for entry in reversed(vis): # top->down
|
|
90
|
+
out.append(entry)
|
|
91
|
+
if entry.policy.blocks_update:
|
|
92
|
+
break
|
|
93
|
+
return list(reversed(out)) # bottom->top order
|
|
94
|
+
|
|
95
|
+
def input_entry(self):
|
|
96
|
+
vis = self.visible_entries()
|
|
97
|
+
return vis[-1] if vis else None
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Service interfaces for runtime components.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
from dataclasses import dataclass
|
|
8
|
+
from typing import TYPE_CHECKING, List
|
|
9
|
+
|
|
10
|
+
from mini_arcade_core.scenes.registry import SceneRegistry
|
|
11
|
+
|
|
12
|
+
if TYPE_CHECKING:
|
|
13
|
+
from mini_arcade_core.engine.game import Game
|
|
14
|
+
from mini_arcade_core.scenes.scene import Scene
|
|
15
|
+
from mini_arcade_core.sim.protocols import SimScene
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@dataclass(frozen=True)
|
|
19
|
+
class ScenePolicy:
|
|
20
|
+
"""
|
|
21
|
+
Controls how a scene behaves in the scene stack.
|
|
22
|
+
|
|
23
|
+
blocks_update: if True, scenes below do not tick/update (pause modal)
|
|
24
|
+
blocks_input: if True, scenes below do not receive input
|
|
25
|
+
is_opaque: if True, scenes below are not rendered
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
blocks_update: bool = False
|
|
29
|
+
blocks_input: bool = False
|
|
30
|
+
is_opaque: bool = False
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@dataclass(frozen=True)
|
|
34
|
+
class SceneEntry:
|
|
35
|
+
"""
|
|
36
|
+
An entry in the scene stack.
|
|
37
|
+
|
|
38
|
+
:ivar scene_id (str): Identifier of the scene.
|
|
39
|
+
:ivar scene (Scene): The scene instance.
|
|
40
|
+
:ivar is_overlay (bool): Whether the scene is an overlay.
|
|
41
|
+
:ivar policy (ScenePolicy): The scene's policy.
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
scene_id: str
|
|
45
|
+
scene: SimScene
|
|
46
|
+
is_overlay: bool
|
|
47
|
+
policy: ScenePolicy
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
@dataclass
|
|
51
|
+
class StackItem:
|
|
52
|
+
"""
|
|
53
|
+
An item in the scene stack.
|
|
54
|
+
|
|
55
|
+
:ivar entry (SceneEntry): The scene entry.
|
|
56
|
+
"""
|
|
57
|
+
|
|
58
|
+
entry: SceneEntry
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class ScenePort:
|
|
62
|
+
"""Interface for scene management operations."""
|
|
63
|
+
|
|
64
|
+
_registry: SceneRegistry
|
|
65
|
+
_stack: List[StackItem]
|
|
66
|
+
_game: Game
|
|
67
|
+
|
|
68
|
+
@property
|
|
69
|
+
def current_scene(self) -> "SimScene | None":
|
|
70
|
+
"""
|
|
71
|
+
Get the currently active scene.
|
|
72
|
+
|
|
73
|
+
:return: The active Scene instance, or None if no scene is active.
|
|
74
|
+
:rtype: SimScene | None
|
|
75
|
+
"""
|
|
76
|
+
|
|
77
|
+
@property
|
|
78
|
+
def visible_stack(self) -> List["SimScene"]:
|
|
79
|
+
"""
|
|
80
|
+
Return the list of scenes that should be drawn (base + overlays).
|
|
81
|
+
We draw from the top-most non-overlay scene upward.
|
|
82
|
+
|
|
83
|
+
:return: List of visible Scene instances.
|
|
84
|
+
:rtype: List[SimScene]
|
|
85
|
+
"""
|
|
86
|
+
|
|
87
|
+
def change(self, scene_id: str):
|
|
88
|
+
"""
|
|
89
|
+
Change the current scene to the specified scene.
|
|
90
|
+
|
|
91
|
+
:param scene_id: Identifier of the scene to switch to.
|
|
92
|
+
:type scene_id: str
|
|
93
|
+
"""
|
|
94
|
+
|
|
95
|
+
def push(self, scene_id: str, *, as_overlay: bool = False):
|
|
96
|
+
"""
|
|
97
|
+
Push a new scene onto the scene stack.
|
|
98
|
+
|
|
99
|
+
:param scene_id: Identifier of the scene to push.
|
|
100
|
+
:type scene_id: str
|
|
101
|
+
|
|
102
|
+
:param as_overlay: Whether to push the scene as an overlay.
|
|
103
|
+
:type as_overlay: bool
|
|
104
|
+
"""
|
|
105
|
+
|
|
106
|
+
def pop(self) -> "Scene | None":
|
|
107
|
+
"""
|
|
108
|
+
Pop the current scene from the scene stack.
|
|
109
|
+
|
|
110
|
+
:return: The popped Scene instance, or None if the stack was empty.
|
|
111
|
+
:rtype: Scene | None
|
|
112
|
+
"""
|
|
113
|
+
|
|
114
|
+
def clean(self):
|
|
115
|
+
"""
|
|
116
|
+
Clean up all scenes from the scene stack.
|
|
117
|
+
"""
|
|
118
|
+
|
|
119
|
+
def quit(self):
|
|
120
|
+
"""
|
|
121
|
+
Quit the game
|
|
122
|
+
"""
|
|
123
|
+
|
|
124
|
+
def visible_entries(self) -> list[SceneEntry]:
|
|
125
|
+
"""
|
|
126
|
+
Render from bottom->top unless an opaque entry exists; if so,
|
|
127
|
+
render only from that entry up.
|
|
128
|
+
|
|
129
|
+
:return: List of SceneEntry instances to render.
|
|
130
|
+
:rtype: list[SceneEntry]
|
|
131
|
+
"""
|
|
132
|
+
|
|
133
|
+
def update_entries(self) -> list[SceneEntry]:
|
|
134
|
+
"""
|
|
135
|
+
Tick/update scenes considering blocks_update.
|
|
136
|
+
Typical: pause overlay blocks update below it.
|
|
137
|
+
|
|
138
|
+
:return: List of SceneEntry instances to update.
|
|
139
|
+
:rtype: list[SceneEntry]
|
|
140
|
+
"""
|
|
141
|
+
|
|
142
|
+
def input_entry(self) -> SceneEntry | None:
|
|
143
|
+
"""
|
|
144
|
+
Who gets input this frame. If top blocks_input, only it receives input.
|
|
145
|
+
If not, top still gets input (v1 simple). Later you can allow fall-through.
|
|
146
|
+
|
|
147
|
+
:return: The SceneEntry that receives input, or None if no scenes are active.
|
|
148
|
+
:rtype: SceneEntry | None
|
|
149
|
+
"""
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Service container for runtime components.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
from dataclasses import dataclass
|
|
8
|
+
|
|
9
|
+
from mini_arcade_core.runtime.audio.audio_port import AudioPort
|
|
10
|
+
from mini_arcade_core.runtime.capture.capture_port import CapturePort
|
|
11
|
+
from mini_arcade_core.runtime.file.file_port import FilePort
|
|
12
|
+
from mini_arcade_core.runtime.input.input_port import InputPort
|
|
13
|
+
from mini_arcade_core.runtime.scene.scene_port import ScenePort
|
|
14
|
+
from mini_arcade_core.runtime.window.window_port import WindowPort
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@dataclass
|
|
18
|
+
class RuntimeServices:
|
|
19
|
+
"""
|
|
20
|
+
Container for runtime service ports.
|
|
21
|
+
|
|
22
|
+
:ivar window (WindowPort): Window service port.
|
|
23
|
+
:ivar scenes (ScenePort): Scene management service port.
|
|
24
|
+
:ivar audio (AudioPort): Audio service port.
|
|
25
|
+
:ivar files (FilePort): File service port.
|
|
26
|
+
:ivar capture (CapturePort): Capture service port.
|
|
27
|
+
:ivar input (InputPort): Input handling service port.
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
window: WindowPort
|
|
31
|
+
scenes: ScenePort
|
|
32
|
+
audio: AudioPort
|
|
33
|
+
files: FilePort
|
|
34
|
+
capture: CapturePort
|
|
35
|
+
input: InputPort
|
|
File without changes
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Module providing runtime adapters for window and scene management.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
from mini_arcade_core.runtime.window.window_port import WindowPort
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class WindowAdapter(WindowPort):
|
|
11
|
+
"""
|
|
12
|
+
Manages multiple game windows (not implemented).
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
def __init__(self, backend):
|
|
16
|
+
self.backend = backend
|
|
17
|
+
|
|
18
|
+
def set_window_size(self, width, height):
|
|
19
|
+
self.size = (width, height)
|
|
20
|
+
self.backend.init(width, height)
|
|
21
|
+
|
|
22
|
+
def set_title(self, title):
|
|
23
|
+
self.backend.set_window_title(title)
|
|
24
|
+
|
|
25
|
+
def set_clear_color(self, r, g, b):
|
|
26
|
+
self.backend.set_clear_color(r, g, b)
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Service interfaces for runtime components.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
from mini_arcade_core.backend import Backend
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class WindowPort:
|
|
11
|
+
"""Interface for window-related operations."""
|
|
12
|
+
|
|
13
|
+
backend: Backend
|
|
14
|
+
size: tuple[int, int]
|
|
15
|
+
|
|
16
|
+
def set_window_size(self, width: int, height: int):
|
|
17
|
+
"""
|
|
18
|
+
Set the size of the window.
|
|
19
|
+
|
|
20
|
+
:param width: Width in pixels.
|
|
21
|
+
:type width: int
|
|
22
|
+
|
|
23
|
+
:param height: Height in pixels.
|
|
24
|
+
:type height: int
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
def set_title(self, title: str):
|
|
28
|
+
"""
|
|
29
|
+
Set the window title.
|
|
30
|
+
|
|
31
|
+
:param title: The new title for the window.
|
|
32
|
+
:type title: str
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
def set_clear_color(self, r: int, g: int, b: int):
|
|
36
|
+
"""
|
|
37
|
+
Set the clear color for the window.
|
|
38
|
+
|
|
39
|
+
:param r: Red component (0-255).
|
|
40
|
+
:type r: int
|
|
41
|
+
|
|
42
|
+
:param g: Green component (0-255).
|
|
43
|
+
:type g: int
|
|
44
|
+
|
|
45
|
+
:param b: Blue component (0-255).
|
|
46
|
+
:type b: int
|
|
47
|
+
"""
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Scenes module for Mini Arcade Core.
|
|
3
|
-
Provides the base Scene class and related functionality.
|
|
4
|
-
"""
|
|
5
|
-
|
|
6
|
-
from __future__ import annotations
|
|
7
|
-
|
|
8
|
-
from .autoreg import register_scene
|
|
9
|
-
from .registry import SceneRegistry
|
|
10
|
-
from .scene import Scene, SceneServices
|
|
11
|
-
|
|
12
|
-
__all__ = ["Scene", "register_scene", "SceneRegistry", "SceneServices"]
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"""
|
|
2
|
-
|
|
2
|
+
SimScene registry for mini arcade core.
|
|
3
3
|
Allows registering and creating scenes by string IDs.
|
|
4
4
|
"""
|
|
5
5
|
|
|
@@ -10,11 +10,13 @@ import pkgutil
|
|
|
10
10
|
from dataclasses import dataclass
|
|
11
11
|
from typing import TYPE_CHECKING, Dict, Protocol
|
|
12
12
|
|
|
13
|
+
from mini_arcade_core.runtime.context import RuntimeContext
|
|
14
|
+
|
|
13
15
|
from .autoreg import snapshot
|
|
14
16
|
|
|
15
17
|
if TYPE_CHECKING:
|
|
16
|
-
from mini_arcade_core.
|
|
17
|
-
from mini_arcade_core.
|
|
18
|
+
from mini_arcade_core.engine.commands import CommandQueue
|
|
19
|
+
from mini_arcade_core.sim import SimScene
|
|
18
20
|
|
|
19
21
|
|
|
20
22
|
class SceneFactory(Protocol):
|
|
@@ -22,7 +24,7 @@ class SceneFactory(Protocol):
|
|
|
22
24
|
Protocol for scene factory callables.
|
|
23
25
|
"""
|
|
24
26
|
|
|
25
|
-
def __call__(self,
|
|
27
|
+
def __call__(self, context: RuntimeContext) -> "SimScene": ...
|
|
26
28
|
|
|
27
29
|
|
|
28
30
|
@dataclass
|
|
@@ -40,28 +42,28 @@ class SceneRegistry:
|
|
|
40
42
|
:param scene_id: The string ID for the scene.
|
|
41
43
|
:type scene_id: str
|
|
42
44
|
|
|
43
|
-
:param factory: A callable that creates a
|
|
45
|
+
:param factory: A callable that creates a SimScene instance.
|
|
44
46
|
:type factory: SceneFactory
|
|
45
47
|
"""
|
|
46
48
|
self._factories[scene_id] = factory
|
|
47
49
|
|
|
48
|
-
def register_cls(self, scene_id: str, scene_cls: type["
|
|
50
|
+
def register_cls(self, scene_id: str, scene_cls: type["SimScene"]):
|
|
49
51
|
"""
|
|
50
|
-
Register a
|
|
52
|
+
Register a SimScene class under a given scene ID.
|
|
51
53
|
|
|
52
54
|
:param scene_id: The string ID for the scene.
|
|
53
55
|
:type scene_id: str
|
|
54
56
|
|
|
55
|
-
:param scene_cls: The
|
|
56
|
-
:type scene_cls: type["
|
|
57
|
+
:param scene_cls: The SimScene class to register.
|
|
58
|
+
:type scene_cls: type["SimScene"]
|
|
57
59
|
"""
|
|
58
60
|
|
|
59
|
-
def return_factory(
|
|
60
|
-
return scene_cls(
|
|
61
|
+
def return_factory(context: RuntimeContext) -> "SimScene":
|
|
62
|
+
return scene_cls(context)
|
|
61
63
|
|
|
62
64
|
self.register(scene_id, return_factory)
|
|
63
65
|
|
|
64
|
-
def create(self, scene_id: str,
|
|
66
|
+
def create(self, scene_id: str, context: RuntimeContext) -> "SimScene":
|
|
65
67
|
"""
|
|
66
68
|
Create a scene instance using the registered factory for the given scene ID.
|
|
67
69
|
|
|
@@ -71,22 +73,22 @@ class SceneRegistry:
|
|
|
71
73
|
:param game: The Game instance to pass to the scene factory.
|
|
72
74
|
:type game: Game
|
|
73
75
|
|
|
74
|
-
:return: A new
|
|
75
|
-
:rtype:
|
|
76
|
+
:return: A new SimScene instance.
|
|
77
|
+
:rtype: SimScene
|
|
76
78
|
|
|
77
79
|
:raises KeyError: If no factory is registered for the given scene ID.
|
|
78
80
|
"""
|
|
79
81
|
try:
|
|
80
|
-
return self._factories[scene_id](
|
|
82
|
+
return self._factories[scene_id](context)
|
|
81
83
|
except KeyError as e:
|
|
82
84
|
raise KeyError(f"Unknown scene_id={scene_id!r}") from e
|
|
83
85
|
|
|
84
|
-
def load_catalog(self, catalog: Dict[str, type["
|
|
86
|
+
def load_catalog(self, catalog: Dict[str, type["SimScene"]]):
|
|
85
87
|
"""
|
|
86
|
-
Load a catalog of
|
|
88
|
+
Load a catalog of SimScene classes into the registry.
|
|
87
89
|
|
|
88
|
-
:param catalog: A dictionary mapping scene IDs to
|
|
89
|
-
:type catalog: Dict[str, type["
|
|
90
|
+
:param catalog: A dictionary mapping scene IDs to SimScene classes.
|
|
91
|
+
:type catalog: Dict[str, type["SimScene"]]
|
|
90
92
|
"""
|
|
91
93
|
for scene_id, cls in catalog.items():
|
|
92
94
|
self.register_cls(scene_id, cls)
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Simulation scene protocol module.
|
|
3
|
+
Defines the SimScene protocol for simulation scenes.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
from typing import Protocol, runtime_checkable
|
|
9
|
+
|
|
10
|
+
from mini_arcade_core.engine.render.packet import RenderPacket
|
|
11
|
+
from mini_arcade_core.runtime.input_frame import InputFrame
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@runtime_checkable
|
|
15
|
+
class SimScene(Protocol):
|
|
16
|
+
""" "Protocol for a simulation scene in the mini arcade core."""
|
|
17
|
+
|
|
18
|
+
def on_enter(self):
|
|
19
|
+
"""Called when the scene is entered."""
|
|
20
|
+
|
|
21
|
+
def on_exit(self):
|
|
22
|
+
"""Called when the scene is exited."""
|
|
23
|
+
|
|
24
|
+
def tick(self, input_frame: InputFrame, dt: float):
|
|
25
|
+
"""
|
|
26
|
+
Advance the simulation by one tick.
|
|
27
|
+
|
|
28
|
+
:param input_frame: Current input frame.
|
|
29
|
+
:type input_frame: InputFrame
|
|
30
|
+
|
|
31
|
+
:param dt: Delta time since last tick.
|
|
32
|
+
:type dt: float
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
def build_render_packet(self) -> RenderPacket:
|
|
36
|
+
"""
|
|
37
|
+
Build the render packet for the current scene state.
|
|
38
|
+
|
|
39
|
+
:return: RenderPacket instance.
|
|
40
|
+
:rtype: RenderPacket
|
|
41
|
+
"""
|
|
File without changes
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Protocol for base systems in the mini arcade core.
|
|
3
|
+
Defines the BaseSystem protocol that all systems should implement.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
from typing import Generic, Protocol, TypeVar, runtime_checkable
|
|
9
|
+
|
|
10
|
+
# Justification: Type variable name is conventional.
|
|
11
|
+
# pylint: disable=invalid-name
|
|
12
|
+
TSystemContext = TypeVar("TSystemContext")
|
|
13
|
+
# pylint: enable=invalid-name
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@runtime_checkable
|
|
17
|
+
class BaseSystem(Protocol, Generic[TSystemContext]):
|
|
18
|
+
"""Protocol for a system that operates within a given context."""
|
|
19
|
+
|
|
20
|
+
name: str
|
|
21
|
+
order: int
|
|
22
|
+
|
|
23
|
+
def enabled(self, ctx: TSystemContext) -> bool:
|
|
24
|
+
"""
|
|
25
|
+
Determine if the system is enabled in the given context.
|
|
26
|
+
|
|
27
|
+
:param ctx: The system context.
|
|
28
|
+
:type ctx: TSystemContext
|
|
29
|
+
|
|
30
|
+
:return: True if the system is enabled, False otherwise.
|
|
31
|
+
:rtype: bool
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
def step(self, ctx: TSystemContext):
|
|
35
|
+
"""
|
|
36
|
+
Perform a single step of the system within the given context.
|
|
37
|
+
|
|
38
|
+
:param ctx: The system context.
|
|
39
|
+
:type ctx: TSystemContext
|
|
40
|
+
"""
|