Skip to content

Commit 677d4df

Browse files
committed
v3.0.0
1 parent f3c54ac commit 677d4df

11 files changed

Lines changed: 444 additions & 22 deletions

File tree

README.md

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ pip install spritepro
148148
Для мобильного host-режима:
149149

150150
```bash
151-
pip install kivy
151+
pip install "spritepro[kivy]"
152152
```
153153

154154
#### Обновление
@@ -195,6 +195,19 @@ s.run(scene=MainScene, size=(800, 600), title="My Game", fill_color=(20, 20, 30)
195195

196196
**Вот и всё!** У вас уже есть игра с управлением, отрисовкой и игровым циклом. Для mobile достаточно сменить `platform` на `"kivy"`. 🎮
197197

198+
Для файлов ассетов задавайте путь явно от текущего файла, а не от рабочей папки:
199+
200+
```python
201+
from pathlib import Path
202+
203+
ASSETS_DIR = Path(__file__).resolve().parent / "assets" / "images"
204+
205+
def asset_path(name: str) -> str:
206+
return str((ASSETS_DIR / name).resolve())
207+
```
208+
209+
Такой способ одинаково корректно работает и в `pygame`, и в `kivy`. Подробности: [docs/mobile.md](docs/mobile.md).
210+
198211
### ⚡ Быстрый старт 2.0 (шаблон проекта)
199212

200213
```bash
@@ -235,6 +248,14 @@ s.run(scene=MainScene, platform="kivy")
235248
- [Hybrid Kivy UI guide](docs/kivy_hybrid.md) — Kivy menu/layout + встроенная игровая область SpritePro
236249
- [Build guide](docs/building.md) — как собирать library, web и mobile build
237250

251+
Быстрый preview разных экранов через CLI:
252+
253+
```bash
254+
python -m spritePro.cli --preview main.py --platform kivy --screen phone-portrait
255+
python -m spritePro.cli --preview main.py --platform kivy --screen tablet-landscape
256+
python -m spritePro.cli --list-screen-presets
257+
```
258+
238259
### Что уже работает
239260

240261
- desktop runtime через `pygame`

docs/building.md

Lines changed: 76 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -185,10 +185,10 @@ s.run(scene=MainScene, platform="kivy")
185185

186186
### Локальная проверка mobile-режима на ПК
187187

188-
Установите `Kivy`:
188+
Установите mobile-зависимости:
189189

190190
```bash
191-
pip install kivy
191+
pip install "spritepro[kivy]"
192192
```
193193

194194
Запустите игру:
@@ -204,6 +204,72 @@ python -m spritePro.demoGames.mobile_orb_collector_demo --kivy
204204
python -m spritePro.demoGames.builder_demo --kivy
205205
```
206206

207+
Если вы работаете из исходников SpritePro, а не из опубликованного пакета:
208+
209+
```bash
210+
pip install -e ".[kivy]"
211+
```
212+
213+
### Тестирование на разных экранах до Android build
214+
215+
Перед реальной сборкой полезно прогнать одну и ту же игру на нескольких размерах окна в desktop-preview через `platform="kivy"`.
216+
217+
Самый быстрый способ теперь через CLI:
218+
219+
```bash
220+
python -m spritePro.cli --preview main.py --platform kivy --screen phone-portrait
221+
python -m spritePro.cli --preview main.py --platform kivy --screen phone-tall
222+
python -m spritePro.cli --preview main.py --platform kivy --screen phone-landscape
223+
python -m spritePro.cli --preview main.py --platform kivy --screen tablet-landscape
224+
python -m spritePro.cli --preview main.py --platform pygame --size 412x915
225+
python -m spritePro.cli --list-screen-presets
226+
```
227+
228+
Команда `--preview`:
229+
230+
- принимает путь к `main.py` или к папке проекта
231+
- временно подменяет размер окна
232+
- для scene-based игр на `s.run(...)` может быстро переключать `pygame` / `kivy`
233+
- помогает быстро увидеть расхождения layout до Android build
234+
235+
Пример:
236+
237+
```python
238+
import spritePro as s
239+
240+
241+
class MainScene(s.Scene):
242+
def __init__(self):
243+
super().__init__()
244+
self.player = s.Sprite("", (96, 96), s.WH_C, scene=self)
245+
self.player.set_rect_shape((96, 96), (90, 210, 255), border_radius=24)
246+
247+
248+
s.run(
249+
scene=MainScene,
250+
size=(360, 640),
251+
title="Phone Portrait Preview",
252+
fill_color=(20, 20, 30),
253+
platform="kivy",
254+
)
255+
```
256+
257+
Что стоит проверить хотя бы в нескольких профилях:
258+
259+
- `size=(360, 640)` — компактный phone portrait
260+
- `size=(412, 915)` — современный высокий phone portrait
261+
- `size=(640, 360)` — compact landscape
262+
- `size=(1280, 720)` — tablet / desktop-preview landscape
263+
264+
На что смотреть:
265+
266+
- не уезжает ли UI за края
267+
- хватает ли размеров hitbox и кнопок под touch
268+
- корректно ли выглядят `screen_space`-элементы
269+
- не завязана ли логика на один фиксированный `s.WH`
270+
- одинаково ли ведут себя `pygame` и `kivy`
271+
- помните, что в `Kivy` при resize `s.WH` и `s.WH_C` обновляются, но уже созданные объекты не relayout'ятся автоматически
272+
207273
### Android: рекомендуемый путь
208274

209275
Для Android-сборки обычно используется `Buildozer`.
@@ -212,6 +278,7 @@ python -m spritePro.demoGames.builder_demo --kivy
212278

213279
- `Buildozer` официально удобнее всего запускать на Linux
214280
- на Windows обычно используют `WSL` или отдельную Linux-машину
281+
- собирать проект лучше внутри Linux filesystem/WSL home, а не из Windows-диска
215282
- на Android нужно заранее продумать ассеты, ориентацию экрана и touch-управление
216283

217284
### Минимальный сценарий сборки Android
@@ -247,6 +314,8 @@ s.run(
247314

248315
### Buildozer
249316

317+
`Buildozer` ставится и запускается внутри Linux/WSL-окружения.
318+
250319
Установка:
251320

252321
```bash
@@ -271,6 +340,11 @@ orientation = landscape
271340
fullscreen = 1
272341
```
273342

343+
Если вы тестируете не опубликованный `spritepro`, а локально модифицированную версию, заранее проверьте, как именно библиотека попадёт в Android build:
344+
345+
- либо используйте опубликованный пакет `spritepro`
346+
- либо собирайте/подключайте свою локальную версию отдельно и проверяйте это до финальной сборки
347+
274348
Если игра использует сеть по Wi-Fi:
275349

276350
```ini

docs/kivy_hybrid.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,13 @@ HybridApp().run()
233233

234234
Это именно то поведение, которое нужно для embedded-игры.
235235

236+
Важно понимать нюанс resize:
237+
238+
- при изменении размера `game_widget` значения `s.WH` и `s.WH_C` тоже обновляются
239+
- но уже созданные объекты не перепозиционируются автоматически
240+
- если вы один раз поставили спрайт в `__init__` через `s.WH_C`, он не "переедет" сам после следующего resize
241+
- для truly adaptive layout пересчитывайте позиции/размеры от текущих `s.WH` и `s.WH_C`
242+
236243
---
237244

238245
## Что лучше использовать

docs/mobile.md

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,20 @@ s.run(scene=MyScene, platform="kivy")
2323
- `spritePro.update_embedded(...)` — один кадр без `pygame.display.update()`
2424
- `spritePro.mobile.run_kivy_app(...)` — низкоуровневый запуск, если нужна ручная настройка host-приложения
2525

26+
## Установка mobile-зависимостей
27+
28+
Если вы ставите библиотеку из `pip`:
29+
30+
```bash
31+
pip install "spritepro[kivy]"
32+
```
33+
34+
Если вы работаете из исходников:
35+
36+
```bash
37+
pip install -e ".[kivy]"
38+
```
39+
2640
## Full-screen по умолчанию
2741

2842
Сейчас режим по умолчанию для `Kivy` остаётся простым:
@@ -131,6 +145,122 @@ if left.rect.collidepoint(s.input.mouse_pos) and s.input.is_mouse_pressed(1):
131145

132146
Это работает и мышью на desktop, и касанием внутри `Kivy`.
133147

148+
## Пути к ассетам: делайте явно через `Path(__file__)`
149+
150+
Если игра должна одинаково работать в `pygame` и `kivy`, не полагайтесь на текущую рабочую папку и не пишите пути вроде `"spritePro\\demoGames\\Sprites\\hero.png"` или `"assets/player.png"` как "магическую" строку без привязки к файлу.
151+
152+
Правильный и явный вариант:
153+
154+
```python
155+
from pathlib import Path
156+
import spritePro as s
157+
158+
159+
ASSETS_DIR = Path(__file__).resolve().parent / "assets" / "images"
160+
161+
162+
def asset_path(name: str) -> str:
163+
return str((ASSETS_DIR / name).resolve())
164+
165+
166+
class MyScene(s.Scene):
167+
def __init__(self):
168+
super().__init__()
169+
self.player = s.Sprite(
170+
asset_path("player.png"),
171+
(96, 96),
172+
s.WH_C,
173+
scene=self,
174+
)
175+
```
176+
177+
Почему именно так:
178+
179+
- путь считается от текущего `.py` файла, а не от папки, из которой вы запустили Python
180+
- один и тот же код стабильно работает в `pygame`, `kivy` и в будущей упаковке проекта
181+
- это особенно важно для mobile/hybrid-сценариев, где host-приложение может запускать игру не из той директории, на которую вы рассчитывали
182+
183+
Рекомендуемое правило:
184+
185+
- для изображений, звуков, JSON-сцен и шрифтов используйте `Path(__file__).resolve()`
186+
- передавайте в `SpritePro` уже нормализованный путь через `str(...)`
187+
188+
## Как тестировать на разных экранах
189+
190+
До сборки на телефон полезно прогнать игру на нескольких размерах окна прямо на ПК.
191+
192+
Самый быстрый путь теперь через CLI:
193+
194+
```bash
195+
python -m spritePro.cli --preview main.py --platform kivy --screen phone-portrait
196+
python -m spritePro.cli --preview main.py --platform kivy --screen phone-tall
197+
python -m spritePro.cli --preview main.py --platform kivy --screen tablet-landscape
198+
python -m spritePro.cli --preview main.py --platform pygame --size 412x915
199+
python -m spritePro.cli --list-screen-presets
200+
```
201+
202+
Что делает `--preview`:
203+
204+
- запускает указанный `main.py` или папку проекта с `main.py`
205+
- временно подменяет размер окна
206+
- может быстро переключать `pygame` / `kivy` для игр на `s.run(...)`
207+
- добавляет в title подпись вида `[kivy 360x640]`, чтобы не путать окна
208+
209+
Важно:
210+
211+
- переключение платформы через CLI рассчитано на современные игры, которые запускаются через `s.run(...)`
212+
- если проект использует старый ручной цикл с `s.get_screen(...)`, override размера сработает, но автоматическое переключение на `kivy` через CLI не гарантируется
213+
214+
Что происходит при resize в `Kivy`:
215+
216+
- `s.WH` и `s.WH_C` обновляются под новый размер окна/виджета
217+
- но уже созданные спрайты, панели и текст не перестраиваются автоматически только потому, что когда-то были созданы через `s.WH` или `s.WH_C`
218+
- если нужен настоящий adaptive layout, пересчитывайте позиции и размеры от текущих `s.WH` / `s.WH_C` после resize
219+
220+
Минимальный пример:
221+
222+
```python
223+
import spritePro as s
224+
225+
226+
class MainScene(s.Scene):
227+
def __init__(self):
228+
super().__init__()
229+
self.player = s.Sprite("", (96, 96), s.WH_C, scene=self)
230+
self.player.set_rect_shape((96, 96), (90, 210, 255), border_radius=24)
231+
232+
233+
s.run(
234+
scene=MainScene,
235+
size=(360, 640),
236+
title="Mobile Preview",
237+
fill_color=(20, 20, 30),
238+
platform="kivy",
239+
)
240+
```
241+
242+
Полезные размеры для быстрой проверки:
243+
244+
- `size=(360, 640)` — маленький portrait
245+
- `size=(412, 915)` — высокий portrait
246+
- `size=(640, 360)` — compact landscape
247+
- `size=(1280, 720)` — большой landscape / tablet preview
248+
249+
Практика:
250+
251+
- сначала прогоните игру в `platform="pygame"`
252+
- потом те же размеры прогоните в `platform="kivy"`
253+
- сравните layout, размер кнопок, позиционирование и touch-friendly UI
254+
255+
Что проверять:
256+
257+
- опирается ли UI на `s.WH` и `s.WH_C` корректно
258+
- не обрезаются ли панели, текст и кнопки
259+
- удобны ли hitbox для пальца
260+
- не выглядят ли ассеты слишком мелкими или слишком крупными
261+
- нормально ли игра переживает portrait/landscape-сценарии
262+
- не осталось ли объектов, которые были один раз выставлены в `__init__` от старого `s.WH_C` и больше не обновляются
263+
134264
## Готовое демо
135265

136266
```bash

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ dependencies = [
3434

3535
[project.optional-dependencies]
3636
web = ["pygbag>=0.9.0"]
37+
kivy = ["kivy"]
3738

3839
[project.urls]
3940
Homepage = "https://github.com/NeoXider/SpritePro"

spritePro/__init__.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
Документация: см. docs/ в корне репозитория и DOCUMENTATION_INDEX.md.
2323
"""
2424

25+
import os
2526
from typing import Callable, List
2627

2728
import pygame
@@ -1022,6 +1023,47 @@ def init():
10221023
_context.init_pygame()
10231024

10241025

1026+
def _parse_size_override(raw_value: str | None) -> tuple[int, int] | None:
1027+
if not raw_value:
1028+
return None
1029+
normalized = raw_value.lower().replace(" ", "")
1030+
separator = "x" if "x" in normalized else ","
1031+
if separator not in normalized:
1032+
return None
1033+
try:
1034+
width_str, height_str = normalized.split(separator, 1)
1035+
width = max(1, int(width_str))
1036+
height = max(1, int(height_str))
1037+
except ValueError:
1038+
return None
1039+
return width, height
1040+
1041+
1042+
def _resolve_screen_options(
1043+
size: tuple[int, int],
1044+
title: str,
1045+
) -> tuple[tuple[int, int], str]:
1046+
size_override = _parse_size_override(os.environ.get("SPRITEPRO_WINDOW_SIZE"))
1047+
if size_override is not None:
1048+
size = size_override
1049+
title_suffix = os.environ.get("SPRITEPRO_TITLE_SUFFIX", "").strip()
1050+
if title_suffix:
1051+
title = f"{title} {title_suffix}"
1052+
return size, title
1053+
1054+
1055+
def _resolve_run_options(
1056+
size: tuple[int, int],
1057+
title: str,
1058+
platform: str,
1059+
) -> tuple[tuple[int, int], str, str]:
1060+
size, title = _resolve_screen_options(size, title)
1061+
platform_override = os.environ.get("SPRITEPRO_PLATFORM")
1062+
if platform_override:
1063+
platform = platform_override
1064+
return size, title, platform
1065+
1066+
10251067
def get_screen(
10261068
size: tuple[int, int] = (800, 600), title: str = "Игра", icon: str = None
10271069
) -> pygame.Surface:
@@ -1037,6 +1079,7 @@ def get_screen(
10371079
Returns:
10381080
pygame.Surface: Поверхность экрана игры.
10391081
"""
1082+
size, title = _resolve_screen_options(size, title)
10401083
result = _context.get_screen(size=size, title=title, icon=icon)
10411084
_sync_globals()
10421085
return result
@@ -1102,6 +1145,7 @@ def run(
11021145
fill_color: Цвет очистки кадра.
11031146
platform: "pygame" или "kivy".
11041147
"""
1148+
size, title, platform = _resolve_run_options(size, title, platform)
11051149
platform_normalized = platform.lower().strip()
11061150
if platform_normalized in {"pygame", "desktop"}:
11071151
get_screen(size=size, title=title, icon=icon)

0 commit comments

Comments
 (0)