80 lines
6.0 KiB
Markdown
80 lines
6.0 KiB
Markdown
# Плеер Ren'Py: что он делает так же, как Ren'Py
|
||
|
||
Плеер (`frontend/src/player/`) исполняет сценарий Ren'Py из IR в браузере. Здесь — то, что
|
||
повторяет поведение Ren'Py, а не его упрощение. Принцип: если игра приносит свой код (библиотеку
|
||
текстовых эффектов, свои displayable, свои настройки), плеер запускает **её код**, а не заменяет
|
||
его собственной копией.
|
||
|
||
## Геометрия трансформаций
|
||
|
||
`rendertransform.ts` — порт `RenderTransform` из `renpy/display/accelerator.pyx`: обрезка (`crop`),
|
||
`size`/`fit`, `zoom` и отражения, `rotate` с `rotate_pad`, 3D-повороты (`xrotate`, `yrotate`,
|
||
`zrotate`) вокруг `matrixanchor`, `zpos`, `zzoom`, `matrixtransform`, якорь по `transform_anchor`.
|
||
Матрицы — Ren'Py (`Matrix4`: векторы-столбцы, ось z от зрителя); в CSS уходит `matrix3d` с
|
||
отражённым z. `xpan`/`ypan`/`xtile`/`ytile` — отдельный элемент с повторяющимся фоном.
|
||
`blend` и `additive` переводятся в `mix-blend-mode`. Тесты — `frontend/tests/rendertransform.test.mjs`.
|
||
|
||
## Слои и камера
|
||
|
||
`config.layers` задаёт порядок слоёв снизу вверх; слой `screens` — собственный интерфейс плеера
|
||
(текстбокс, меню, экраны), слои до него лежат под интерфейсом, после — над ним. Игра управляет
|
||
слоями так же, как в Ren'Py:
|
||
|
||
* `show`/`hide`/`scene ... onlayer имя`, `renpy.show/hide/scene(layer=...)`, `renpy.showing`,
|
||
`renpy.get_showing_tags`, `renpy.get_attributes` с `layer`;
|
||
* `show screen`/`hide screen`/`call screen ... onlayer имя`, свойство `layer` экрана,
|
||
`renpy.show_screen(_layer=...)`, `renpy.get_screen(layer=...)`;
|
||
* `renpy.add_layer(имя, above=, below=)` — порядок сохраняется в сохранении;
|
||
* `camera имя at ...` и `renpy.show_layer_at(список, layer=)` — трансформация всего слоя
|
||
(анимируемая, с теми же свойствами, что у картинки);
|
||
* `perspective True|число|(near, p, far)` на слое: картинки со `zpos` уходят в глубину с
|
||
перспективой (CSS `perspective` на слое).
|
||
|
||
Смена сцены (`with`) снимает копию всех слоёв под интерфейсом. `preferences.transitions = 0`
|
||
отключает переходы.
|
||
|
||
## Откат
|
||
|
||
Плеер хранит снимок состояния на каждом взаимодействии (до 50) и возвращается к предыдущему по
|
||
колесу вверх, `PageUp` и действию `Rollback`. Журнал очищается при новой игре и загрузке.
|
||
|
||
## Текст
|
||
|
||
* `{font}`, `{alpha}`, `{k}`, `{plain}`, `{outlinecolor}`, `{cps}` (в том числе `{cps=*2}` и
|
||
`{/cps}`), `{a=...}` (адреса, `show:`, `hide:`, `jump:`, `call_in_new_context:` или
|
||
`config.hyperlink_handler`), `{rb}`/`{rt}` (ruby), `{space=N}`, `{vspace=N}`, `{alt}`, `{image=...}`.
|
||
* **Свои теги игры** (`config.custom_text_tags[...]`, `config.self_closing_custom_text_tags[...]`):
|
||
плеер вызывает функцию игры с `(tag, argument, contents)`, где `contents` — пары
|
||
`(renpy.TEXT_TEXT | TEXT_TAG, текст)`; ответ — тот же список, а `renpy.TEXT_DISPLAYABLE`
|
||
вставляет displayable в строку как один символ. Так работают Kinetic Text Tags (`{bt}`, `{fi}`,
|
||
`{sc}`, `{rotat}`, `{chaos}`, `{swap}`, `{move}`, `{omega}`), `{glitch}`, `{gradient}`,
|
||
`{explode}` и `{ruby}` в *That New Teacher*: их библиотеки — обычные скрипты игры.
|
||
* История, сохранения и перевод видят текст без вызова функций тегов (`parseText(text, false)`).
|
||
|
||
## API отрисовки для своих displayable
|
||
|
||
`render.ts`: `renpy.Displayable`, `renpy.Render` (`blit`, `subpixel_blit`, `fill`, `canvas`,
|
||
`subsurface`, `zoom`), `renpy.render`, `renpy.redraw`, `Text.set_text`. Дерево рендера
|
||
превращается в DOM и перерисовывается, пока элемент на странице.
|
||
|
||
## Настройки игры
|
||
|
||
`preferences` — объект настроек плеера: `text_cps`, `afm_time`, `afm_enable`, `fullscreen`,
|
||
`transitions`, `language`, `volumes[...]`, `get_volume`/`set_volume`, `get_mute`/`set_mute`,
|
||
`get_all_mixers`; `default preferences.x = ...` добавляет поле. `Color(...)` — настоящий `Color`
|
||
Ren'Py (`interpolate`, `tint`, `shade`, `hexcode`, `replace_*`, `rgb`/`hls`/`hsv`).
|
||
`renpy.fetch` отправляет запрос из браузера (нужен CORS на сервере); без сети игра получает
|
||
`FetchError`, как в Ren'Py.
|
||
|
||
Шрифты: `FontGroup().add(файл, от, до)` собирается в одно CSS-семейство с `unicode-range`.
|
||
`config.mouse_displayable = MouseDisplayable(...)` и `config.mouse` меняют курсор.
|
||
|
||
## Чего пока нет
|
||
|
||
* Шейдеры и сетки (`renpy.register_shader`, ATL `shader`/`mesh`, `u_*`, `gl_*`), поэтому
|
||
шейдерные эффекты текста (`{wave}`) и размытие через `blur.rpy` в профилях пропускаются;
|
||
частичное `additive` (0 < x < 1).
|
||
* Live2D.
|
||
* Снимки экрана в слотах сохранения и импорт `.save` Ren'Py.
|
||
* Пропуск только прочитанного текста (`preferences.skip_unseen` сохраняется, но не действует).
|