ci / release (push) Successful in 5m5s
ci-platforms / build (amd64, windows, windows-2022) (push) Skipped
ci-platforms / build (arm64, darwin, macos-15) (push) Skipped
ci-platforms / build (amd64, darwin, macos-15-intel) (push) Skipped
ci / checks (push) Successful in 4m41s
ci / build (amd64, linux, ubuntu-24.04) (push) Successful in 7m14s
The remaining editor strings and undo step names; component, field, enum, setting, diagnostic and Script API texts under schema.*, enum.*, setting.*, diag.* and api.*; the launcher, the in-game Settings View with a Language setting, the CLI and aego schema show --lang. Every documentation page has a .ru.md translation; the site has a full Russian tree with hreflang, a language switch and ru/llms.txt; aego docs check --lang ru. New doc.tutorial and doc.recipe icons. Fix: an animator restored by a rewind prepares its controller before the replayed step.
246 lines
19 KiB
Markdown
246 lines
19 KiB
Markdown
---
|
||
id: camera
|
||
title: Камеры 2D
|
||
group: camera
|
||
group_title: Камеры 2D
|
||
---
|
||
# Камеры 2D
|
||
|
||
[«Камера 2D»](ref:engine.Camera2D) рисует вид, а виртуальные камеры решают, куда она смотрит. Каждая [«Виртуальная камера 2D»](ref:camera.VirtualCamera2D) — возможная поза. Видом управляет включённая камера с наибольшим приоритетом, а переключение между камерами идёт плавным переходом. Слежение, тряска и зоны — компоненты на виртуальных камерах; скрипты их запускают.
|
||
|
||
Быстрый старт: **Создать → Следящая камера** даёт узел с «Камерой 2D», «Виртуальной камерой 2D» и «Слежением камеры 2D». Укажите игрока в поле «Цель» и нажмите **Играть**.
|
||
|
||
| Компонент | Назначение |
|
||
|---|---|
|
||
| Виртуальная камера 2D | поза с приоритетом, масштабом, границами и переходом |
|
||
| Слежение камеры 2D | ведёт свою виртуальную камеру за целью |
|
||
| Тряска камеры 2D | настраивает тряску своей виртуальной камеры |
|
||
| Зона камеры 2D | поднимает камеру, пока цель внутри области |
|
||
| Мозг камеры 2D | заставляет «Камеру 2D» показывать другой выход |
|
||
|
||
Камеры работают во время игры и в `aego run`. В режиме редактирования панель «Сцена» показывает рамку камеры, мёртвую зону, границы и зоны.
|
||
|
||
---
|
||
id: camera/virtual
|
||
title: Виртуальные камеры
|
||
---
|
||
# Виртуальные камеры
|
||
|
||
Каждый кадр мозг выбирает по одной виртуальной камере на выход:
|
||
|
||
1. Включённая виртуальная камера с наибольшим [Приоритетом](ref:camera.VirtualCamera2D.Priority). При равных приоритетах выбирается камера, созданная раньше.
|
||
2. [«Зона камеры 2D»](ref:camera.CameraZone2D), внутри которой находится цель, поднимает свою камеру до приоритета зоны. При равенстве зона побеждает обычную камеру, а зона, в которую вошли позже, — более раннюю.
|
||
3. `camera.BlendTo` и `camera.Cut` перекрывают всё до вызова `camera.Release`.
|
||
|
||
Поза берётся из узла виртуальной камеры: его интерполированная позиция и поворот, а также [Масштаб](ref:camera.VirtualCamera2D.Zoom); 0 оставляет масштаб «Камеры 2D». «Слежение камеры 2D» на том же узле заменяет позицию. Трансформация узла никогда не меняется; камера двигает только вид.
|
||
|
||
В «Попробовать» скрипт Director по очереди поднимает **Close** и **Tilt**, каждую на две секунды, и вид плавно переходит к ним и обратно. Измените у Close «Масштаб», «Время перехода» или «Кривую перехода» в Инспекторе и посмотрите на следующий переход; скрипт лежит под сценой.
|
||
|
||
## Переходы
|
||
|
||
Когда активной становится другая камера, вид переходит от позы, которую показывает сейчас, к новой камере за её [Время перехода](ref:camera.VirtualCamera2D.BlendTime) по [Кривой перехода](ref:camera.VirtualCamera2D.BlendCurve). Переключение во время перехода начинается от текущего вида, а не от старой камеры. Масштаб меняется на экране равномерно. «Время перехода» 0 переключает сразу.
|
||
|
||
## Границы
|
||
|
||
[«Использовать границы»](ref:camera.VirtualCamera2D.UseBounds) держит видимую область внутри [Границ](ref:camera.VirtualCamera2D.Bounds) — прямоугольника в мире. Если по какой-то оси область меньше вида, вид центрируется на ней по этой оси.
|
||
|
||
---
|
||
id: camera/outputs
|
||
title: Выходы
|
||
---
|
||
# Выходы
|
||
|
||
Виртуальные камеры управляют главным выходом, если их [Выход](ref:camera.VirtualCamera2D.Output) не называет другой. «Камера 2D» показывает главный выход; добавьте [«Мозг камеры 2D»](ref:camera.CameraBrain2D) с тем же выходом, чтобы она показывала другой, например мини-карту. У каждого выхода своя активная камера, свои переходы и своя тряска. «Камера 2D», у выхода которой нет виртуальных камер, остаётся как есть.
|
||
|
||
В «Попробовать» мини-карта в углу — вторая «Камера 2D» с маленькой «Областью вывода» и «Мозгом камеры 2D» с выходом `map`; её собственная виртуальная камера следит за мячом издалека.
|
||
|
||
---
|
||
id: camera/follow
|
||
title: Слежение
|
||
---
|
||
# Слежение
|
||
|
||
[«Слежение камеры 2D»](ref:camera.CameraFollow2D) ведёт свою виртуальную камеру за [Целью](ref:camera.CameraFollow2D.Target).
|
||
|
||
Внутри **Мёртвой зоны** — части вида — цель движется свободно; (0.4, 0.4, 0.2, 0.2) — пятая часть в центре. Снаружи камера догоняет цель со скоростью, которую задаёт **Демпфирование**; при 0 камера следует жёстко.
|
||
|
||
**Упреждение** сдвигает камеру вперёд движущейся цели на столько секунд её скорости. **Макс. упреждение** ограничивает этот сдвиг, а **Сглаживание упреждения** — скорость его изменения. Когда цель прыгает дальше **Расстояния скачка**, например после телепорта, камера перемещается сразу.
|
||
|
||
Все поля с единицами измерения перечислены на странице [«Слежение камеры 2D»](ref:camera.CameraFollow2D).
|
||
|
||

