mini-arcade-core 1.1.1__py3-none-any.whl → 1.2.1__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 +14 -42
- mini_arcade_core/backend/__init__.py +1 -2
- mini_arcade_core/backend/backend.py +182 -184
- mini_arcade_core/backend/types.py +5 -1
- mini_arcade_core/engine/commands.py +8 -8
- mini_arcade_core/engine/game.py +54 -354
- mini_arcade_core/engine/game_config.py +40 -0
- mini_arcade_core/engine/gameplay_settings.py +24 -0
- mini_arcade_core/engine/loop/config.py +20 -0
- mini_arcade_core/engine/loop/hooks.py +77 -0
- mini_arcade_core/engine/loop/runner.py +272 -0
- mini_arcade_core/engine/loop/state.py +32 -0
- mini_arcade_core/engine/managers.py +24 -0
- mini_arcade_core/engine/render/context.py +0 -2
- mini_arcade_core/engine/render/effects/base.py +2 -2
- mini_arcade_core/engine/render/effects/crt.py +4 -4
- mini_arcade_core/engine/render/effects/registry.py +1 -1
- mini_arcade_core/engine/render/effects/vignette.py +8 -8
- mini_arcade_core/engine/render/passes/begin_frame.py +1 -1
- mini_arcade_core/engine/render/passes/end_frame.py +1 -1
- mini_arcade_core/engine/render/passes/postfx.py +1 -1
- mini_arcade_core/engine/render/passes/ui.py +1 -1
- mini_arcade_core/engine/render/passes/world.py +6 -6
- mini_arcade_core/engine/render/pipeline.py +7 -6
- mini_arcade_core/engine/render/viewport.py +10 -4
- mini_arcade_core/engine/scenes/models.py +54 -0
- mini_arcade_core/engine/scenes/scene_manager.py +213 -0
- mini_arcade_core/runtime/audio/audio_adapter.py +4 -3
- mini_arcade_core/runtime/audio/audio_port.py +0 -4
- mini_arcade_core/runtime/capture/capture_adapter.py +53 -31
- mini_arcade_core/runtime/capture/capture_port.py +0 -4
- mini_arcade_core/runtime/capture/capture_worker.py +174 -0
- mini_arcade_core/runtime/context.py +8 -6
- mini_arcade_core/runtime/scene/scene_query_adapter.py +31 -0
- mini_arcade_core/runtime/scene/scene_query_port.py +38 -0
- mini_arcade_core/runtime/services.py +3 -2
- mini_arcade_core/runtime/window/window_adapter.py +43 -41
- mini_arcade_core/runtime/window/window_port.py +3 -17
- mini_arcade_core/scenes/debug_overlay.py +5 -4
- mini_arcade_core/scenes/registry.py +11 -1
- mini_arcade_core/scenes/sim_scene.py +14 -14
- mini_arcade_core/ui/menu.py +54 -16
- mini_arcade_core/utils/__init__.py +2 -1
- mini_arcade_core/utils/logging.py +47 -18
- mini_arcade_core/utils/profiler.py +283 -0
- {mini_arcade_core-1.1.1.dist-info → mini_arcade_core-1.2.1.dist-info}/METADATA +1 -1
- mini_arcade_core-1.2.1.dist-info/RECORD +93 -0
- {mini_arcade_core-1.1.1.dist-info → mini_arcade_core-1.2.1.dist-info}/WHEEL +1 -1
- mini_arcade_core/managers/inputs.py +0 -284
- mini_arcade_core/runtime/scene/scene_adapter.py +0 -125
- mini_arcade_core/runtime/scene/scene_port.py +0 -170
- mini_arcade_core/sim/protocols.py +0 -41
- mini_arcade_core/sim/runner.py +0 -222
- mini_arcade_core-1.1.1.dist-info/RECORD +0 -85
- /mini_arcade_core/{managers → engine}/cheats.py +0 -0
- /mini_arcade_core/{managers → engine/loop}/__init__.py +0 -0
- /mini_arcade_core/{sim → engine/scenes}/__init__.py +0 -0
- {mini_arcade_core-1.1.1.dist-info → mini_arcade_core-1.2.1.dist-info}/licenses/LICENSE +0 -0
mini_arcade_core/__init__.py
CHANGED
|
@@ -9,7 +9,8 @@ import traceback
|
|
|
9
9
|
from importlib.metadata import PackageNotFoundError, version
|
|
10
10
|
from typing import Callable, Type, Union
|
|
11
11
|
|
|
12
|
-
from mini_arcade_core.engine.game import Game
|
|
12
|
+
from mini_arcade_core.engine.game import Game
|
|
13
|
+
from mini_arcade_core.engine.game_config import GameConfig
|
|
13
14
|
from mini_arcade_core.scenes.registry import SceneRegistry
|
|
14
15
|
from mini_arcade_core.scenes.sim_scene import SimScene
|
|
15
16
|
from mini_arcade_core.utils import logger
|
|
@@ -17,59 +18,31 @@ from mini_arcade_core.utils import logger
|
|
|
17
18
|
SceneFactoryLike = Union[Type[SimScene], Callable[[Game], SimScene]]
|
|
18
19
|
|
|
19
20
|
|
|
20
|
-
# TODO: Improve exception
|
|
21
|
-
# TODO: Consider reducing parameters by using a single config object
|
|
22
|
-
# TODO: Delegate responsibilities to Game class where appropriate
|
|
21
|
+
# TODO: Improve exception handliers by usingng and logging in run_game
|
|
23
22
|
def run_game(
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
registry: SceneRegistry | None = None,
|
|
27
|
-
initial_scene: str = "main",
|
|
23
|
+
game_config: GameConfig | None = None,
|
|
24
|
+
scene_registry: SceneRegistry | None = None,
|
|
28
25
|
):
|
|
29
26
|
"""
|
|
30
27
|
Convenience helper to bootstrap and run a game with a single scene.
|
|
31
28
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
- run_game(config=cfg, initial_scene="main", registry=...) # registry-based
|
|
35
|
-
- run_game(cfg) # config-only
|
|
29
|
+
:param game_config: Optional GameConfig to customize game settings.
|
|
30
|
+
:type game_config: GameConfig | None
|
|
36
31
|
|
|
37
|
-
:param
|
|
38
|
-
:type
|
|
32
|
+
:param scene_registry: Optional SceneRegistry for scene management.
|
|
33
|
+
:type scene_registry: SceneRegistry | None
|
|
39
34
|
|
|
40
|
-
:
|
|
41
|
-
:type initial_scene: str
|
|
42
|
-
|
|
43
|
-
:param config: Optional GameConfig to customize game settings.
|
|
44
|
-
:type config: GameConfig | None
|
|
45
|
-
|
|
46
|
-
:param registry: Optional SceneRegistry for scene management.
|
|
47
|
-
:type registry: SceneRegistry | None
|
|
48
|
-
|
|
49
|
-
:raises ValueError: If the provided config does not have a valid Backend.
|
|
35
|
+
:raises ValueError: If the provided game_config does not have a valid Backend.
|
|
50
36
|
"""
|
|
51
37
|
try:
|
|
52
|
-
|
|
53
|
-
if isinstance(scene, GameConfig) and config is None:
|
|
54
|
-
config = scene
|
|
55
|
-
scene = None
|
|
56
|
-
|
|
57
|
-
cfg = config or GameConfig()
|
|
38
|
+
cfg = game_config or GameConfig()
|
|
58
39
|
if cfg.backend is None:
|
|
59
40
|
raise ValueError(
|
|
60
41
|
"GameConfig.backend must be set to a Backend instance"
|
|
61
42
|
)
|
|
62
43
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
if registry is None:
|
|
66
|
-
registry = SceneRegistry(_factories={})
|
|
67
|
-
registry.register(
|
|
68
|
-
initial_scene, scene
|
|
69
|
-
) # SimScene class is callable(game) -> SimScene
|
|
70
|
-
|
|
71
|
-
game = Game(cfg, registry=registry)
|
|
72
|
-
game.run(initial_scene)
|
|
44
|
+
game = Game(cfg, scene_registry=scene_registry)
|
|
45
|
+
game.run()
|
|
73
46
|
# Justification: We need to catch all exceptions while we improve error handling.
|
|
74
47
|
# pylint: disable=broad-exception-caught
|
|
75
48
|
except Exception as e:
|
|
@@ -78,7 +51,7 @@ def run_game(
|
|
|
78
51
|
# pylint: enable=broad-exception-caught
|
|
79
52
|
|
|
80
53
|
|
|
81
|
-
PACKAGE_NAME = "mini-arcade-core"
|
|
54
|
+
PACKAGE_NAME = "mini-arcade-core"
|
|
82
55
|
|
|
83
56
|
|
|
84
57
|
def get_version() -> str:
|
|
@@ -107,7 +80,6 @@ def get_version() -> str:
|
|
|
107
80
|
__all__ = [
|
|
108
81
|
"Game",
|
|
109
82
|
"GameConfig",
|
|
110
|
-
"WindowConfig",
|
|
111
83
|
"run_game",
|
|
112
84
|
]
|
|
113
85
|
|
|
@@ -5,320 +5,318 @@ This is the only part of the code that talks to SDL/pygame directly.
|
|
|
5
5
|
|
|
6
6
|
from __future__ import annotations
|
|
7
7
|
|
|
8
|
-
from dataclasses import dataclass
|
|
9
8
|
from typing import Iterable, Protocol
|
|
10
9
|
|
|
11
10
|
from .events import Event
|
|
12
|
-
from .types import Color
|
|
13
11
|
|
|
12
|
+
# Justification: Many positional and keyword arguments needed for some backend methods.
|
|
13
|
+
# Might be refactored later.
|
|
14
|
+
# pylint: disable=too-many-positional-arguments,too-many-arguments
|
|
14
15
|
|
|
15
|
-
@dataclass
|
|
16
|
-
class WindowSettings:
|
|
17
|
-
"""
|
|
18
|
-
Settings for the backend window.
|
|
19
16
|
|
|
20
|
-
|
|
21
|
-
|
|
17
|
+
class WindowProtocol(Protocol):
|
|
18
|
+
"""
|
|
19
|
+
Represents a game window.
|
|
22
20
|
"""
|
|
23
21
|
|
|
24
22
|
width: int
|
|
25
23
|
height: int
|
|
26
24
|
|
|
25
|
+
def set_title(self, title: str):
|
|
26
|
+
"""
|
|
27
|
+
Set the window title.
|
|
27
28
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
class Backend(Protocol):
|
|
32
|
-
"""
|
|
33
|
-
Interface that any rendering/input backend must implement.
|
|
29
|
+
:param title: New window title.
|
|
30
|
+
:type title: str
|
|
31
|
+
"""
|
|
34
32
|
|
|
35
|
-
|
|
36
|
-
|
|
33
|
+
def resize(self, width: int, height: int):
|
|
34
|
+
"""
|
|
35
|
+
Resize the window.
|
|
37
36
|
|
|
38
|
-
|
|
37
|
+
:param width: New width in pixels.
|
|
38
|
+
:type width: int
|
|
39
|
+
:param height: New height in pixels.
|
|
40
|
+
:type height: int
|
|
39
41
|
"""
|
|
40
|
-
Initialize the backend and open a window.
|
|
41
|
-
Should be called once before the main loop.
|
|
42
42
|
|
|
43
|
-
|
|
44
|
-
:type window_settings: WindowSettings
|
|
43
|
+
def size(self) -> tuple[int, int]:
|
|
45
44
|
"""
|
|
45
|
+
Get the window size.
|
|
46
46
|
|
|
47
|
-
|
|
47
|
+
:return: Tuple of (width, height) in pixels.
|
|
48
|
+
:rtype: tuple[int, int]
|
|
48
49
|
"""
|
|
49
|
-
Set the window title.
|
|
50
50
|
|
|
51
|
-
|
|
52
|
-
:type title: str
|
|
51
|
+
def drawable_size(self) -> tuple[int, int]:
|
|
53
52
|
"""
|
|
54
|
-
|
|
53
|
+
Get the drawable size of the window.
|
|
55
54
|
|
|
56
|
-
|
|
55
|
+
:return: Tuple of (width, height) in pixels.
|
|
56
|
+
:rtype: tuple[int, int]
|
|
57
57
|
"""
|
|
58
|
-
Return all pending events since last call.
|
|
59
|
-
Concrete backends will translate their native events into core Event objects.
|
|
60
58
|
|
|
61
|
-
|
|
59
|
+
|
|
60
|
+
class InputProtocol(Protocol):
|
|
61
|
+
"""
|
|
62
|
+
Interface for input operations.
|
|
63
|
+
"""
|
|
64
|
+
|
|
65
|
+
def poll(self) -> Iterable[Event]:
|
|
66
|
+
"""
|
|
67
|
+
Get the list of input events since the last call.
|
|
68
|
+
|
|
69
|
+
:return: Iterable of Event instances.
|
|
62
70
|
:rtype: Iterable[Event]
|
|
63
71
|
"""
|
|
64
72
|
|
|
73
|
+
|
|
74
|
+
class RenderProtocol(Protocol):
|
|
75
|
+
"""
|
|
76
|
+
Interface for rendering operations.
|
|
77
|
+
"""
|
|
78
|
+
|
|
65
79
|
def set_clear_color(self, r: int, g: int, b: int):
|
|
66
80
|
"""
|
|
67
|
-
Set the
|
|
81
|
+
Set the clear color for the renderer.
|
|
68
82
|
|
|
69
83
|
:param r: Red component (0-255).
|
|
70
84
|
:type r: int
|
|
71
|
-
|
|
72
85
|
:param g: Green component (0-255).
|
|
73
86
|
:type g: int
|
|
74
|
-
|
|
75
87
|
:param b: Blue component (0-255).
|
|
76
88
|
:type b: int
|
|
77
89
|
"""
|
|
78
90
|
|
|
79
91
|
def begin_frame(self):
|
|
80
|
-
"""
|
|
81
|
-
Prepare for drawing a new frame (e.g. clear screen).
|
|
82
|
-
"""
|
|
92
|
+
"""Begin a new rendering frame."""
|
|
83
93
|
|
|
84
94
|
def end_frame(self):
|
|
85
|
-
"""
|
|
86
|
-
Present the frame to the user (swap buffers).
|
|
87
|
-
"""
|
|
95
|
+
"""End the current rendering frame."""
|
|
88
96
|
|
|
89
|
-
|
|
90
|
-
# pylint: disable=too-many-arguments,too-many-positional-arguments
|
|
91
|
-
def draw_rect(
|
|
92
|
-
self,
|
|
93
|
-
x: int,
|
|
94
|
-
y: int,
|
|
95
|
-
w: int,
|
|
96
|
-
h: int,
|
|
97
|
-
color: Color = (255, 255, 255),
|
|
98
|
-
):
|
|
97
|
+
def draw_rect(self, x: int, y: int, w: int, h: int, color=(255, 255, 255)):
|
|
99
98
|
"""
|
|
100
|
-
Draw a filled rectangle
|
|
101
|
-
We'll keep this minimal for now; later we can extend with colors/sprites.
|
|
99
|
+
Draw a filled rectangle.
|
|
102
100
|
|
|
103
|
-
:param x:
|
|
101
|
+
:param x: The x-coordinate of the rectangle.
|
|
104
102
|
:type x: int
|
|
105
|
-
|
|
106
|
-
:param y: Y position of the rectangle's top-left corner.
|
|
103
|
+
:param y: The y-coordinate of the rectangle.
|
|
107
104
|
:type y: int
|
|
108
|
-
|
|
109
|
-
:param w: Width of the rectangle.
|
|
105
|
+
:param w: The width of the rectangle.
|
|
110
106
|
:type w: int
|
|
111
|
-
|
|
112
|
-
:param h: Height of the rectangle.
|
|
107
|
+
:param h: The height of the rectangle.
|
|
113
108
|
:type h: int
|
|
114
|
-
|
|
115
|
-
:
|
|
116
|
-
:type color: Color
|
|
109
|
+
:param color: The color of the rectangle as an (R, G, B) or (R, G, B, A) tuple.
|
|
110
|
+
:type color: tuple[int, int, int] | tuple[int, int, int, int]
|
|
117
111
|
"""
|
|
118
112
|
|
|
119
|
-
def
|
|
120
|
-
self,
|
|
121
|
-
x: int,
|
|
122
|
-
y: int,
|
|
123
|
-
text: str,
|
|
124
|
-
color: Color = (255, 255, 255),
|
|
125
|
-
font_size: int | None = None,
|
|
113
|
+
def draw_line(
|
|
114
|
+
self, x1: int, y1: int, x2: int, y2: int, color=(255, 255, 255)
|
|
126
115
|
):
|
|
127
116
|
"""
|
|
128
|
-
Draw
|
|
117
|
+
Draw a line between two points.
|
|
129
118
|
|
|
130
|
-
|
|
131
|
-
|
|
119
|
+
:param x1: The x-coordinate of the start point.
|
|
120
|
+
:type x1: int
|
|
121
|
+
:param y1: The y-coordinate of the start point.
|
|
122
|
+
:type y1: int
|
|
123
|
+
:param x2: The x-coordinate of the end point.
|
|
124
|
+
:type x2: int
|
|
125
|
+
:param y2: The y-coordinate of the end point.
|
|
126
|
+
:type y2: int
|
|
127
|
+
:param color: The color of the line as an (R, G, B) or (R, G, B, A) tuple.
|
|
128
|
+
:type color: tuple[int, int, int] | tuple[int, int, int, int]
|
|
129
|
+
"""
|
|
132
130
|
|
|
133
|
-
|
|
134
|
-
|
|
131
|
+
def set_clip_rect(self, x: int, y: int, w: int, h: int):
|
|
132
|
+
"""
|
|
133
|
+
Set the clipping rectangle.
|
|
135
134
|
|
|
136
|
-
:param
|
|
135
|
+
:param x: The x-coordinate of the clipping rectangle.
|
|
136
|
+
:type x: int
|
|
137
|
+
:param y: The y-coordinate of the clipping rectangle.
|
|
137
138
|
:type y: int
|
|
139
|
+
:param w: The width of the clipping rectangle.
|
|
140
|
+
:type w: int
|
|
141
|
+
:param h: The height of the clipping rectangle.
|
|
142
|
+
:type h: int
|
|
143
|
+
"""
|
|
138
144
|
|
|
139
|
-
|
|
140
|
-
|
|
145
|
+
def clear_clip_rect(self):
|
|
146
|
+
"""Clear the clipping rectangle."""
|
|
141
147
|
|
|
142
|
-
:param color: RGB color tuple.
|
|
143
|
-
:type color: Color
|
|
144
|
-
"""
|
|
145
148
|
|
|
146
|
-
|
|
149
|
+
class TextProtocol(Protocol):
|
|
150
|
+
"""
|
|
151
|
+
Interface for text rendering operations.
|
|
152
|
+
"""
|
|
147
153
|
|
|
148
|
-
def
|
|
154
|
+
def measure(
|
|
155
|
+
self, text: str, font_size: int | None = None
|
|
156
|
+
) -> tuple[int, int]:
|
|
149
157
|
"""
|
|
150
|
-
Measure the width and height of the given text
|
|
158
|
+
Measure the width and height of the given text.
|
|
151
159
|
|
|
152
|
-
:param text: The text
|
|
160
|
+
:param text: The text to measure.
|
|
153
161
|
:type text: str
|
|
154
|
-
|
|
155
|
-
:
|
|
162
|
+
:param font_size: The font size to use for measurement.
|
|
163
|
+
:type font_size: int | None
|
|
164
|
+
:return: A tuple containing the width and height of the text.
|
|
156
165
|
:rtype: tuple[int, int]
|
|
157
166
|
"""
|
|
158
|
-
raise NotImplementedError
|
|
159
167
|
|
|
160
|
-
def
|
|
168
|
+
def draw(
|
|
169
|
+
self,
|
|
170
|
+
x: int,
|
|
171
|
+
y: int,
|
|
172
|
+
text: str,
|
|
173
|
+
color=(255, 255, 255),
|
|
174
|
+
font_size: int | None = None,
|
|
175
|
+
):
|
|
176
|
+
"""
|
|
177
|
+
Draw the given text at the specified position.
|
|
178
|
+
|
|
179
|
+
:param x: The x-coordinate to draw the text.
|
|
180
|
+
:type x: int
|
|
181
|
+
:param y: The y-coordinate to draw the text.
|
|
182
|
+
:type y: int
|
|
183
|
+
:param text: The text to draw.
|
|
184
|
+
:type text: str
|
|
185
|
+
:param color: The color of the text as an (R, G, B) or (R, G, B, A) tuple.
|
|
186
|
+
:type color: tuple[int, int, int] | tuple[int, int, int, int]
|
|
187
|
+
:param font_size: The font size to use for drawing.
|
|
188
|
+
:type font_size: int | None
|
|
161
189
|
"""
|
|
162
|
-
Capture the current frame.
|
|
163
|
-
If `path` is provided, save to that file (e.g. PNG).
|
|
164
|
-
Returns raw bytes (PNG) or None if unsupported.
|
|
165
190
|
|
|
166
|
-
:param path: Optional file path to save the screenshot.
|
|
167
|
-
:type path: str | None
|
|
168
191
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
192
|
+
class AudioProtocol(Protocol):
|
|
193
|
+
"""
|
|
194
|
+
Interface for audio operations.
|
|
195
|
+
"""
|
|
173
196
|
|
|
174
|
-
def
|
|
197
|
+
def init(
|
|
175
198
|
self, frequency: int = 44100, channels: int = 2, chunk_size: int = 2048
|
|
176
199
|
):
|
|
177
200
|
"""
|
|
178
|
-
Initialize
|
|
201
|
+
Initialize audio subsystem.
|
|
179
202
|
|
|
180
203
|
:param frequency: Audio frequency in Hz.
|
|
181
204
|
:type frequency: int
|
|
182
|
-
|
|
183
205
|
:param channels: Number of audio channels (1=mono, 2=stereo).
|
|
184
206
|
:type channels: int
|
|
185
|
-
|
|
186
207
|
:param chunk_size: Size of audio chunks.
|
|
187
208
|
:type chunk_size: int
|
|
188
209
|
"""
|
|
189
210
|
|
|
190
|
-
def
|
|
191
|
-
"""
|
|
211
|
+
def shutdown(self):
|
|
212
|
+
"""
|
|
213
|
+
Shutdown the audio subsystem.
|
|
214
|
+
"""
|
|
192
215
|
|
|
193
216
|
def load_sound(self, sound_id: str, path: str):
|
|
194
217
|
"""
|
|
195
|
-
Load a
|
|
196
|
-
Example: backend.load_sound("hit", "assets/sfx/hit.wav")
|
|
218
|
+
Load a sound file.
|
|
197
219
|
|
|
198
220
|
:param sound_id: Unique identifier for the sound.
|
|
199
221
|
:type sound_id: str
|
|
200
|
-
|
|
201
|
-
:param path: File path to the WAV sound.
|
|
222
|
+
:param path: File path to the sound.
|
|
202
223
|
:type path: str
|
|
203
224
|
"""
|
|
204
225
|
|
|
205
226
|
def play_sound(self, sound_id: str, loops: int = 0):
|
|
206
227
|
"""
|
|
207
228
|
Play a loaded sound.
|
|
208
|
-
loops=0 => play once
|
|
209
|
-
loops=-1 => infinite loop
|
|
210
|
-
loops=1 => play twice (SDL convention)
|
|
211
229
|
|
|
212
230
|
:param sound_id: Unique identifier for the sound.
|
|
213
231
|
:type sound_id: str
|
|
214
|
-
|
|
215
232
|
:param loops: Number of times to loop the sound.
|
|
216
233
|
:type loops: int
|
|
217
234
|
"""
|
|
218
235
|
|
|
219
236
|
def set_master_volume(self, volume: int):
|
|
220
237
|
"""
|
|
221
|
-
|
|
238
|
+
Set the master volume.
|
|
239
|
+
|
|
240
|
+
:param volume: Volume level (0-128).
|
|
241
|
+
:type volume: int
|
|
222
242
|
"""
|
|
223
243
|
|
|
224
244
|
def set_sound_volume(self, sound_id: str, volume: int):
|
|
225
245
|
"""
|
|
226
|
-
|
|
246
|
+
Set volume for a specific sound.
|
|
227
247
|
|
|
228
248
|
:param sound_id: Unique identifier for the sound.
|
|
229
249
|
:type sound_id: str
|
|
230
|
-
|
|
231
250
|
:param volume: Volume level (0-128).
|
|
232
251
|
:type volume: int
|
|
233
252
|
"""
|
|
234
253
|
|
|
235
|
-
def
|
|
236
|
-
"""Stop all channels."""
|
|
237
|
-
|
|
238
|
-
def set_viewport_transform(
|
|
239
|
-
self, offset_x: int, offset_y: int, scale: float
|
|
240
|
-
):
|
|
254
|
+
def stop_all(self):
|
|
241
255
|
"""
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
:param offset_x: X offset in pixels.
|
|
245
|
-
:type offset_x: int
|
|
246
|
-
|
|
247
|
-
:param offset_y: Y offset in pixels.
|
|
248
|
-
:type offset_y: int
|
|
249
|
-
|
|
250
|
-
:param scale: Scale factor.
|
|
251
|
-
:type scale: float
|
|
256
|
+
Stop all currently playing sounds.
|
|
252
257
|
"""
|
|
253
|
-
raise NotImplementedError
|
|
254
258
|
|
|
255
|
-
def clear_viewport_transform(self):
|
|
256
|
-
"""Reset any viewport transform back to identity."""
|
|
257
|
-
raise NotImplementedError
|
|
258
|
-
|
|
259
|
-
def resize_window(self, width: int, height: int):
|
|
260
|
-
"""
|
|
261
|
-
Resize the actual OS window (SDL_SetWindowSize in native backend).
|
|
262
259
|
|
|
263
|
-
|
|
264
|
-
|
|
260
|
+
class CaptureProtocol(Protocol):
|
|
261
|
+
"""
|
|
262
|
+
Interface for frame capture operations.
|
|
263
|
+
"""
|
|
265
264
|
|
|
266
|
-
|
|
267
|
-
:type height: int
|
|
265
|
+
def bmp(self, path: str | None = None) -> bool:
|
|
268
266
|
"""
|
|
269
|
-
|
|
267
|
+
Capture the current frame as a BMP file.
|
|
270
268
|
|
|
271
|
-
|
|
269
|
+
:param path: Optional file path to save the BMP. If None, returns bytes.
|
|
270
|
+
:type path: str | None
|
|
271
|
+
:return: Whether the capture was successful.
|
|
272
|
+
:rtype: bool
|
|
272
273
|
"""
|
|
273
|
-
Set a clipping rectangle for rendering.
|
|
274
274
|
|
|
275
|
-
:param x: X position of the rectangle's top-left corner.
|
|
276
|
-
:type x: int
|
|
277
275
|
|
|
278
|
-
|
|
279
|
-
|
|
276
|
+
# TODO: Refactor backend interface into smaller protocols?
|
|
277
|
+
# Justification: Many public methods needed for backend interface
|
|
278
|
+
# pylint: disable=too-many-public-methods
|
|
279
|
+
class Backend(Protocol):
|
|
280
|
+
"""
|
|
281
|
+
Interface that any rendering/input backend must implement.
|
|
282
|
+
mini-arcade-core only talks to this protocol, never to SDL/pygame directly.
|
|
280
283
|
|
|
281
|
-
|
|
282
|
-
|
|
284
|
+
:ivar window (WindowProtocol): Window management interface.
|
|
285
|
+
:ivar audio (AudioProtocol): Audio management interface.
|
|
286
|
+
:ivar input (InputProtocol): Input management interface.
|
|
287
|
+
:ivar render (RenderProtocol): Rendering interface.
|
|
288
|
+
:ivar text (TextProtocol): Text rendering interface.
|
|
289
|
+
:ivar capture (CaptureProtocol): Frame capture interface.
|
|
290
|
+
"""
|
|
283
291
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
292
|
+
window: WindowProtocol
|
|
293
|
+
audio: AudioProtocol
|
|
294
|
+
input: InputProtocol
|
|
295
|
+
render: RenderProtocol
|
|
296
|
+
text: TextProtocol
|
|
297
|
+
capture: CaptureProtocol
|
|
288
298
|
|
|
289
|
-
def
|
|
290
|
-
"""
|
|
291
|
-
|
|
299
|
+
def init(self):
|
|
300
|
+
"""
|
|
301
|
+
Initialize the backend and open a window.
|
|
302
|
+
Should be called once before the main loop.
|
|
303
|
+
"""
|
|
292
304
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
def draw_line(
|
|
296
|
-
self,
|
|
297
|
-
x1: int,
|
|
298
|
-
y1: int,
|
|
299
|
-
x2: int,
|
|
300
|
-
y2: int,
|
|
301
|
-
color: tuple[int, ...] = (255, 255, 255),
|
|
305
|
+
def set_viewport_transform(
|
|
306
|
+
self, offset_x: int, offset_y: int, scale: float
|
|
302
307
|
):
|
|
303
308
|
"""
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
:param x1: X position of the start point.
|
|
307
|
-
:type x1: int
|
|
308
|
-
|
|
309
|
-
:param y1: Y position of the start point.
|
|
310
|
-
:type y1: int
|
|
311
|
-
|
|
312
|
-
:param x2: X position of the end point.
|
|
313
|
-
:type x2: int
|
|
309
|
+
Set the viewport transformation.
|
|
314
310
|
|
|
315
|
-
:param
|
|
316
|
-
:type
|
|
317
|
-
|
|
318
|
-
:
|
|
319
|
-
:
|
|
311
|
+
:param offset_x: Horizontal offset.
|
|
312
|
+
:type offset_x: int
|
|
313
|
+
:param offset_y: Vertical offset.
|
|
314
|
+
:type offset_y: int
|
|
315
|
+
:param scale: Scaling factor.
|
|
316
|
+
:type scale: float
|
|
320
317
|
"""
|
|
321
|
-
raise NotImplementedError
|
|
322
318
|
|
|
323
|
-
|
|
324
|
-
|
|
319
|
+
def clear_viewport_transform(self):
|
|
320
|
+
"""
|
|
321
|
+
Clear the viewport transformation (reset to defaults).
|
|
322
|
+
"""
|
|
@@ -6,4 +6,8 @@ from __future__ import annotations
|
|
|
6
6
|
|
|
7
7
|
from typing import Tuple, Union
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
ColorRGB = Tuple[int, int, int]
|
|
10
|
+
ColorRGBA = Tuple[int, int, int, int]
|
|
11
|
+
|
|
12
|
+
Color = Union[ColorRGB, ColorRGBA]
|
|
13
|
+
Alpha = Union[float, int]
|