Utility and polishing + bag fixes
This commit is contained in:
@@ -0,0 +1,120 @@
|
||||
# Камера: прибрано `lookAt`, лінійне зміщення замість орбіти (2026-08-12)
|
||||
|
||||
Фідбек від ментора користувача: замість `lookAt`-based слідкування камери
|
||||
за персонажем — краще визначити точку біля персонажа і зміщувати камеру
|
||||
відносно неї, залежно від напрямку погляду персонажа. Уточнення від
|
||||
користувача: **без orbit-behind** — це має бути суто лінійне зміщення
|
||||
позиції, кут камери взагалі не повинен обертатись.
|
||||
|
||||
## Що було
|
||||
`CameraFollowC.update()` щокадру: (1) демпінгував позицію камери до
|
||||
`targetPosition + offset + lookAhead` (це вже було чисте лінійне
|
||||
зміщення — `lookAhead` — той самий "зсув в напрямку погляду персонажа",
|
||||
про який казав ментор, він вже існував), (2) **окремо** демпінгував
|
||||
`smoothedLookAt`-точку і кожен кадр робив `camera.lookAt(smoothedLookAt)`
|
||||
— тобто поворот перераховувався з нуля щокадру з двох незалежно
|
||||
згладжених точок, а не одного узгодженого стану.
|
||||
|
||||
## Що зроблено (перша ітерація)
|
||||
- Прибрано `smoothedLookAt`, `LOOK_DAMPING`, і сам виклик `camera.lookAt()`
|
||||
з `update()` повністю. Позиційна частина (`offset` + `lookAhead` +
|
||||
obstacle-avoidance raycast) лишилась незмінною — вона й раніше була
|
||||
чистим translation, без жодного обертання.
|
||||
- Поворот камери відтепер **виставляється один раз** в `init()`:
|
||||
`camera.position.copy(target.position).add(offset); camera.lookAt(target.position);`
|
||||
— і після цього `update()` більше НІКОЛИ не торкається `camera.rotation`/
|
||||
`camera.quaternion`. Кут "заморожений" геометрично на старті й лишається
|
||||
таким назавжди, скільки б персонаж не розвертався.
|
||||
|
||||
## Доопрацювання: навіть без обертання камери відчувався рух "по колу" (2026-08-12)
|
||||
Користувач: коли персонаж РОЗВЕРТАЄТЬСЯ (не рухаючись при цьому), камера
|
||||
все ще відчутно "йде по колу". Причина — той самий `lookAhead`-вектор, що
|
||||
лишили в першій ітерації: він рахувався з напрямку, куди персонаж
|
||||
**дивиться** (`facing`, з `target.quaternion`), а не куди рухається.
|
||||
Навіть згладжений (`LOOK_AHEAD_DAMPING`), він все одно ОБЕРТАЄТЬСЯ разом
|
||||
з поворотом персонажа (наприклад, коли той розвертається на місці, щоб
|
||||
глянути на ящик) — а що обертається, те й тягне позицію камери по дузі
|
||||
навколо персонажа, хай і невеликій. Користувач хотів буквально "2 точки і
|
||||
пряма між ними" — жодної залежності від напрямку погляду.
|
||||
|
||||
**Перша спроба**: прибрав `lookAhead` повністю (`desiredPosition =
|
||||
targetPosition + offset`, без жодного додаткового вектора). Круговий рух
|
||||
дійсно зник, але користувач одразу зауважив: зникло й саме зміщення —
|
||||
"раніше зміщення було підходяще, єдина проблема була в тому, що воно йшло
|
||||
по колу". Тобто магнітуда/факт панорамування був потрібен, просто НЕ
|
||||
прив'язаний до повороту.
|
||||
|
||||
**Фінальне виправлення**: `lookAhead` вернув, але тепер рахується з
|
||||
**реального зміщення позиції персонажа між кадрами**
|
||||
(`targetPosition - previousTargetPosition`), а не з `target.quaternion`.
|
||||
`previousTargetPosition` — нове поле, оновлюється щокадру. Якщо кадровий
|
||||
рух менший за `MOVEMENT_EPSILON_SQ` (стоїть на місці — байдуже, як
|
||||
розвернутий) — цільовий look-ahead = нульовий вектор; якщо рухається —
|
||||
нормалізований напрямок руху × `LOOK_AHEAD_DISTANCE` (та сама магнітуда,
|
||||
що й була). Обидва варіанти йдуть через той самий `smoothedLookAhead.lerp`
|
||||
з `LOOK_AHEAD_DAMPING`, як і раніше — тільки джерело напрямку інше.
|
||||
Результат: розворот на місці = нуль руху = камера взагалі не рухається;
|
||||
ходьба = той самий пан вперед, що й був до всіх цих правок.
|
||||
**Урок**: "згладжений вектор, що обертається з об'єктом" все одно
|
||||
читається як орбітальний рух — згладжування прибирає різкість, а не
|
||||
кривизну; правильний фікс — прив'язати джерело напрямку до РУХУ
|
||||
(position delta), а не до facing/quaternion, а не просто видалити ефект.
|
||||
|
||||
Перевірено в браузері (Playwright) — рендер коректний з першого кадру і
|
||||
після ходьби/бою, без console-помилок.
|
||||
|
||||
## Доопрацювання ×3: зовсім не відчувалось, тримати зсув, миттєвий розворот на 180° (2026-08-12)
|
||||
Після руху-based lookahead користувач: "Немає зміщення взагалі". Причина —
|
||||
не баг у логіці (перевірив логуванням, числа рахувались вірно), а те, що
|
||||
**стара `lookAt`-версія давала подвійний ефект** (і зсув позиції, і
|
||||
доворот камери в той же бік щокадру), а зараз лишився тільки зсув позиції
|
||||
— і сама позиційна складова (`LOOK_AHEAD_DISTANCE=1.2`) була занадто
|
||||
малою, щоб щось означати з відстані ~12.7 од. (`(0,9,-9)` риг). Підняв до
|
||||
`4`, користувач сам потюнив назад до **`2`** (лишив цю зміну, не
|
||||
відкатувати).
|
||||
|
||||
Ще дві правки в тому ж повідомленні:
|
||||
- **"Камера після зсуву не має повертатись назад"** — `desiredLookAhead`
|
||||
тепер **окреме поле**, не локальна константа: оновлюється (`.copy(movement)...`)
|
||||
ТІЛЬКИ коли `movement.lengthSq() > MOVEMENT_EPSILON_SQ`, і просто НЕ
|
||||
чіпається, коли персонаж стоїть — замість `: new Vector3()` (нуль) в
|
||||
тернарному операторі, як було. Тобто пан тримається на місці, де
|
||||
зупинився, а не з'їжджає назад до центру, поки не з'явиться новий, ІНШИЙ
|
||||
напрямок руху.
|
||||
- **"Зроби анімацію плавнішою"** — `LOOK_AHEAD_DAMPING` знижений з `2` до
|
||||
`1.2` (повільніший ease).
|
||||
- **"Персонаж має розвертатись моментально, якщо ми змінюємо напрям на
|
||||
протилежний"** — це вже не про камеру, а про `PlayerC` (`updateMovement`):
|
||||
новий `OPPOSITE_TURN_THRESHOLD = Math.PI * (150/180)` (~150°). Якщо кут
|
||||
між поточним і цільовим facing (`quaternion.angleTo(...)`) перевищує цей
|
||||
порог — `quaternion.copy(facingRotation)` миттєво, інакше — старий
|
||||
капований `rotateTowards(facingRotation, MAX_TURN_SPEED * delta)`. Тобто
|
||||
тільки різкі розвороти "в протилежну сторону" миттєві, дрібні корекції
|
||||
курсу лишаються плавними, як і були.
|
||||
|
||||
## ⚠️ Знахідка: `camera_rotation_p`/`camera_rotation_l` (дизайнерський конфіг) виявився нежиттєздатним самостійно
|
||||
Спочатку спробував залишити кут камери таким, яким його виставляє
|
||||
`CameraC.setCamera()` з конфіг-параметрів `camera_rotation_p`/`_l`
|
||||
(дизайнер може їх тюнити через UI) — просто прибравши `lookAt` і НІЧОГО
|
||||
більше не додаючи. Результат: **порожнє темно-синє небо**, ні мапи, ні
|
||||
персонажа в кадрі. Причина: цей конфіг-кут ніколи насправді не був
|
||||
призначений працювати самостійно — `CameraFollowC` з першого ж комміту,
|
||||
що його додав, миттєво перезаписував поворот через `lookAt()` щокадру,
|
||||
тож ніхто й не міг помітити (чи потребу) тюнити `camera_rotation_p` під
|
||||
реальний рух — він був "мертвим" параметром, що впливав щонайбільше на
|
||||
один кадр до першого `update()`.
|
||||
|
||||
**Виправлення**: не покладатись на цей конфіг взагалі для follow-камери —
|
||||
рахувати фіксований кут геометрично з реального `offset` (`(0,9,-9)`) в
|
||||
момент `CameraFollowC.init()` (описано вище). Це гарантовано framing
|
||||
персонажа з самого старту, незалежно від того, що зараз стоїть в
|
||||
`camera_rotation_p`. **Урок**: значення з `configUIParams`/`globalSettings`
|
||||
не завжди відображають те, що реально відбувається в грі — перевіряти,
|
||||
чи щось інше (як тут `CameraFollowC`) не перезаписує їх одразу після
|
||||
встановлення, перш ніж покладатись на них як на джерело правди.
|
||||
|
||||
Перевірено в браузері (Playwright): після фіксу сцена рендериться коректно
|
||||
з самого старту (мапа/персонаж/крейти на місці, кут ідентичний
|
||||
попередньому вигляду), і лишається так само коректно framed після
|
||||
ходьби/бою/розвороту персонажа — камера просто зсувається лінійно, кут
|
||||
не змінюється.
|
||||
Reference in New Issue
Block a user