mini-arcade-native-backend 0.3.3__cp39-cp39-win_amd64.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_native_backend/__init__.py +194 -0
- mini_arcade_native_backend/_native.cp39-win_amd64.pyd +0 -0
- mini_arcade_native_backend-0.3.3.dist-info/METADATA +345 -0
- mini_arcade_native_backend-0.3.3.dist-info/RECORD +6 -0
- mini_arcade_native_backend-0.3.3.dist-info/WHEEL +5 -0
- mini_arcade_native_backend-0.3.3.dist-info/licenses/LICENSE +19 -0
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
"""
|
|
2
|
+
mini-arcade native backend package.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
import os
|
|
8
|
+
import sys
|
|
9
|
+
|
|
10
|
+
# --- 1) Make sure Windows can find SDL2.dll when using vcpkg ------------------
|
|
11
|
+
|
|
12
|
+
if sys.platform == "win32":
|
|
13
|
+
vcpkg_root = os.environ.get("VCPKG_ROOT")
|
|
14
|
+
if vcpkg_root:
|
|
15
|
+
# Typical vcpkg layout: <VCPKG_ROOT>/installed/x64-windows/bin/SDL2.dll
|
|
16
|
+
sdl_bin = os.path.join(vcpkg_root, "installed", "x64-windows", "bin")
|
|
17
|
+
if os.path.isdir(sdl_bin):
|
|
18
|
+
# Python 3.8+ – add DLL search path before importing the extension
|
|
19
|
+
os.add_dll_directory(sdl_bin)
|
|
20
|
+
|
|
21
|
+
# --- 2) Now import native extension and core types ----------------------------
|
|
22
|
+
|
|
23
|
+
# Justification: Need to import core after setting DLL path on Windows
|
|
24
|
+
# pylint: disable=wrong-import-position
|
|
25
|
+
from mini_arcade_core import Backend, Event, EventType
|
|
26
|
+
|
|
27
|
+
# Justification: Importing the native extension module
|
|
28
|
+
# pylint: disable=import-self,no-name-in-module
|
|
29
|
+
from . import _native as native
|
|
30
|
+
|
|
31
|
+
# --- 2) Now import core + define NativeBackend as before ---
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
__all__ = ["NativeBackend", "native"]
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
_NATIVE_TO_CORE = {
|
|
38
|
+
native.EventType.Unknown: EventType.UNKNOWN,
|
|
39
|
+
native.EventType.Quit: EventType.QUIT,
|
|
40
|
+
native.EventType.KeyDown: EventType.KEYDOWN,
|
|
41
|
+
native.EventType.KeyUp: EventType.KEYUP,
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class NativeBackend(Backend):
|
|
46
|
+
"""Adapter that makes the C++ Engine usable as a mini-arcade backend."""
|
|
47
|
+
|
|
48
|
+
def __init__(self, font_path: str | None = None, font_size: int = 24):
|
|
49
|
+
"""
|
|
50
|
+
:param font_path: Optional path to a TTF font file to load.
|
|
51
|
+
:type font_path: str | None
|
|
52
|
+
|
|
53
|
+
:param font_size: Font size in points to use when loading the font.
|
|
54
|
+
:type font_size: int
|
|
55
|
+
"""
|
|
56
|
+
self._engine = native.Engine()
|
|
57
|
+
self._font_path = font_path
|
|
58
|
+
self._font_size = font_size
|
|
59
|
+
|
|
60
|
+
def init(self, width: int, height: int, title: str):
|
|
61
|
+
"""
|
|
62
|
+
Initialize the backend with a window of given width, height, and title.
|
|
63
|
+
|
|
64
|
+
:param width: Width of the window in pixels.
|
|
65
|
+
:type width: int
|
|
66
|
+
|
|
67
|
+
:param height: Height of the window in pixels.
|
|
68
|
+
:type height: int
|
|
69
|
+
|
|
70
|
+
:param title: Title of the window.
|
|
71
|
+
:type title: str
|
|
72
|
+
"""
|
|
73
|
+
self._engine.init(width, height, title)
|
|
74
|
+
|
|
75
|
+
# Load font if provided
|
|
76
|
+
if self._font_path is not None:
|
|
77
|
+
self._engine.load_font(self._font_path, self._font_size)
|
|
78
|
+
|
|
79
|
+
def set_clear_color(self, r: int, g: int, b: int):
|
|
80
|
+
"""
|
|
81
|
+
Set the background/clear color used by begin_frame.
|
|
82
|
+
|
|
83
|
+
:param r: Red component (0-255).
|
|
84
|
+
:type r: int
|
|
85
|
+
|
|
86
|
+
:param g: Green component (0-255).
|
|
87
|
+
:type g: int
|
|
88
|
+
|
|
89
|
+
:param b: Blue component (0-255).
|
|
90
|
+
:type b: int
|
|
91
|
+
"""
|
|
92
|
+
self._engine.set_clear_color(int(r), int(g), int(b))
|
|
93
|
+
|
|
94
|
+
def poll_events(self) -> list[Event]:
|
|
95
|
+
"""
|
|
96
|
+
Poll for events from the backend and return them as a list of Event objects.
|
|
97
|
+
|
|
98
|
+
:return: List of Event objects representing the polled events.
|
|
99
|
+
:rtype: list[Event]
|
|
100
|
+
"""
|
|
101
|
+
events: list[Event] = []
|
|
102
|
+
for ev in self._engine.poll_events():
|
|
103
|
+
core_type = _NATIVE_TO_CORE.get(ev.type, EventType.UNKNOWN)
|
|
104
|
+
key = ev.key if getattr(ev, "key", 0) != 0 else None
|
|
105
|
+
events.append(Event(type=core_type, key=key))
|
|
106
|
+
return events
|
|
107
|
+
|
|
108
|
+
def begin_frame(self):
|
|
109
|
+
"""Begin a new frame for rendering."""
|
|
110
|
+
self._engine.begin_frame()
|
|
111
|
+
|
|
112
|
+
def end_frame(self):
|
|
113
|
+
"""End the current frame for rendering."""
|
|
114
|
+
self._engine.end_frame()
|
|
115
|
+
|
|
116
|
+
# pylint: disable=too-many-arguments,too-many-positional-arguments
|
|
117
|
+
def draw_rect(
|
|
118
|
+
self,
|
|
119
|
+
x: int,
|
|
120
|
+
y: int,
|
|
121
|
+
w: int,
|
|
122
|
+
h: int,
|
|
123
|
+
color: tuple[int, ...] = (255, 255, 255),
|
|
124
|
+
):
|
|
125
|
+
"""
|
|
126
|
+
Draw a rectangle at the specified position with given width and height.
|
|
127
|
+
|
|
128
|
+
:param x: X coordinate of the rectangle's top-left corner.
|
|
129
|
+
:type x: int
|
|
130
|
+
|
|
131
|
+
:param y: Y coordinate of the rectangle's top-left corner.
|
|
132
|
+
:type y: int
|
|
133
|
+
|
|
134
|
+
:param w: Width of the rectangle.
|
|
135
|
+
:type w: int
|
|
136
|
+
|
|
137
|
+
:param h: Height of the rectangle.
|
|
138
|
+
:type h: int
|
|
139
|
+
|
|
140
|
+
:param color: Color of the rectangle as (r, g, b) or (r, g, b, a).
|
|
141
|
+
:type color: tuple[int, ...]
|
|
142
|
+
"""
|
|
143
|
+
if len(color) == 3:
|
|
144
|
+
r, g, b = color
|
|
145
|
+
self._engine.draw_rect(x, y, w, h, r, g, b)
|
|
146
|
+
elif len(color) == 4:
|
|
147
|
+
r, g, b, a = color
|
|
148
|
+
self._engine.draw_rect_rgba(x, y, w, h, r, g, b, a)
|
|
149
|
+
else:
|
|
150
|
+
raise ValueError(
|
|
151
|
+
f"Color must be (r,g,b) or (r,g,b,a), got {color!r}"
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
# pylint: enable=too-many-arguments,too-many-positional-arguments
|
|
155
|
+
|
|
156
|
+
def draw_text(
|
|
157
|
+
self,
|
|
158
|
+
x: int,
|
|
159
|
+
y: int,
|
|
160
|
+
text: str,
|
|
161
|
+
color: tuple[int, int, int] = (255, 255, 255),
|
|
162
|
+
):
|
|
163
|
+
"""
|
|
164
|
+
Draw text at the given position using the loaded font.
|
|
165
|
+
If no font is loaded, this is a no-op.
|
|
166
|
+
|
|
167
|
+
:param x: X coordinate for the text position.
|
|
168
|
+
:type x: int
|
|
169
|
+
|
|
170
|
+
:param y: Y coordinate for the text position.
|
|
171
|
+
:type y: int
|
|
172
|
+
|
|
173
|
+
:param text: The text string to draw.
|
|
174
|
+
:type text: str
|
|
175
|
+
|
|
176
|
+
:param color: Color of the text as (r, g, b).
|
|
177
|
+
:type color: tuple[int, int, int]
|
|
178
|
+
"""
|
|
179
|
+
# We rely on C++ side to no-op if font is missing
|
|
180
|
+
r, g, b = color
|
|
181
|
+
self._engine.draw_text(text, x, y, int(r), int(g), int(b))
|
|
182
|
+
|
|
183
|
+
def capture_frame(self, path: str | None = None) -> bool:
|
|
184
|
+
"""
|
|
185
|
+
Capture the current frame.
|
|
186
|
+
|
|
187
|
+
:param path: Optional file path to save the captured frame (e.g., PNG).
|
|
188
|
+
:type path: str | None
|
|
189
|
+
|
|
190
|
+
:return: True if the frame was successfully captured (and saved if path provided),
|
|
191
|
+
False otherwise.
|
|
192
|
+
:rtype: bool
|
|
193
|
+
"""
|
|
194
|
+
return self._engine.capture_frame(path)
|
|
Binary file
|
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
|
+
Name: mini-arcade-native-backend
|
|
3
|
+
Version: 0.3.3
|
|
4
|
+
Summary: Native SDL2 backend for mini-arcade-core using SDL2 + pybind11.
|
|
5
|
+
Author-Email: Santiago Rincon <rincores@gmail.com>
|
|
6
|
+
License: Copyright (c) 2025 Santiago Rincón
|
|
7
|
+
|
|
8
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
9
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
10
|
+
in the Software without restriction, including without limitation the rights
|
|
11
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
12
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
13
|
+
furnished to do so, subject to the following conditions:
|
|
14
|
+
|
|
15
|
+
The above copyright notice and this permission notice shall be included in all
|
|
16
|
+
copies or substantial portions of the Software.
|
|
17
|
+
|
|
18
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
19
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
20
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
21
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
22
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
23
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
24
|
+
SOFTWARE.
|
|
25
|
+
|
|
26
|
+
Requires-Python: <3.12,>=3.9
|
|
27
|
+
Requires-Dist: mini-arcade-core>=0.2.3
|
|
28
|
+
Provides-Extra: dev
|
|
29
|
+
Requires-Dist: pytest~=8.3; extra == "dev"
|
|
30
|
+
Requires-Dist: pytest-cov~=6.0; extra == "dev"
|
|
31
|
+
Requires-Dist: black~=24.10; extra == "dev"
|
|
32
|
+
Requires-Dist: isort~=5.13; extra == "dev"
|
|
33
|
+
Requires-Dist: mypy~=1.5; extra == "dev"
|
|
34
|
+
Requires-Dist: pylint~=3.3; extra == "dev"
|
|
35
|
+
Description-Content-Type: text/markdown
|
|
36
|
+
|
|
37
|
+
# mini-arcade-native-backend
|
|
38
|
+
|
|
39
|
+
Native SDL2 backend for **mini-arcade-core**, implemented in C++ with `SDL2` + `pybind11`
|
|
40
|
+
and exposed to Python as a backend that plugs into your mini-arcade game framework.
|
|
41
|
+
|
|
42
|
+
The goal of this repo is to provide a **native window + input + drawing layer** while
|
|
43
|
+
keeping all game logic in Python (via `mini-arcade-core`).
|
|
44
|
+
|
|
45
|
+
- C++ (`SDL2` + `pybind11`) ⇒ `_native` extension module
|
|
46
|
+
- Python adapter ⇒ `NativeBackend` implementing `mini_arcade_core.backend.Backend`
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## Features (current)
|
|
51
|
+
|
|
52
|
+
- Opens an SDL window from Python
|
|
53
|
+
- Basic event polling (Quit, KeyDown, KeyUp) mapped to `Event` / `EventType` in mini-core
|
|
54
|
+
- Simple rendering:
|
|
55
|
+
- `begin_frame()` / `end_frame()`
|
|
56
|
+
- `draw_rect(x, y, w, h)` (filled rectangle)
|
|
57
|
+
- Example script that shows a moving rectangle and exits on **ESC** or window close
|
|
58
|
+
|
|
59
|
+
This is intentionally minimal and intended as a foundation for adding sprites, textures,
|
|
60
|
+
audio, etc.
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## Repository layout
|
|
65
|
+
|
|
66
|
+
```text
|
|
67
|
+
mini-arcade-native-backend/
|
|
68
|
+
├─ cpp/
|
|
69
|
+
│ ├─ engine.h # C++ Engine class (SDL wrapper)
|
|
70
|
+
│ ├─ engine.cpp
|
|
71
|
+
│ └─ bindings.cpp # pybind11 bindings for Engine / Event / EventType
|
|
72
|
+
├─ src/
|
|
73
|
+
│ └─ mini_arcade_native_backend/
|
|
74
|
+
│ ├─ __init__.py # Python adapter (NativeBackend)
|
|
75
|
+
│ └─ ... # (future helpers)
|
|
76
|
+
├─ examples/
|
|
77
|
+
│ └─ native_backend_demo.py # example using NativeBackend directly
|
|
78
|
+
├─ CMakeLists.txt # C++ build (pybind11 + SDL2)
|
|
79
|
+
└─ pyproject.toml # Python package & build config (scikit-build-core)
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## Install modes
|
|
85
|
+
|
|
86
|
+
There are **two ways** to consume this backend:
|
|
87
|
+
|
|
88
|
+
1. **From PyPI (recommended for players / game users)**
|
|
89
|
+
Prebuilt wheels for your platform (no C++ toolchain or vcpkg needed).
|
|
90
|
+
2. **From source (for contributors / engine dev)**
|
|
91
|
+
Build the C++ extension locally using CMake + vcpkg.
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## 1. Using the backend from PyPI (no C++ build)
|
|
96
|
+
|
|
97
|
+
Once wheels are published, you can simply do:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
pip install mini-arcade-core
|
|
101
|
+
pip install mini-arcade-native-backend
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
And in your game:
|
|
105
|
+
|
|
106
|
+
```python
|
|
107
|
+
from mini_arcade_core import Game, GameConfig, Scene
|
|
108
|
+
from mini_arcade_core.backend import EventType
|
|
109
|
+
from mini_arcade_native_backend import NativeBackend
|
|
110
|
+
|
|
111
|
+
class MyScene(Scene):
|
|
112
|
+
def handle_event(self, event):
|
|
113
|
+
if event.type == EventType.KEYDOWN and event.key == 27: # ESC
|
|
114
|
+
self.game.quit()
|
|
115
|
+
|
|
116
|
+
def update(self, dt: float):
|
|
117
|
+
...
|
|
118
|
+
|
|
119
|
+
def draw(self, backend):
|
|
120
|
+
backend.draw_rect(100, 100, 200, 150)
|
|
121
|
+
|
|
122
|
+
config = GameConfig(
|
|
123
|
+
width=800,
|
|
124
|
+
height=600,
|
|
125
|
+
title="Mini Arcade + Native SDL2",
|
|
126
|
+
backend_factory=lambda: NativeBackend(),
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
game = Game(config)
|
|
130
|
+
scene = MyScene(game)
|
|
131
|
+
game.run(scene)
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
For normal users of your games, this is the ideal path: **no vcpkg**, no CMake, no compiler.
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
## 2. Developing / building from source
|
|
139
|
+
|
|
140
|
+
If you want to work on the native backend itself (C++ + Python), you’ll build the extension
|
|
141
|
+
locally. For that, you need a C++ toolchain, CMake, and vcpkg.
|
|
142
|
+
|
|
143
|
+
### 2.1. System requirements
|
|
144
|
+
|
|
145
|
+
- **OS**: Windows 10 or later (current dev setup)
|
|
146
|
+
- **Compiler**: MSVC via Visual Studio Build Tools or Visual Studio 2022
|
|
147
|
+
- Install the *“Desktop development with C++”* workload
|
|
148
|
+
- **CMake**: 3.16+
|
|
149
|
+
- **Python**: 3.9–3.11 (matching your `mini-arcade-core` version)
|
|
150
|
+
- **vcpkg**: for `SDL2` and `pybind11`
|
|
151
|
+
- (Optional but nice) **virtual environment** / Poetry for Python deps
|
|
152
|
+
|
|
153
|
+
### 2.2. vcpkg + C++ libraries
|
|
154
|
+
|
|
155
|
+
This project uses [vcpkg](https://github.com/microsoft/vcpkg) to manage C++ dependencies.
|
|
156
|
+
|
|
157
|
+
#### Clone and bootstrap vcpkg
|
|
158
|
+
|
|
159
|
+
```powershell
|
|
160
|
+
cd C:\Users\<your_user>\work
|
|
161
|
+
|
|
162
|
+
git clone https://github.com/microsoft/vcpkg.git
|
|
163
|
+
cd vcpkg
|
|
164
|
+
.\bootstrap-vcpkg.bat
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
#### Install dependencies via vcpkg
|
|
168
|
+
|
|
169
|
+
```powershell
|
|
170
|
+
# From the vcpkg folder:
|
|
171
|
+
.\vcpkg.exe install sdl2 pybind11
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
You only need to do this once per machine (unless you wipe `vcpkg` or add new libraries).
|
|
175
|
+
|
|
176
|
+
### 2.3. Linking CMake to vcpkg
|
|
177
|
+
|
|
178
|
+
For builds in this repo, set the toolchain environment variable once per shell:
|
|
179
|
+
|
|
180
|
+
```powershell
|
|
181
|
+
$env:CMAKE_TOOLCHAIN_FILE = "C:/Users/<your_user>/work/vcpkg/scripts/buildsystems/vcpkg.cmake"
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
(Adjust the path if you cloned `vcpkg` somewhere else.)
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
## 3. Building & installing the package from source
|
|
189
|
+
|
|
190
|
+
This project uses **[scikit-build-core](https://github.com/scikit-build/scikit-build-core)** as
|
|
191
|
+
the build backend, which lets `pip` drive CMake for you.
|
|
192
|
+
|
|
193
|
+
From the repo root (`mini-arcade-native-backend/`):
|
|
194
|
+
|
|
195
|
+
### 3.1. Editable install (dev mode)
|
|
196
|
+
|
|
197
|
+
```powershell
|
|
198
|
+
# Activate your virtualenv (or use Poetry's venv)
|
|
199
|
+
# Then, with CMAKE_TOOLCHAIN_FILE set:
|
|
200
|
+
|
|
201
|
+
pip install -e .
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
What this does:
|
|
205
|
+
|
|
206
|
+
- Runs CMake via scikit-build-core
|
|
207
|
+
- Builds the `_native` extension
|
|
208
|
+
- Installs the package in editable mode, so changes to `src/` are picked up immediately
|
|
209
|
+
|
|
210
|
+
After this, you can test in Python:
|
|
211
|
+
|
|
212
|
+
```python
|
|
213
|
+
>>> from mini_arcade_native_backend import NativeBackend
|
|
214
|
+
>>> backend = NativeBackend()
|
|
215
|
+
>>> backend.init(800, 600, "Hello from native backend")
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
### 3.2. Building wheels / sdist
|
|
219
|
+
|
|
220
|
+
To build distributable artifacts:
|
|
221
|
+
|
|
222
|
+
```powershell
|
|
223
|
+
python -m build
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
This will produce:
|
|
227
|
+
|
|
228
|
+
```text
|
|
229
|
+
dist/
|
|
230
|
+
mini-arcade-native-backend-0.1.0-*.whl
|
|
231
|
+
mini-arcade-native-backend-0.1.0.tar.gz
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
Those wheels can be uploaded to PyPI (e.g. via `twine`) and installed by anyone with:
|
|
235
|
+
|
|
236
|
+
```bash
|
|
237
|
+
pip install mini-arcade-native-backend
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
End users installing the wheel **do not** need vcpkg or a compiler.
|
|
241
|
+
|
|
242
|
+
---
|
|
243
|
+
|
|
244
|
+
## 4. Python usage & example
|
|
245
|
+
|
|
246
|
+
The package exposes a `NativeBackend` that implements the `Backend` protocol from
|
|
247
|
+
`mini-arcade-core` and wraps the C++ `Engine` underneath.
|
|
248
|
+
|
|
249
|
+
```python
|
|
250
|
+
from mini_arcade_native_backend import NativeBackend
|
|
251
|
+
from mini_arcade_core.backend import EventType
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
A small standalone demo is provided under `examples/`:
|
|
255
|
+
|
|
256
|
+
```bash
|
|
257
|
+
python examples/native_backend_demo.py
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
That demo:
|
|
261
|
+
|
|
262
|
+
- opens an 800×600 window,
|
|
263
|
+
- moves a rectangle horizontally,
|
|
264
|
+
- exits on ESC or window close.
|
|
265
|
+
|
|
266
|
+
(When installed via `pip install -e .`, you can run this from the repo root.)
|
|
267
|
+
|
|
268
|
+
---
|
|
269
|
+
|
|
270
|
+
## 5. How it fits into mini-arcade-core
|
|
271
|
+
|
|
272
|
+
On the C++ side (`cpp/engine.h` / `cpp/engine.cpp`):
|
|
273
|
+
|
|
274
|
+
- `mini::Engine` wraps SDL:
|
|
275
|
+
- `init(width, height, title)`
|
|
276
|
+
- `begin_frame()` / `end_frame()`
|
|
277
|
+
- `draw_rect(x, y, w, h)`
|
|
278
|
+
- `poll_events()` → `std::vector<Event>`
|
|
279
|
+
- `EventType` and `Event` are simple types mapping SDL events to something Python-friendly.
|
|
280
|
+
|
|
281
|
+
On the Python side (`src/mini_arcade_native_backend/__init__.py`):
|
|
282
|
+
|
|
283
|
+
- The compiled C++ module is imported as `._native` (installed into the same package)
|
|
284
|
+
- `NativeBackend` implements `mini_arcade_core.backend.Backend`:
|
|
285
|
+
- `init(width, height, title)` → `_native.Engine.init(...)`
|
|
286
|
+
- `poll_events()` → converts `_native.Event` to core `Event`
|
|
287
|
+
- `begin_frame()` / `end_frame()` → pass-through
|
|
288
|
+
- `draw_rect(x, y, w, h)` → pass-through
|
|
289
|
+
|
|
290
|
+
A minimal integration with mini-arcade-core:
|
|
291
|
+
|
|
292
|
+
```python
|
|
293
|
+
from mini_arcade_core import Game, GameConfig, Scene
|
|
294
|
+
from mini_arcade_core.backend import Backend, Event, EventType
|
|
295
|
+
from mini_arcade_native_backend import NativeBackend
|
|
296
|
+
|
|
297
|
+
class MyScene(Scene):
|
|
298
|
+
def handle_event(self, event: Event) -> None:
|
|
299
|
+
if event.type == EventType.KEYDOWN and event.key == 27: # ESC
|
|
300
|
+
self.game.quit()
|
|
301
|
+
|
|
302
|
+
def update(self, dt: float) -> None:
|
|
303
|
+
...
|
|
304
|
+
|
|
305
|
+
def draw(self, backend: Backend) -> None:
|
|
306
|
+
backend.draw_rect(100, 100, 200, 150)
|
|
307
|
+
|
|
308
|
+
config = GameConfig(
|
|
309
|
+
width=800,
|
|
310
|
+
height=600,
|
|
311
|
+
title="Mini Arcade + Native SDL2",
|
|
312
|
+
backend_factory=lambda: NativeBackend(),
|
|
313
|
+
)
|
|
314
|
+
|
|
315
|
+
game = Game(config)
|
|
316
|
+
scene = MyScene(game)
|
|
317
|
+
game.run(scene)
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
---
|
|
321
|
+
|
|
322
|
+
## 6. Troubleshooting
|
|
323
|
+
|
|
324
|
+
- **`ModuleNotFoundError: No module named '_native'`**
|
|
325
|
+
- Ensure `pip install -e .` (or `python -m build`) completed successfully.
|
|
326
|
+
- Confirm that the wheel contains `mini_arcade_native_backend/_native.*.pyd`.
|
|
327
|
+
|
|
328
|
+
- **DLL load error / Python version mismatch**
|
|
329
|
+
- Make sure you are building and running with the **same Python version**.
|
|
330
|
+
- If you have multiple Python versions installed, ensure the one used by
|
|
331
|
+
`pip install -e .` is the one used to run your game.
|
|
332
|
+
|
|
333
|
+
- **CMake can’t find SDL2 or pybind11**
|
|
334
|
+
- Confirm vcpkg is installed and `sdl2` + `pybind11` are installed via vcpkg.
|
|
335
|
+
- Make sure `CMAKE_TOOLCHAIN_FILE` is set correctly in your shell.
|
|
336
|
+
|
|
337
|
+
---
|
|
338
|
+
|
|
339
|
+
## 7. Roadmap
|
|
340
|
+
|
|
341
|
+
- Configurable clear color (per scene / per game)
|
|
342
|
+
- Basic texture / sprite support
|
|
343
|
+
- Simple audio playback
|
|
344
|
+
- CI that builds wheels for Windows and uploads to PyPI
|
|
345
|
+
- A `mini-arcade-core` example project that uses this backend as the default renderer
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
mini_arcade_native_backend/__init__.py,sha256=Wc8QcUb39AUnwJMy1XEykBadAybJNgncld2HLvKUPWw,6118
|
|
2
|
+
mini_arcade_native_backend/_native.cp39-win_amd64.pyd,sha256=MPpUieq0R-8NKlq6o4LZ47ZqVsVAsZgF1wb4bp9MIvk,219648
|
|
3
|
+
mini_arcade_native_backend-0.3.3.dist-info/METADATA,sha256=N9TjTXkbNSu-U7wDgTg95W_B0yRAZu1ieucneBzGrUI,10519
|
|
4
|
+
mini_arcade_native_backend-0.3.3.dist-info/WHEEL,sha256=9tsL4JT94eZPTkcS3bNng2riasYJMxXndrO9CxUfJHs,104
|
|
5
|
+
mini_arcade_native_backend-0.3.3.dist-info/licenses/LICENSE,sha256=cZRgTdRJ3YASekMxkGAvylB2nROh4ov228DxAogK3yY,1115
|
|
6
|
+
mini_arcade_native_backend-0.3.3.dist-info/RECORD,,
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
Copyright (c) 2025 Santiago Rincón
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
5
|
+
in the Software without restriction, including without limitation the rights
|
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
8
|
+
furnished to do so, subject to the following conditions:
|
|
9
|
+
|
|
10
|
+
The above copyright notice and this permission notice shall be included in all
|
|
11
|
+
copies or substantial portions of the Software.
|
|
12
|
+
|
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
19
|
+
SOFTWARE.
|