mini-arcade-core 0.9.5__py3-none-any.whl → 0.9.7__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 -19
- mini_arcade_core/backend/__init__.py +18 -0
- mini_arcade_core/{backend.py → backend/backend.py} +3 -93
- mini_arcade_core/backend/events.py +98 -0
- mini_arcade_core/backend/types.py +9 -0
- mini_arcade_core/entity.py +6 -3
- mini_arcade_core/game.py +36 -7
- mini_arcade_core/keymaps/__init__.py +15 -0
- mini_arcade_core/keymaps/sdl.py +46 -43
- mini_arcade_core/scenes/__init__.py +12 -0
- mini_arcade_core/{autoreg.py → scenes/autoreg.py} +9 -2
- mini_arcade_core/{registry.py → scenes/registry.py} +1 -1
- mini_arcade_core/{scene.py → scenes/scene.py} +7 -5
- mini_arcade_core/two_d/__init__.py +30 -0
- mini_arcade_core/{collision2d.py → two_d/collision2d.py} +1 -1
- mini_arcade_core/{kinematics2d.py → two_d/kinematics2d.py} +2 -1
- mini_arcade_core/ui/__init__.py +14 -0
- mini_arcade_core/ui/menu.py +31 -8
- {mini_arcade_core-0.9.5.dist-info → mini_arcade_core-0.9.7.dist-info}/METADATA +1 -1
- mini_arcade_core-0.9.7.dist-info/RECORD +26 -0
- mini_arcade_core-0.9.5.dist-info/RECORD +0 -21
- /mini_arcade_core/{keys.py → keymaps/keys.py} +0 -0
- /mini_arcade_core/{boundaries2d.py → two_d/boundaries2d.py} +0 -0
- /mini_arcade_core/{geometry2d.py → two_d/geometry2d.py} +0 -0
- /mini_arcade_core/{physics2d.py → two_d/physics2d.py} +0 -0
- {mini_arcade_core-0.9.5.dist-info → mini_arcade_core-0.9.7.dist-info}/WHEEL +0 -0
- {mini_arcade_core-0.9.5.dist-info → mini_arcade_core-0.9.7.dist-info}/licenses/LICENSE +0 -0
mini_arcade_core/__init__.py
CHANGED
|
@@ -7,52 +7,77 @@ from __future__ import annotations
|
|
|
7
7
|
|
|
8
8
|
import logging
|
|
9
9
|
from importlib.metadata import PackageNotFoundError, version
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
from .backend import Backend, Event, EventType
|
|
13
|
-
from .
|
|
10
|
+
from typing import Callable, Type, Union
|
|
11
|
+
|
|
12
|
+
from mini_arcade_core.backend import Backend, Event, EventType
|
|
13
|
+
from mini_arcade_core.entity import Entity, KinematicEntity, SpriteEntity
|
|
14
|
+
from mini_arcade_core.game import Game, GameConfig
|
|
15
|
+
from mini_arcade_core.keymaps.keys import Key, keymap
|
|
16
|
+
from mini_arcade_core.scenes import Scene, SceneRegistry, register_scene
|
|
17
|
+
from mini_arcade_core.two_d import (
|
|
18
|
+
Bounds2D,
|
|
19
|
+
KinematicData,
|
|
20
|
+
Position2D,
|
|
21
|
+
RectCollider,
|
|
14
22
|
RectKinematic,
|
|
15
23
|
RectSprite,
|
|
24
|
+
Size2D,
|
|
25
|
+
Velocity2D,
|
|
16
26
|
VerticalBounce,
|
|
17
27
|
VerticalWrap,
|
|
18
28
|
)
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
from .game import Game, GameConfig
|
|
22
|
-
from .geometry2d import Bounds2D, Position2D, Size2D
|
|
23
|
-
from .keys import Key, keymap
|
|
24
|
-
from .kinematics2d import KinematicData
|
|
25
|
-
from .physics2d import Velocity2D
|
|
26
|
-
from .registry import SceneRegistry
|
|
27
|
-
from .scene import Scene
|
|
29
|
+
|
|
30
|
+
SceneFactoryLike = Union[Type[Scene], Callable[[Game], Scene]]
|
|
28
31
|
|
|
29
32
|
logger = logging.getLogger(__name__)
|
|
30
33
|
|
|
31
34
|
|
|
32
35
|
def run_game(
|
|
33
|
-
|
|
36
|
+
scene: SceneFactoryLike | None = None,
|
|
34
37
|
config: GameConfig | None = None,
|
|
35
38
|
registry: SceneRegistry | None = None,
|
|
39
|
+
initial_scene: str = "main",
|
|
36
40
|
):
|
|
37
41
|
"""
|
|
38
42
|
Convenience helper to bootstrap and run a game with a single scene.
|
|
39
43
|
|
|
40
|
-
|
|
41
|
-
|
|
44
|
+
Supports both:
|
|
45
|
+
- run_game(SceneClass, cfg) # legacy
|
|
46
|
+
- run_game(config=cfg, initial_scene="main", registry=...) # registry-based
|
|
47
|
+
- run_game(cfg) # config-only
|
|
48
|
+
|
|
49
|
+
:param initial_scene: The Scene ID to start the game with.
|
|
50
|
+
:type initial_scene: str
|
|
42
51
|
|
|
43
52
|
:param config: Optional GameConfig to customize game settings.
|
|
44
53
|
:type config: GameConfig | None
|
|
45
54
|
|
|
55
|
+
:param registry: Optional SceneRegistry for scene management.
|
|
56
|
+
:type registry: SceneRegistry | None
|
|
57
|
+
|
|
46
58
|
:raises ValueError: If the provided config does not have a valid Backend.
|
|
47
59
|
"""
|
|
60
|
+
# Handle run_game(cfg) where the first arg is actually a GameConfig
|
|
61
|
+
if isinstance(scene, GameConfig) and config is None:
|
|
62
|
+
config = scene
|
|
63
|
+
scene = None
|
|
64
|
+
|
|
48
65
|
cfg = config or GameConfig()
|
|
49
|
-
if
|
|
66
|
+
if cfg.backend is None:
|
|
50
67
|
raise ValueError(
|
|
51
68
|
"GameConfig.backend must be set to a Backend instance"
|
|
52
69
|
)
|
|
70
|
+
|
|
71
|
+
# If user provided a Scene factory/class, ensure it's registered
|
|
72
|
+
if scene is not None:
|
|
73
|
+
if registry is None:
|
|
74
|
+
registry = SceneRegistry(_factories={})
|
|
75
|
+
registry.register(
|
|
76
|
+
initial_scene, scene
|
|
77
|
+
) # Scene class is callable(game) -> Scene
|
|
78
|
+
|
|
53
79
|
game = Game(cfg, registry=registry)
|
|
54
|
-
|
|
55
|
-
game.run(scene)
|
|
80
|
+
game.run(initial_scene)
|
|
56
81
|
|
|
57
82
|
|
|
58
83
|
__all__ = [
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Backend module for rendering and input abstraction.
|
|
3
|
+
Defines the Backend interface and related types.
|
|
4
|
+
This is the only part of the code that talks to SDL/pygame directly.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from .backend import Backend
|
|
10
|
+
from .events import Event, EventType
|
|
11
|
+
from .types import Color
|
|
12
|
+
|
|
13
|
+
__all__ = [
|
|
14
|
+
"Backend",
|
|
15
|
+
"Event",
|
|
16
|
+
"EventType",
|
|
17
|
+
"Color",
|
|
18
|
+
]
|
|
@@ -5,100 +5,10 @@ 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
|
|
9
|
-
from enum import Enum, auto
|
|
10
|
-
from typing import Iterable, Optional, Protocol, Tuple, Union
|
|
8
|
+
from typing import Iterable, Protocol
|
|
11
9
|
|
|
12
|
-
from .
|
|
13
|
-
|
|
14
|
-
Color = Union[Tuple[int, int, int], Tuple[int, int, int, int]]
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
class EventType(Enum):
|
|
18
|
-
"""
|
|
19
|
-
High-level event types understood by the core.
|
|
20
|
-
|
|
21
|
-
:cvar UNKNOWN: Unknown/unhandled event.
|
|
22
|
-
:cvar QUIT: User requested to quit the game.
|
|
23
|
-
:cvar KEYDOWN: A key was pressed.
|
|
24
|
-
:cvar KEYUP: A key was released.
|
|
25
|
-
:cvar MOUSEMOTION: The mouse was moved.
|
|
26
|
-
:cvar MOUSEBUTTONDOWN: A mouse button was pressed.
|
|
27
|
-
:cvar MOUSEBUTTONUP: A mouse button was released.
|
|
28
|
-
:cvar MOUSEWHEEL: The mouse wheel was scrolled.
|
|
29
|
-
:cvar WINDOWRESIZED: The window was resized.
|
|
30
|
-
:cvar TEXTINPUT: Text input event (for IME support).
|
|
31
|
-
"""
|
|
32
|
-
|
|
33
|
-
UNKNOWN = auto()
|
|
34
|
-
QUIT = auto()
|
|
35
|
-
|
|
36
|
-
KEYDOWN = auto()
|
|
37
|
-
KEYUP = auto()
|
|
38
|
-
|
|
39
|
-
# Mouse
|
|
40
|
-
MOUSEMOTION = auto()
|
|
41
|
-
MOUSEBUTTONDOWN = auto()
|
|
42
|
-
MOUSEBUTTONUP = auto()
|
|
43
|
-
MOUSEWHEEL = auto()
|
|
44
|
-
|
|
45
|
-
# Window / text
|
|
46
|
-
WINDOWRESIZED = auto()
|
|
47
|
-
TEXTINPUT = auto()
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
# Justification: Simple data container for now
|
|
51
|
-
# pylint: disable=too-many-instance-attributes
|
|
52
|
-
@dataclass(frozen=True)
|
|
53
|
-
class Event:
|
|
54
|
-
"""
|
|
55
|
-
Core event type.
|
|
56
|
-
|
|
57
|
-
For now we only care about:
|
|
58
|
-
- type: what happened
|
|
59
|
-
- key: integer key code (e.g. ESC = 27), or None if not applicable
|
|
60
|
-
|
|
61
|
-
:ivar type (EventType): The type of event.
|
|
62
|
-
:ivar key (Key | None): The key associated with the event, if any.
|
|
63
|
-
:ivar key_code (int | None): The key code associated with the event, if any.
|
|
64
|
-
:ivar scancode (int | None): The hardware scancode of the key, if any.
|
|
65
|
-
:ivar mod (int | None): Modifier keys bitmask, if any.
|
|
66
|
-
:ivar repeat (bool | None): Whether this key event is a repeat, if any.
|
|
67
|
-
:ivar x (int | None): Mouse X position, if any.
|
|
68
|
-
:ivar y (int | None): Mouse Y position, if any.
|
|
69
|
-
:ivar dx (int | None): Mouse delta X, if any.
|
|
70
|
-
:ivar dy (int | None): Mouse delta Y, if any.
|
|
71
|
-
:ivar button (int | None): Mouse button number, if any.
|
|
72
|
-
:ivar wheel (Tuple[int, int] | None): Mouse wheel scroll (x, y), if any.
|
|
73
|
-
:ivar size (Tuple[int, int] | None): New window size (width, height), if any.
|
|
74
|
-
:ivar text (str | None): Text input, if any.
|
|
75
|
-
"""
|
|
76
|
-
|
|
77
|
-
type: EventType
|
|
78
|
-
key: Key | None = None # Use Key enum for better clarity
|
|
79
|
-
key_code: Optional[int] = None
|
|
80
|
-
|
|
81
|
-
# Keyboard extras (optional)
|
|
82
|
-
scancode: Optional[int] = None
|
|
83
|
-
mod: Optional[int] = None
|
|
84
|
-
repeat: Optional[bool] = None
|
|
85
|
-
|
|
86
|
-
# Mouse (optional)
|
|
87
|
-
x: Optional[int] = None
|
|
88
|
-
y: Optional[int] = None
|
|
89
|
-
dx: Optional[int] = None
|
|
90
|
-
dy: Optional[int] = None
|
|
91
|
-
button: Optional[int] = None
|
|
92
|
-
wheel: Optional[Tuple[int, int]] = None # (wheel_x, wheel_y)
|
|
93
|
-
|
|
94
|
-
# Window (optional)
|
|
95
|
-
size: Optional[Tuple[int, int]] = None # (width, height)
|
|
96
|
-
|
|
97
|
-
# Text input (optional)
|
|
98
|
-
text: Optional[str] = None
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
# pylint: enable=too-many-instance-attributes
|
|
10
|
+
from .events import Event
|
|
11
|
+
from .types import Color
|
|
102
12
|
|
|
103
13
|
|
|
104
14
|
class Backend(Protocol):
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Core event types and structures.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
from dataclasses import dataclass
|
|
8
|
+
from enum import Enum, auto
|
|
9
|
+
from typing import Optional, Tuple
|
|
10
|
+
|
|
11
|
+
from mini_arcade_core.keymaps.keys import Key
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class EventType(Enum):
|
|
15
|
+
"""
|
|
16
|
+
High-level event types understood by the core.
|
|
17
|
+
|
|
18
|
+
:cvar UNKNOWN: Unknown/unhandled event.
|
|
19
|
+
:cvar QUIT: User requested to quit the game.
|
|
20
|
+
:cvar KEYDOWN: A key was pressed.
|
|
21
|
+
:cvar KEYUP: A key was released.
|
|
22
|
+
:cvar MOUSEMOTION: The mouse was moved.
|
|
23
|
+
:cvar MOUSEBUTTONDOWN: A mouse button was pressed.
|
|
24
|
+
:cvar MOUSEBUTTONUP: A mouse button was released.
|
|
25
|
+
:cvar MOUSEWHEEL: The mouse wheel was scrolled.
|
|
26
|
+
:cvar WINDOWRESIZED: The window was resized.
|
|
27
|
+
:cvar TEXTINPUT: Text input event (for IME support).
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
UNKNOWN = auto()
|
|
31
|
+
QUIT = auto()
|
|
32
|
+
|
|
33
|
+
KEYDOWN = auto()
|
|
34
|
+
KEYUP = auto()
|
|
35
|
+
|
|
36
|
+
# Mouse
|
|
37
|
+
MOUSEMOTION = auto()
|
|
38
|
+
MOUSEBUTTONDOWN = auto()
|
|
39
|
+
MOUSEBUTTONUP = auto()
|
|
40
|
+
MOUSEWHEEL = auto()
|
|
41
|
+
|
|
42
|
+
# Window / text
|
|
43
|
+
WINDOWRESIZED = auto()
|
|
44
|
+
TEXTINPUT = auto()
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
# Justification: Simple data container for now
|
|
48
|
+
# pylint: disable=too-many-instance-attributes
|
|
49
|
+
@dataclass(frozen=True)
|
|
50
|
+
class Event:
|
|
51
|
+
"""
|
|
52
|
+
Core event type.
|
|
53
|
+
|
|
54
|
+
For now we only care about:
|
|
55
|
+
- type: what happened
|
|
56
|
+
- key: integer key code (e.g. ESC = 27), or None if not applicable
|
|
57
|
+
|
|
58
|
+
:ivar type (EventType): The type of event.
|
|
59
|
+
:ivar key (Key | None): The key associated with the event, if any.
|
|
60
|
+
:ivar key_code (int | None): The key code associated with the event, if any.
|
|
61
|
+
:ivar scancode (int | None): The hardware scancode of the key, if any.
|
|
62
|
+
:ivar mod (int | None): Modifier keys bitmask, if any.
|
|
63
|
+
:ivar repeat (bool | None): Whether this key event is a repeat, if any.
|
|
64
|
+
:ivar x (int | None): Mouse X position, if any.
|
|
65
|
+
:ivar y (int | None): Mouse Y position, if any.
|
|
66
|
+
:ivar dx (int | None): Mouse delta X, if any.
|
|
67
|
+
:ivar dy (int | None): Mouse delta Y, if any.
|
|
68
|
+
:ivar button (int | None): Mouse button number, if any.
|
|
69
|
+
:ivar wheel (Tuple[int, int] | None): Mouse wheel scroll (x, y), if any.
|
|
70
|
+
:ivar size (Tuple[int, int] | None): New window size (width, height), if any.
|
|
71
|
+
:ivar text (str | None): Text input, if any.
|
|
72
|
+
"""
|
|
73
|
+
|
|
74
|
+
type: EventType
|
|
75
|
+
key: Key | None = None # Use Key enum for better clarity
|
|
76
|
+
key_code: Optional[int] = None
|
|
77
|
+
|
|
78
|
+
# Keyboard extras (optional)
|
|
79
|
+
scancode: Optional[int] = None
|
|
80
|
+
mod: Optional[int] = None
|
|
81
|
+
repeat: Optional[bool] = None
|
|
82
|
+
|
|
83
|
+
# Mouse (optional)
|
|
84
|
+
x: Optional[int] = None
|
|
85
|
+
y: Optional[int] = None
|
|
86
|
+
dx: Optional[int] = None
|
|
87
|
+
dy: Optional[int] = None
|
|
88
|
+
button: Optional[int] = None
|
|
89
|
+
wheel: Optional[Tuple[int, int]] = None # (wheel_x, wheel_y)
|
|
90
|
+
|
|
91
|
+
# Window (optional)
|
|
92
|
+
size: Optional[Tuple[int, int]] = None # (width, height)
|
|
93
|
+
|
|
94
|
+
# Text input (optional)
|
|
95
|
+
text: Optional[str] = None
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
# pylint: enable=too-many-instance-attributes
|
mini_arcade_core/entity.py
CHANGED
|
@@ -6,9 +6,12 @@ from __future__ import annotations
|
|
|
6
6
|
|
|
7
7
|
from typing import Any
|
|
8
8
|
|
|
9
|
-
from .
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
from mini_arcade_core.two_d import (
|
|
10
|
+
KinematicData,
|
|
11
|
+
Position2D,
|
|
12
|
+
RectCollider,
|
|
13
|
+
Size2D,
|
|
14
|
+
)
|
|
12
15
|
|
|
13
16
|
|
|
14
17
|
class Entity:
|
mini_arcade_core/game.py
CHANGED
|
@@ -9,15 +9,15 @@ from dataclasses import dataclass
|
|
|
9
9
|
from datetime import datetime
|
|
10
10
|
from pathlib import Path
|
|
11
11
|
from time import perf_counter, sleep
|
|
12
|
-
from typing import TYPE_CHECKING, Union
|
|
12
|
+
from typing import TYPE_CHECKING, Literal, Union
|
|
13
13
|
|
|
14
14
|
from PIL import Image # type: ignore[import]
|
|
15
15
|
|
|
16
|
-
from .backend import Backend
|
|
17
|
-
from .
|
|
16
|
+
from mini_arcade_core.backend import Backend
|
|
17
|
+
from mini_arcade_core.scenes import SceneRegistry
|
|
18
18
|
|
|
19
19
|
if TYPE_CHECKING: # avoid runtime circular import
|
|
20
|
-
from .
|
|
20
|
+
from mini_arcade_core.scenes import Scene
|
|
21
21
|
|
|
22
22
|
SceneOrId = Union["Scene", str]
|
|
23
23
|
|
|
@@ -43,6 +43,20 @@ class GameConfig:
|
|
|
43
43
|
backend: Backend | None = None
|
|
44
44
|
|
|
45
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
|
+
|
|
46
60
|
@dataclass
|
|
47
61
|
class _StackEntry:
|
|
48
62
|
scene: "Scene"
|
|
@@ -59,6 +73,9 @@ class Game:
|
|
|
59
73
|
:param config: Game configuration options.
|
|
60
74
|
:type config: GameConfig
|
|
61
75
|
|
|
76
|
+
:param registry: Optional SceneRegistry for scene management.
|
|
77
|
+
:type registry: SceneRegistry | None
|
|
78
|
+
|
|
62
79
|
:raises ValueError: If the provided config does not have a valid Backend.
|
|
63
80
|
"""
|
|
64
81
|
self.config = config
|
|
@@ -72,6 +89,7 @@ class Game:
|
|
|
72
89
|
self.backend: Backend = config.backend
|
|
73
90
|
self.registry = registry or SceneRegistry(_factories={})
|
|
74
91
|
self._scene_stack: list[_StackEntry] = []
|
|
92
|
+
self.settings = GameSettings()
|
|
75
93
|
|
|
76
94
|
def current_scene(self) -> "Scene | None":
|
|
77
95
|
"""
|
|
@@ -88,7 +106,7 @@ class Game:
|
|
|
88
106
|
``on_exit``/``on_enter`` appropriately.
|
|
89
107
|
|
|
90
108
|
:param scene: The new scene to activate.
|
|
91
|
-
:type scene:
|
|
109
|
+
:type scene: SceneOrId
|
|
92
110
|
"""
|
|
93
111
|
scene = self._resolve_scene(scene)
|
|
94
112
|
|
|
@@ -103,6 +121,12 @@ class Game:
|
|
|
103
121
|
"""
|
|
104
122
|
Push a scene on top of the current one.
|
|
105
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
|
|
106
130
|
"""
|
|
107
131
|
scene = self._resolve_scene(scene)
|
|
108
132
|
|
|
@@ -116,7 +140,12 @@ class Game:
|
|
|
116
140
|
scene.on_enter()
|
|
117
141
|
|
|
118
142
|
def pop_scene(self) -> "Scene | None":
|
|
119
|
-
"""
|
|
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
|
+
"""
|
|
120
149
|
if not self._scene_stack:
|
|
121
150
|
return None
|
|
122
151
|
|
|
@@ -160,7 +189,7 @@ class Game:
|
|
|
160
189
|
or another backend.
|
|
161
190
|
|
|
162
191
|
:param initial_scene: The scene to start the game with.
|
|
163
|
-
:type initial_scene:
|
|
192
|
+
:type initial_scene: SceneOrId
|
|
164
193
|
"""
|
|
165
194
|
backend = self.backend
|
|
166
195
|
backend.init(self.config.width, self.config.height, self.config.title)
|
|
@@ -0,0 +1,15 @@
|
|
|
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
|
+
]
|
mini_arcade_core/keymaps/sdl.py
CHANGED
|
@@ -1,36 +1,39 @@
|
|
|
1
1
|
"""
|
|
2
2
|
SDL keymap for mini arcade core.
|
|
3
3
|
Maps SDL keycodes to mini arcade core Key enums.
|
|
4
|
+
|
|
5
|
+
:cvar SDL_KEYCODE_TO_KEY: dict[int, Key]
|
|
6
|
+
Mapping from SDL keycodes to Key enums.
|
|
4
7
|
"""
|
|
5
8
|
|
|
6
9
|
from __future__ import annotations
|
|
7
10
|
|
|
8
|
-
from mini_arcade_core.keys import Key
|
|
11
|
+
from mini_arcade_core.keymaps.keys import Key
|
|
9
12
|
|
|
10
13
|
# SDL keycodes you need (minimal set)
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
_SDLK_ESCAPE = 27
|
|
15
|
+
_SDLK_RETURN = 13
|
|
16
|
+
_SDLK_SPACE = 32
|
|
17
|
+
_SDLK_TAB = 9
|
|
18
|
+
_SDLK_BACKSPACE = 8
|
|
16
19
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
20
|
+
_SDLK_UP = 1073741906
|
|
21
|
+
_SDLK_DOWN = 1073741905
|
|
22
|
+
_SDLK_LEFT = 1073741904
|
|
23
|
+
_SDLK_RIGHT = 1073741903
|
|
21
24
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
25
|
+
_F1 = 1073741882
|
|
26
|
+
_F2 = 1073741883
|
|
27
|
+
_F3 = 1073741884
|
|
28
|
+
_F4 = 1073741885
|
|
29
|
+
_F5 = 1073741886
|
|
30
|
+
_F6 = 1073741887
|
|
31
|
+
_F7 = 1073741888
|
|
32
|
+
_F8 = 1073741889
|
|
33
|
+
_F9 = 1073741890
|
|
34
|
+
_F10 = 1073741891
|
|
35
|
+
_F11 = 1073741892
|
|
36
|
+
_F12 = 1073741893
|
|
34
37
|
|
|
35
38
|
SDL_KEYCODE_TO_KEY: dict[int, Key] = {
|
|
36
39
|
# Letters
|
|
@@ -61,16 +64,16 @@ SDL_KEYCODE_TO_KEY: dict[int, Key] = {
|
|
|
61
64
|
ord("y"): Key.Y,
|
|
62
65
|
ord("z"): Key.Z,
|
|
63
66
|
# Arrows
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
67
|
+
_SDLK_UP: Key.UP,
|
|
68
|
+
_SDLK_DOWN: Key.DOWN,
|
|
69
|
+
_SDLK_LEFT: Key.LEFT,
|
|
70
|
+
_SDLK_RIGHT: Key.RIGHT,
|
|
68
71
|
# Common
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
72
|
+
_SDLK_ESCAPE: Key.ESCAPE,
|
|
73
|
+
_SDLK_SPACE: Key.SPACE,
|
|
74
|
+
_SDLK_RETURN: Key.ENTER,
|
|
75
|
+
_SDLK_TAB: Key.TAB,
|
|
76
|
+
_SDLK_BACKSPACE: Key.BACKSPACE,
|
|
74
77
|
# Numbers
|
|
75
78
|
ord("0"): Key.NUM_0,
|
|
76
79
|
ord("1"): Key.NUM_1,
|
|
@@ -83,16 +86,16 @@ SDL_KEYCODE_TO_KEY: dict[int, Key] = {
|
|
|
83
86
|
ord("8"): Key.NUM_8,
|
|
84
87
|
ord("9"): Key.NUM_9,
|
|
85
88
|
# Function keys
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
89
|
+
_F1: Key.F1,
|
|
90
|
+
_F2: Key.F2,
|
|
91
|
+
_F3: Key.F3,
|
|
92
|
+
_F4: Key.F4,
|
|
93
|
+
_F5: Key.F5,
|
|
94
|
+
_F6: Key.F6,
|
|
95
|
+
_F7: Key.F7,
|
|
96
|
+
_F8: Key.F8,
|
|
97
|
+
_F9: Key.F9,
|
|
98
|
+
_F10: Key.F10,
|
|
99
|
+
_F11: Key.F11,
|
|
100
|
+
_F12: Key.F12,
|
|
98
101
|
}
|
|
@@ -0,0 +1,12 @@
|
|
|
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
|
|
11
|
+
|
|
12
|
+
__all__ = ["Scene", "register_scene", "SceneRegistry"]
|
|
@@ -8,13 +8,20 @@ from __future__ import annotations
|
|
|
8
8
|
from typing import TYPE_CHECKING, Dict, Type
|
|
9
9
|
|
|
10
10
|
if TYPE_CHECKING:
|
|
11
|
-
from .
|
|
11
|
+
from . import Scene
|
|
12
12
|
|
|
13
13
|
_AUTO: Dict[str, Type["Scene"]] = {}
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
def register_scene(scene_id: str):
|
|
17
|
-
"""
|
|
17
|
+
"""
|
|
18
|
+
Decorator to mark and register a Scene class under an id.
|
|
19
|
+
|
|
20
|
+
:param scene_id: The unique identifier for the Scene class.
|
|
21
|
+
:type scene_id: str
|
|
22
|
+
|
|
23
|
+
:raises ValueError: If the scene_id is already registered.
|
|
24
|
+
"""
|
|
18
25
|
|
|
19
26
|
def deco(cls: Type["Scene"]):
|
|
20
27
|
_AUTO[scene_id] = cls
|
|
@@ -5,12 +5,14 @@ Base class for game scenes (states/screens).
|
|
|
5
5
|
from __future__ import annotations
|
|
6
6
|
|
|
7
7
|
from abc import ABC, abstractmethod
|
|
8
|
-
from typing import Callable, List
|
|
8
|
+
from typing import TYPE_CHECKING, Callable, List
|
|
9
9
|
|
|
10
|
-
from .backend import Backend, Event
|
|
11
|
-
from .entity import Entity
|
|
12
|
-
from .
|
|
13
|
-
|
|
10
|
+
from mini_arcade_core.backend import Backend, Event
|
|
11
|
+
from mini_arcade_core.entity import Entity
|
|
12
|
+
from mini_arcade_core.two_d import Size2D
|
|
13
|
+
|
|
14
|
+
if TYPE_CHECKING:
|
|
15
|
+
from mini_arcade_core.game import Game
|
|
14
16
|
|
|
15
17
|
OverlayFunc = Callable[[Backend], None]
|
|
16
18
|
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Two-dimensional utilities and components for Mini Arcade Core.
|
|
3
|
+
Includes 2D entities, boundaries, and physics.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
from .boundaries2d import (
|
|
9
|
+
RectKinematic,
|
|
10
|
+
RectSprite,
|
|
11
|
+
VerticalBounce,
|
|
12
|
+
VerticalWrap,
|
|
13
|
+
)
|
|
14
|
+
from .collision2d import RectCollider
|
|
15
|
+
from .geometry2d import Bounds2D, Position2D, Size2D
|
|
16
|
+
from .kinematics2d import KinematicData
|
|
17
|
+
from .physics2d import Velocity2D
|
|
18
|
+
|
|
19
|
+
__all__ = [
|
|
20
|
+
"Bounds2D",
|
|
21
|
+
"Position2D",
|
|
22
|
+
"Size2D",
|
|
23
|
+
"KinematicData",
|
|
24
|
+
"Velocity2D",
|
|
25
|
+
"RectCollider",
|
|
26
|
+
"RectKinematic",
|
|
27
|
+
"RectSprite",
|
|
28
|
+
"VerticalBounce",
|
|
29
|
+
"VerticalWrap",
|
|
30
|
+
]
|
|
@@ -46,7 +46,7 @@ class RectCollider:
|
|
|
46
46
|
"""
|
|
47
47
|
OOP collision helper that wraps a Position2D + Size2D pair.
|
|
48
48
|
|
|
49
|
-
It does NOT own the data
|
|
49
|
+
It does NOT own the data - it just points to them. If the
|
|
50
50
|
entity moves (position changes), the collider “sees” it.
|
|
51
51
|
|
|
52
52
|
:ivar position (Position2D): Top-left position of the rectangle.
|
|
@@ -7,7 +7,8 @@ from __future__ import annotations
|
|
|
7
7
|
from dataclasses import dataclass
|
|
8
8
|
from typing import Optional
|
|
9
9
|
|
|
10
|
-
from .backend import Color
|
|
10
|
+
from mini_arcade_core.backend import Color
|
|
11
|
+
|
|
11
12
|
from .geometry2d import Position2D, Size2D
|
|
12
13
|
from .physics2d import Velocity2D
|
|
13
14
|
|
mini_arcade_core/ui/__init__.py
CHANGED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"""
|
|
2
|
+
UI utilities and components for Mini Arcade Core.
|
|
3
|
+
Includes buttons, labels, and layout management.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
from .menu import Menu, MenuItem, MenuStyle
|
|
9
|
+
|
|
10
|
+
__all__ = [
|
|
11
|
+
"Menu",
|
|
12
|
+
"MenuItem",
|
|
13
|
+
"MenuStyle",
|
|
14
|
+
]
|
mini_arcade_core/ui/menu.py
CHANGED
|
@@ -8,7 +8,7 @@ from dataclasses import dataclass
|
|
|
8
8
|
from typing import Callable, Sequence
|
|
9
9
|
|
|
10
10
|
from mini_arcade_core.backend import Backend, Color, Event, EventType
|
|
11
|
-
from mini_arcade_core.
|
|
11
|
+
from mini_arcade_core.two_d import Size2D
|
|
12
12
|
|
|
13
13
|
MenuAction = Callable[[], None]
|
|
14
14
|
|
|
@@ -37,6 +37,28 @@ class MenuStyle:
|
|
|
37
37
|
:ivar normal (Color): Color for unselected items.
|
|
38
38
|
:ivar selected (Color): Color for the selected item.
|
|
39
39
|
:ivar line_height (int): Vertical spacing between items.
|
|
40
|
+
:ivar title_color (Color): Color for the title text.
|
|
41
|
+
:ivar title_spacing (int): Vertical space between title and first item.
|
|
42
|
+
:ivar title_margin_bottom (int): Additional margin below the title.
|
|
43
|
+
:ivar background_color (Color | None): Solid background color for the menu.
|
|
44
|
+
:ivar overlay_color (Color | None): Full-screen overlay color.
|
|
45
|
+
:ivar panel_color (Color | None): Color for the panel behind content.
|
|
46
|
+
:ivar panel_padding_x (int): Horizontal padding inside the panel.
|
|
47
|
+
:ivar panel_padding_y (int): Vertical padding inside the panel.
|
|
48
|
+
:ivar button_enabled (bool): Whether to render items as buttons.
|
|
49
|
+
:ivar button_fill (Color): Fill color for buttons.
|
|
50
|
+
:ivar button_border (Color): Border color for buttons.
|
|
51
|
+
:ivar button_selected_border (Color): Border color for the selected button.
|
|
52
|
+
:ivar button_width (int | None): Fixed width for buttons, or None for auto-fit.
|
|
53
|
+
:ivar button_height (int): Fixed height for buttons.
|
|
54
|
+
:ivar button_gap (int): Vertical gap between buttons.
|
|
55
|
+
:ivar button_padding_x (int): Horizontal padding inside buttons.
|
|
56
|
+
:ivar hint (str | None): Optional hint text to display at the bottom.
|
|
57
|
+
:ivar hint_color (Color): Color for the hint text.
|
|
58
|
+
:ivar hint_margin_bottom (int): Additional margin below the hint text.
|
|
59
|
+
:ivar title_font_size (int): Font size for the title text.
|
|
60
|
+
:ivar hint_font_size (int): Font size for the hint text.
|
|
61
|
+
:ivar item_font_size (int): Font size for the menu items.
|
|
40
62
|
"""
|
|
41
63
|
|
|
42
64
|
normal: Color = (220, 220, 220)
|
|
@@ -98,10 +120,13 @@ class Menu:
|
|
|
98
120
|
):
|
|
99
121
|
"""
|
|
100
122
|
:param items: Sequence of MenuItem instances to display.
|
|
101
|
-
type items: Sequence[MenuItem]
|
|
123
|
+
:type items: Sequence[MenuItem]
|
|
102
124
|
|
|
103
|
-
:param
|
|
104
|
-
:
|
|
125
|
+
:param viewport: Viewport size for the menu's layout and centering.
|
|
126
|
+
:type viewport: Size2D | None
|
|
127
|
+
|
|
128
|
+
:param title: Optional title text for the menu.
|
|
129
|
+
:type title: str | None
|
|
105
130
|
|
|
106
131
|
:param style: Optional MenuStyle for customizing appearance.
|
|
107
132
|
:type style: MenuStyle | None
|
|
@@ -160,10 +185,8 @@ class Menu:
|
|
|
160
185
|
self.select()
|
|
161
186
|
|
|
162
187
|
def _measure_content(self, surface: Backend) -> tuple[int, int, int]:
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
where content is items-only (no padding).
|
|
166
|
-
"""
|
|
188
|
+
# Returns (content_width, content_height, title_height)
|
|
189
|
+
# where content is items-only (no padding)
|
|
167
190
|
if not self.items and not self.title:
|
|
168
191
|
return 0, 0, 0
|
|
169
192
|
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
mini_arcade_core/__init__.py,sha256=Q6N1eJe5W8r3i_G88-WZ90B71P6eFuH-Zk5xw3p7SBs,3650
|
|
2
|
+
mini_arcade_core/backend/__init__.py,sha256=w-6QTUngdIYZuvEU3B8zL-vXyKbyLDVucbt7yKZdLlc,379
|
|
3
|
+
mini_arcade_core/backend/backend.py,sha256=dLXTtLn5qURftWOWOVQd2ouuZmJpbiOl11KMIDRk2us,4026
|
|
4
|
+
mini_arcade_core/backend/events.py,sha256=usn2HTk5-5ZiaU2IjbrNRpEj_4uoaiqfY3qufQLYy0w,2929
|
|
5
|
+
mini_arcade_core/backend/types.py,sha256=SuiwXGNmXCZxfPsww6zj3V_NK7k4jpoCuzMn19afS-g,175
|
|
6
|
+
mini_arcade_core/entity.py,sha256=vDe2v7GajyGaqckBYeD3cjs--pOTFrDNhMIdf7PZsJQ,1759
|
|
7
|
+
mini_arcade_core/game.py,sha256=C8flMXn_DMHWDmr5FVrTey_nUHabwja8wSaialNMcLg,8526
|
|
8
|
+
mini_arcade_core/keymaps/__init__.py,sha256=_5Y5_61XT5TsOhbb6p2EPzvjCNN9hCPoxTgj_TAfBvA,258
|
|
9
|
+
mini_arcade_core/keymaps/keys.py,sha256=LTg20SwLBI3kpPIiTNpq2yBft_QUGj-iNFSNm9M-Fus,3010
|
|
10
|
+
mini_arcade_core/keymaps/sdl.py,sha256=Tb0amkbmYjYkEkYnMZ6i9QWjwXBkEHIm13-gEMUYENM,2060
|
|
11
|
+
mini_arcade_core/scenes/__init__.py,sha256=0zzGFejPZ4CkWHJSkhjRAWA7GbenyZbTGrKOrA5gON4,291
|
|
12
|
+
mini_arcade_core/scenes/autoreg.py,sha256=b4V0jaA65I2hnT2f___rg_pT556OjrtoNjIRdZrXBaI,1009
|
|
13
|
+
mini_arcade_core/scenes/registry.py,sha256=0B3iSvepydwMpELQz8cRaQeAU0pR1Fz9O1YtWshLjQw,3226
|
|
14
|
+
mini_arcade_core/scenes/scene.py,sha256=nAYr-T1RW-7s0a8JrxesJY36iAtpZsA2cqeIZgZWIeU,3962
|
|
15
|
+
mini_arcade_core/two_d/__init__.py,sha256=iWjm39RYDEshxSmiIWyGWa6Qr9O2gnHfOpzrl63FUro,626
|
|
16
|
+
mini_arcade_core/two_d/boundaries2d.py,sha256=H1HkCR1422MkQIEve2DFKvnav4RpvtLx-qTMxzmdDMQ,2610
|
|
17
|
+
mini_arcade_core/two_d/collision2d.py,sha256=jR5bOmqUaedxRzwFoKBgn7k-ozwklB4RP9pUTVk6aUw,1716
|
|
18
|
+
mini_arcade_core/two_d/geometry2d.py,sha256=js791mMpsE_YbEoqtTOsOxNSflvKgSk6VeVKhj9N318,1282
|
|
19
|
+
mini_arcade_core/two_d/kinematics2d.py,sha256=NFMiIzDYqDquyg_EhD7EQBJ_Sz4RncmkEjfls9NwkPs,2102
|
|
20
|
+
mini_arcade_core/two_d/physics2d.py,sha256=qIq86qWVuvcnLIMEPH6xx7XQO4tQhfiMZY6FseuVOR8,1636
|
|
21
|
+
mini_arcade_core/ui/__init__.py,sha256=RmcZXfBFFmL09j_Bo1LHagRjiKYajuySPilIUNjc3KQ,248
|
|
22
|
+
mini_arcade_core/ui/menu.py,sha256=J3hYY46xOHLN65WSet4-cnQU7L5pu48scjLJUW9IkEM,13681
|
|
23
|
+
mini_arcade_core-0.9.7.dist-info/METADATA,sha256=ghW7JHVtzj3xDdaQHOvhHmo0JjtLM5Rqpk0K-05RqOI,8188
|
|
24
|
+
mini_arcade_core-0.9.7.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
|
|
25
|
+
mini_arcade_core-0.9.7.dist-info/licenses/LICENSE,sha256=3lHAuV0584cVS5vAqi2uC6GcsVgxUijvwvtZckyvaZ4,1096
|
|
26
|
+
mini_arcade_core-0.9.7.dist-info/RECORD,,
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
mini_arcade_core/__init__.py,sha256=FC98P5APhgI8NVQcq24uPFMpg0fg4ei_bphZyg6NhLA,2797
|
|
2
|
-
mini_arcade_core/autoreg.py,sha256=hN16LulpKcekP3XV_UniQ6qpRT_RrNj14CAMeCnfa2s,851
|
|
3
|
-
mini_arcade_core/backend.py,sha256=kB666RiMSpFaxVEi0KIOPGjh4cdCPWDs5vz8MdY37G4,6854
|
|
4
|
-
mini_arcade_core/boundaries2d.py,sha256=H1HkCR1422MkQIEve2DFKvnav4RpvtLx-qTMxzmdDMQ,2610
|
|
5
|
-
mini_arcade_core/collision2d.py,sha256=iq800wsoYQNft3SA-W4jeY1wXhbpz2E7IkIorZBI238,1718
|
|
6
|
-
mini_arcade_core/entity.py,sha256=1AuE-_iMJYHxSyG783fsyByKK8Gx4vWWKMCEPjtgHXw,1776
|
|
7
|
-
mini_arcade_core/game.py,sha256=YJD10IePBcZ8qyt1FCIWX9hnm8HhK85QK7J6hDEH1H4,7734
|
|
8
|
-
mini_arcade_core/geometry2d.py,sha256=js791mMpsE_YbEoqtTOsOxNSflvKgSk6VeVKhj9N318,1282
|
|
9
|
-
mini_arcade_core/keymaps/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
10
|
-
mini_arcade_core/keymaps/sdl.py,sha256=lRBvgTfdT7enN0qV7S2ZoLsPAWpaiSHzsyVGDlyTzQA,1924
|
|
11
|
-
mini_arcade_core/keys.py,sha256=LTg20SwLBI3kpPIiTNpq2yBft_QUGj-iNFSNm9M-Fus,3010
|
|
12
|
-
mini_arcade_core/kinematics2d.py,sha256=twBx-1jEwdknIJEyYBUg4VZyAvw1d7pGHaGFd36TPbo,2085
|
|
13
|
-
mini_arcade_core/physics2d.py,sha256=qIq86qWVuvcnLIMEPH6xx7XQO4tQhfiMZY6FseuVOR8,1636
|
|
14
|
-
mini_arcade_core/registry.py,sha256=go3wAu406ZhwocBxmfcgI0Tprg2LXnwcT65_MCMMDX4,3225
|
|
15
|
-
mini_arcade_core/scene.py,sha256=e0E81aHt6saYiGfA-1V2II1yWwcZfvqGTRAv8pZnQtY,3865
|
|
16
|
-
mini_arcade_core/ui/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
17
|
-
mini_arcade_core/ui/menu.py,sha256=LiN1T8YCrigPB4Z6OxNlD0ErL5yAV5skpcAY_bgedKw,12144
|
|
18
|
-
mini_arcade_core-0.9.5.dist-info/METADATA,sha256=pne74vBWZlG2YYVJevZequ1T-MnTC_VZal9tRuYaKnM,8188
|
|
19
|
-
mini_arcade_core-0.9.5.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
|
|
20
|
-
mini_arcade_core-0.9.5.dist-info/licenses/LICENSE,sha256=3lHAuV0584cVS5vAqi2uC6GcsVgxUijvwvtZckyvaZ4,1096
|
|
21
|
-
mini_arcade_core-0.9.5.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|