mini-arcade-core 0.9.5__py3-none-any.whl → 0.9.6__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.
@@ -1,6 +1,35 @@
1
1
  """
2
2
  Entry point for the mini_arcade_core package.
3
3
  Provides access to core classes and a convenience function to run a game.
4
+
5
+ mini_arcade_core/
6
+ |-- __init__.py # main entry point
7
+ |-- game.py # core game loop and management
8
+ |-- entity.py # base entity classes
9
+ |-- backend/ # backend abstraction layer
10
+ | |-- __init__.py
11
+ | |-- backend.py # abstract Backend class
12
+ | |-- events.py # event definitions
13
+ | |-- types.py # common types like Color
14
+ |-- keymaps/ # key mapping utilities
15
+ | |-- __init__.py
16
+ | |-- keys.py # key definitions and keymaps
17
+ | |-- sdl.py # SDL keycode mappings
18
+ |-- scenes/ # scene management
19
+ | |-- __init__.py
20
+ | |-- autoreg.py # automatic scene registration
21
+ | |-- registry.py # SceneRegistry class
22
+ | |-- scene.py # base Scene class
23
+ |-- two_d/ # 2D utilities and types
24
+ | |-- __init__.py
25
+ | |-- boundaries2d.py # boundary behaviors
26
+ | |-- collision2d.py # collision detection
27
+ | |-- geometry2d.py # geometric types like Position2D, Size2D
28
+ | |-- kinematics2d.py # kinematic data structures
29
+ | |-- physics2d.py # physics-related types like Velocity2D
30
+ |-- ui/ # user interface components
31
+ | |-- __init__.py
32
+ | |-- menu.py # menu components
4
33
  """
5
34
 
6
35
  from __future__ import annotations
@@ -8,23 +37,23 @@ from __future__ import annotations
8
37
  import logging
9
38
  from importlib.metadata import PackageNotFoundError, version
10
39
 