|
||
|
||
Камера следует за интерполированной позой физического тела, поэтому движется плавно при любой частоте кадров. Демпфирование экспоненциальное: камера при 30, 60 и 144 кадрах в секунду приходит в одно и то же место. Когда цель телепортируется, вызовите `Snap()` у компонента или положитесь на «Расстояние скачка».
|
||
|
||
В «Попробовать» мяч катится по длинному склону. Поставьте «Демпфирование» в 0 для жёсткой камеры или расширьте «Мёртвую зону», чтобы мяч убегал вперёд.
|
||
|
||
---
|
||
id: camera/zones
|
||
title: Зоны
|
||
---
|
||
# Зоны
|
||
|
||
[«Зона камеры 2D»](ref:camera.CameraZone2D) меняет камеру, пока цель находится внутри её [Области](ref:camera.CameraZone2D.Area) — прямоугольника в пространстве узла зоны. Внутри [Камера](ref:camera.CameraZone2D.Camera) получает [Приоритет](ref:camera.CameraZone2D.Priority), [Масштаб](ref:camera.CameraZone2D.Zoom) и [Границы](ref:camera.CameraZone2D.Bounds) зоны; снаружи всё возвращается как было. Поля самой камеры никогда не меняются.
|
||
|
||
- Пустая «Камера» берёт виртуальную камеру на узле зоны; дайте ей низкий приоритет, чтобы она показывалась только через зону.
|
||
- Пустая «Цель» берёт цель слежения камеры зоны.
|
||
- Зоны используют точную позицию цели, а не интерполированную, поэтому один и тот же ввод всегда входит в зону на одном и том же кадре.
|
||
- Перекрывающиеся зоны: побеждает больший приоритет, затем зона, в которую вошли позже. Выход из одной зоны не влияет на другие.
|
||
|
||
В «Попробовать» фиолетовая область посреди склона — это зона: пока мяч катится через неё, вид переходит к более близкому неподвижному кадру, а после — обратно к следящей камере.
|
||
|
||
|
||