11
- from .autoreg import register_scene
12
- from .backend import Backend, Event, EventType
13
- from .boundaries2d import (
40
+ from mini_arcade_core.backend import Backend, Event, EventType
41
+ from mini_arcade_core.entity import Entity, KinematicEntity, SpriteEntity
42
+ from mini_arcade_core.game import Game, GameConfig
43
+ from mini_arcade_core.keymaps.keys import Key, keymap
44
+ from mini_arcade_core.scenes import Scene, SceneRegistry, register_scene
45
+ from mini_arcade_core.two_d import (
46
+ Bounds2D,
47
+ KinematicData,
48
+ Position2D,
49
+ RectCollider,
14
50
  RectKinematic,
15
51
  RectSprite,
52
+ Size2D,
53
+ Velocity2D,
16
54
  VerticalBounce,
17
55
  VerticalWrap,
18
56
  )
19
- from .collision2d import RectCollider
20
- from .entity import Entity, KinematicEntity, SpriteEntity
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
28
57
 
29
58
  logger = logging.getLogger(__name__)
30
59
 
@@ -43,6 +72,9 @@ def run_game(
43
72
  :param config: Optional GameConfig to customize game settings.
44
73
  :type config: GameConfig | None
45
74
 
75
+ :param registry: Optional SceneRegistry for scene management.
76
+ :type registry: SceneRegistry | None
77
+
46
78
  :raises ValueError: If the provided config does not have a valid Backend.
47
79
  """
48
80
  cfg = config or GameConfig()
@@ -109,3 +141,6 @@ def get_version() -> str:
109
141
 
110
142
 
111
143
  __version__ = get_version()
144
+ __version__ = get_version()
145
+ __version__ = get_version()
146
+ __version__ = get_version()
@@ -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 dataclasses import dataclass
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 .keys import Key
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
@@ -0,0 +1,9 @@
1
+ """
2
+ Types used in the backend module.
3
+ """
4
+
5
+ from __future__ import annotations
6
+
7
+ from typing import Tuple, Union
8
+
9
+ Color = Union[Tuple[int, int, int], Tuple[int, int, int, int]]
@@ -6,9 +6,12 @@ from __future__ import annotations
6
6
 
7
7
  from typing import Any
8
8
 
9
- from .collision2d import RectCollider
10
- from .geometry2d import Position2D, Size2D
11
- from .kinematics2d import KinematicData
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 .registry import SceneRegistry
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 .scene import Scene
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: 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
- """Pop the top scene. If stack becomes empty, quit."""
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: 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
+ ]
@@ -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
- SDLK_ESCAPE = 27
12
- SDLK_RETURN = 13
13
- SDLK_SPACE = 32
14
- SDLK_TAB = 9
15
- SDLK_BACKSPACE = 8
14
+ _SDLK_ESCAPE = 27
15
+ _SDLK_RETURN = 13
16
+ _SDLK_SPACE = 32
17
+ _SDLK_TAB = 9
18
+ _SDLK_BACKSPACE = 8
16
19
 
17
- SDLK_UP = 1073741906
18
- SDLK_DOWN = 1073741905
19
- SDLK_LEFT = 1073741904
20
- SDLK_RIGHT = 1073741903
20
+ _SDLK_UP = 1073741906
21
+ _SDLK_DOWN = 1073741905
22
+ _SDLK_LEFT = 1073741904
23
+ _SDLK_RIGHT = 1073741903
21
24
 
22
- F1 = 1073741882
23
- F2 = 1073741883
24
- F3 = 1073741884
25
- F4 = 1073741885
26
- F5 = 1073741886
27
- F6 = 1073741887
28
- F7 = 1073741888
29
- F8 = 1073741889
30
- F9 = 1073741890
31
- F10 = 1073741891
32
- F11 = 1073741892
33
- F12 = 1073741893
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
- SDLK_UP: Key.UP,
65
- SDLK_DOWN: Key.DOWN,
66
- SDLK_LEFT: Key.LEFT,
67
- SDLK_RIGHT: Key.RIGHT,
67
+ _SDLK_UP: Key.UP,
68
+ _SDLK_DOWN: Key.DOWN,
69
+ _SDLK_LEFT: Key.LEFT,
70
+ _SDLK_RIGHT: Key.RIGHT,
68
71
  # Common
69
- SDLK_ESCAPE: Key.ESCAPE,
70
- SDLK_SPACE: Key.SPACE,
71
- SDLK_RETURN: Key.ENTER,
72
- SDLK_TAB: Key.TAB,
73
- SDLK_BACKSPACE: Key.BACKSPACE,
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
- F1: Key.F1,
87
- F2: Key.F2,
88
- F3: Key.F3,
89
- F4: Key.F4,
90
- F5: Key.F5,
91
- F6: Key.F6,
92
- F7: Key.F7,
93
- F8: Key.F8,
94
- F9: Key.F9,
95
- F10: Key.F10,
96
- F11: Key.F11,
97
- F12: Key.F12,
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 .scene import Scene
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
- """Decorator to mark and register a Scene class under an id."""
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
@@ -14,7 +14,7 @@ from .autoreg import snapshot
14
14
 
15
15
  if TYPE_CHECKING:
16
16
  from mini_arcade_core.game import Game
17
- from mini_arcade_core.scene import Scene
17
+ from mini_arcade_core.scenes import Scene
18
18
 
19
19
 
20
20
  class SceneFactory(Protocol):
@@ -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 .game import Game
13
- from .geometry2d import Size2D
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 it just points to them. If the
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
 
@@ -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
+ ]
@@ -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.geometry2d import Size2D
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 x: X coordinate for the menu's top-left corner.
104
- :param y: Y coordinate for the menu's top-left corner.
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
- Returns (content_width, content_height, title_height)
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
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mini-arcade-core
3
- Version: 0.9.5
3
+ Version: 0.9.6
4
4
  Summary: Tiny scene-based game loop core for small arcade games.
5
5
  License: Copyright (c) 2025 Santiago Rincón
6
6
 
@@ -0,0 +1,26 @@
1
+ mini_arcade_core/__init__.py,sha256=yAtLsSrBZD3778nStf0XQjKn5hTP-daYkddk7_dAGe4,4029
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.6.dist-info/METADATA,sha256=TXCP-kgqZegagNZ6_Zoa_lLU0nhNiC6yVGnHpv4iRjM,8188
24
+ mini_arcade_core-0.9.6.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
25
+ mini_arcade_core-0.9.6.dist-info/licenses/LICENSE,sha256=3lHAuV0584cVS5vAqi2uC6GcsVgxUijvwvtZckyvaZ4,1096
26
+ mini_arcade_core-0.9.6.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