|
||
|
||
---
|
||
id: camera/shake
|
||
title: Тряска
|
||
---
|
||
# Тряска
|
||
|
||
В «Попробовать» ящик падает каждые две секунды, и при приземлении его скрипт вызывает `camera.Shake(0.9)`. Увеличьте «Макс. угол» или уменьшите «Степень» и «Затухание» у камеры, чтобы почувствовать разницу.
|
||
|
||
Тряской управляет травма — значение от 0 до 1 на каждый выход. `camera.Shake(0.4)` добавляет травму, а она убывает на [Затухание](ref:camera.CameraShake2D.Decay) в секунду. Вид сдвигается не больше чем на [Макс. смещение](ref:camera.CameraShake2D.MaxOffset) и поворачивается не больше чем на [Макс. угол](ref:camera.CameraShake2D.MaxAngle), с множителем «травма в [Степени](ref:camera.CameraShake2D.Exponent)», поэтому слабые удары остаются едва заметными. Если на активной камере нет «Тряски камеры 2D», берутся значения по умолчанию.
|
||
|
||
Движение берётся из детерминированного шума, поэтому повтор трясётся так же. Тряска никогда не трогает трансформацию узла и случайные числа игры.
|
||
|
||
Травма складывается и убывает в реальном времени. При «Затухании» по умолчанию 1,5 удар силой 0,6 проходит за 0,4 секунды:
|
||
|
||
```aes run
|
||
package demo
|
||
|
||
import (
|
||
"aego/camera"
|
||
"aego/log"
|
||
)
|
||
|
||
script Hits {
|
||
var frames int
|
||
|
||
func Ready() {
|
||
camera.Shake(0.6)
|
||
log.Info("hit, trauma " + string(camera.Trauma()))
|
||
}
|
||
|
||
func Update(dt float) {
|
||
frames++
|
||
if frames % 6 == 0 && frames <= 30 {
|
||
log.Info("trauma " + string(camera.Trauma()))
|
||
}
|
||
if frames == 30 {
|
||
camera.Shake(0.5)
|
||
camera.Shake(0.8)
|
||
log.Info("two hits, capped at " + string(camera.Trauma()))
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
## Доступность
|
||
|
||
**Настройки → Доступность → Тряска экрана** масштабирует любую тряску; 0 выключает её. «Меньше движения» выключает тряску и убирает упреждение. Травма по-прежнему убывает, поэтому геймплей, который читает `camera.Trauma()`, не затронут.
|
||
|
||
---
|
||
id: camera/time
|
||
title: Время и повторы
|
||
---
|
||
# Время и повторы
|
||
|
||
[«Шкала времени»](ref:camera.VirtualCamera2D.TimeDomain) решает, как переходы и тряска активной камеры считают время. `unscaled`, значение по умолчанию, использует реальное время: стоп-кадр при ударе с масштабом времени 0 не замораживает камеру. `game` следует за масштабом времени и паузой.
|
||
|
||
Слежение всегда использует игровое время: когда игра на паузе или идёт по шагам, неподвижная цель держит камеру неподвижной.
|
||
|
||
Перемотка и повтор сохраняют активную камеру, перекрытия, зоны и всё, что идёт в игровом времени. После перехода к другому моменту переход в реальном времени сразу завершается, а тряска в реальном времени сохраняет свою травму.
|
||
|
||
---
|
||
id: camera/scripting
|
||
title: Скрипты
|
||
---
|
||
# Скрипты
|
||
|
||
import "aego/camera"
|
||
|
||
func OnCollisionEnter(other NodeRef, c physics.Contact) {
|
||
if c.Normal.Y < -0.5 && c.NormalImpulse > 8 {
|
||
camera.Shake(0.35)
|
||
}
|
||
}
|
||
|
||
func Boss() coroutine {
|
||
yield camera.BlendTo(BossCam, 1.5)
|
||
yield waitSeconds(3)
|
||
camera.Release(0)
|
||
}
|
||
|
||
| Функция | |
|
||
|---|---|
|
||
| `Active() NodeRef`, `ActiveOn(output) NodeRef` | виртуальная камера, которая управляет выходом |
|
||
| `BlendTo(camera, seconds) Blend` | сделать камеру активной поверх приоритетов и плавно перейти к ней; 0 берёт её «Время перехода» |
|
||
| `Cut(camera)` | то же без перехода |
|
||
| `Release(seconds) Blend` | вернуть главный выход приоритетам |
|
||
| `Shake(trauma)`, `ShakeOn(output, trauma)` | добавить травму |
|
||
| `Trauma() float` | травма главного выхода |
|
||
| `LogicalPose() Pose` | поза без тряски и привязки к пикселям |
|
||
| `RenderPose() Pose` | поза, с которой нарисован главный выход |
|
||
| `ScreenToWorld(p)`, `WorldToScreen(p)` | пересчёт по последнему нарисованному виду, в пикселях выхода |
|
||
|
||
У `Blend` есть `Done()`, `Running()`, `Stop()` и сигнал `Completed(finished bool)`; `yield` ждёт его. Методы компонентов: `VirtualCamera2D.IsActive()`, `CameraFollow2D.Snap()` и `CameraShake2D.Add(trauma)`.
|
||
|
||
Каждый выход хранит свою травму:
|
||
|
||
```aes run
|
||
package demo
|
||
|
||
import (
|
||
"aego/camera"
|
||
"aego/log"
|
||
)
|
||
|
||
script Outputs {
|
||
func Ready() {
|
||
camera.Shake(0.3)
|
||
camera.ShakeOn("map", 0.9)
|
||
log.Info("main " + string(camera.Trauma()))
|
||
log.Info("active camera is nil: " + string(camera.Active() == nil))
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
id: camera/editor
|
||
title: Инструменты редактора
|
||
---
|
||
# Инструменты редактора
|
||
|
||
Редактор рисует рамки камер, мёртвые зоны и зоны, а во время игры показывает состояние активной камеры.
|
||
|
||
## Маркеры и рамки
|
||
|
||
- Выберите виртуальную камеру, чтобы перетаскивать её границы, или зону, чтобы перетаскивать её область. Следящая камера показывает свою рамку, мёртвую зону и линию к цели. Каждое перетаскивание — один шаг отмены.
|
||
- **Камера → Рамки камер** включает и выключает рамки на панели «Сцена». Во время игры панель «Игра» тоже рисует мёртвую зону активной камеры, её границы и зоны.
|
||
|
||
## Инспектор во время игры
|
||
|
||
Виртуальная камера показывает, активна ли она, свой приоритет, ход перехода и травму. **Смотреть через камеру** переносит панель «Сцена» в её позу. У «Слежения камеры 2D» есть **Привязать к цели**.
|
||
|
||
## Профилирование и проблемы
|
||
|
||
- **Профилировщик → Камера** перечисляет все выходы с их активной виртуальной камерой, масштабом и ходом перехода.
|
||
- «Проблемы» показывают слежение и тряску без виртуальной камеры ([CAM001](ref:CAM001)), зоны без камеры ([CAM002](ref:CAM002)), пустые прямоугольники ([CAM003](ref:CAM003)) и слежение без цели ([CAM004](ref:CAM004)).
|
||
|
||
---
|
||
id: camera/go
|
||
title: Go
|
||
---
|
||
# Go
|
||
|
||
cams := sdk.CamerasOf(ctx)
|
||
cams.Shake("", 0.5)
|
||
if k, err := cams.BlendTo(bossCam, 1.5, false); err == nil {
|
||
cams.OnBlendCompleted(k, func(finished bool) { ... })
|
||
}
|
||
|
||
У `Service` есть `Active`, `BlendTo`, `Release`, `Shake`, `Trauma`, `Logical`, `Render`, `View` и `Snap`; все они принимают имя выхода, `""` — главный выход.
|
||
|
||
Модуль публикует контракт `camera2d.adjust`; `render2d.cameras` просит его подправить вид каждой «Камеры 2D». Система `camera.update` (PostUpdate, работает и на паузе) выбирает камеры, продвигает переходы и зоны и гасит травму. Слежение и итоговая поза вычисляются при построении вида, один раз на выход и кадр. Модуль может масштабировать тряску, предоставив `camera2d.accessibility` с идентификаторами своих настроек.
|