Document Day 7/8 work in CLAUDE.md (weapon trail, resource pickup redesign, HUD overhaul)
Was committed stale in the previous push — catches it up with WeaponTrailC, SparkleFxC pooling, ResourceC's bounce/flash/shrink/perspective-compensation redesign, the HudC UI overhaul, and PayZoneC's deposit-flight fixes. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -27,9 +27,12 @@
|
||||
src/controllers/
|
||||
PlayerC.ts - джойстик-рух (nipplejs), AABB-колізії з "colliders",
|
||||
бій: неперервний AoE-swing по всіх breakable-цілях в
|
||||
зоні ураження, перебивається рухом
|
||||
зоні ураження (240°-конус, FACING_DOT_THRESHOLD=-0.5,
|
||||
Day 7 — див. "Кут ураження"), перебивається рухом
|
||||
TestSceneC.ts - завантажує ZombiePunk_Map.glb, /collider/i -> hidden+colliders,
|
||||
ставить cannon Wall-тіла на все, крім Lootable-крейтів
|
||||
ставить cannon Wall-тіла на все, крім Lootable-крейтів;
|
||||
ініціалізує всі VFX/HUD-контролери (PropVfxC,
|
||||
SparkleFxC, WeaponTrailC, HudC) в правильному порядку
|
||||
CameraFollowC.ts - камера-слідкувач, obstacle-avoidance через Raycaster
|
||||
по тому ж масиву colliders (НЕ торкались)
|
||||
PhysicsC.ts - PhysicsLayer enum, PhysicsBody (Box/Sphere+cannon Body
|
||||
@@ -37,26 +40,63 @@ src/controllers/
|
||||
BreakablePropC.ts - парсить групу "Lootable" в мапі, S1/S2/S3 damage-stages,
|
||||
2 хіти на стейдж, hit() advance stage / повне
|
||||
знищення (tween-джус, Day 6), дропає ресурси
|
||||
ResourceC.ts - спавн ресурсів "розльотом" від цілі + автозбір
|
||||
(Day 5, незмінно) — НЕ знає про Pay Zone/гравця;
|
||||
візуал — клон реального "UI_Wood" з мапи
|
||||
(fallback-куб про запас), createVisual() — публічний
|
||||
доступ до цього візуалу для інших контролерів
|
||||
PayZoneC.ts - Day 6: окремо зливає ResourceC.getCollectedCount() в
|
||||
WeaponTrailC.ts - Day 7: hand-rolled screen-facing ribbon-шлейф за
|
||||
битою під час замаху (samples PlayerC.getWeaponAnchor(),
|
||||
обчислює "кінець бити" з реальної local bbox, не
|
||||
вгадує offset), тає/звужується за час, не тон-мап,
|
||||
toggled через PlayerC.updateCombat (isAttacking)
|
||||
ResourceC.ts - Day 7: спавн ресурсу з крейта -> scatter -> 2 баунси
|
||||
(відчутні, БЕЗ ротейту) -> на 2-му баунсі: білий
|
||||
флеш (окремий additive-оверлей-меш, БЕЗ
|
||||
squash-and-widen — чистий uniform shrink, тримається,
|
||||
не пружинить назад) + SparkleFxC-вибух зірочок ->
|
||||
staggered (по черзі, не купою) політ до
|
||||
HudC.getWorldAnchorPosition() (ціль пере-семплюється
|
||||
ЩОКАДРУ, не застигає, якщо камера рухається) з
|
||||
компенсацією перспективи (див. RESOURCE_ICON_BASE_SCALE,
|
||||
нижче) -> яскравіє й зникає рівно на іконці. НЕ знає
|
||||
про Pay Zone/гравця; візуал — клон реального
|
||||
"UI_Wood" з мапи; createVisual() — публічний доступ
|
||||
до цього візуалу (без баунс/флеш начинки) для інших
|
||||
контролерів (PayZoneC)
|
||||
PayZoneC.ts - Day 6/8: окремо зливає ResourceC.getCollectedCount() в
|
||||
Pay Zone (вузол мапи "UI_Interactive_Zone_02"), по
|
||||
одному ресурсу, тільки поки гравець стоїть в зоні;
|
||||
зникає після RESOURCES_TO_CLOSE_ZONE доставлених
|
||||
(зараз 20, підкручено після Day 6 — див. секцію
|
||||
"прогрес-заповнення зони"); росте плаский
|
||||
fill-overlay квад по мірі заповнення; політ депозиту
|
||||
летить з HudC.getWorldAnchorPosition(), не з гравця
|
||||
HudC.ts - лічильник ресурсу (іконка+число) у правому верхньому
|
||||
куті, DOM-оверлей в #ui; володіє "світовою" точкою
|
||||
(дитина камери), куди летять зібрані ресурси і
|
||||
звідки стартує політ депозиту в Pay Zone
|
||||
(зараз 20); росте плаский fill-overlay квад по мірі
|
||||
заповнення; політ депозиту (HudC.getWorldAnchorPosition()
|
||||
-> Pay Zone) БЕЗ ротейту, з тією ж компенсацією
|
||||
перспективи й базовим розміром, що й ResourceC
|
||||
(RESOURCE_ICON_BASE_SCALE, спільна константа —
|
||||
інакше токен виглядає більшим за ресурс, що щойно
|
||||
був на тому ж місці), плюс окремий
|
||||
DEPOSIT_FLIGHT_SCALE_MULTIPLIER для локального тюнінгу
|
||||
HudC.ts - Day 8: лічильник ресурсу — реальний дизайнерський
|
||||
ассет (resourceCounterBgSrc, Tool_15.webp з temp/,
|
||||
планка вже вбудована в картинку, не окрема іконка),
|
||||
DOM-оверлей в #ui, стилі в src/css/ui.css (не inline
|
||||
<style>); getWorldAnchorPosition() — СПРАВЖНЯ
|
||||
screen-to-world проєкція (getBoundingClientRect()
|
||||
правого краю плейта + unproject через камеру), НЕ
|
||||
вгаданий локальний офсет від камери (той підхід
|
||||
видалений повністю, разом з WORLD_ANCHOR_LOCAL_OFFSET)
|
||||
SparkleFxC.ts - Day 7: пул із 30 зіркових мешів/матеріалів (pop-in
|
||||
Back.Out -> hold -> fade-out через TweenC), жодних
|
||||
нових Mesh/Material під час гри — spawnBurst() бере
|
||||
вільний слот з пулу; використовується ResourceC на
|
||||
2-му баунсі
|
||||
PropVfxC.ts - Day 6: завантажує дизайнерські quarks.art VFX-префаби
|
||||
(JSON з temp/, sparks/dust/debris) для хіту/знищення
|
||||
крейтів
|
||||
ThreeC.ts/CameraC.ts - базовий сетап three.js/камери від SDK
|
||||
resources/meshes/ - ZombiePunk_Map.glb, ZombiePunk_Character.glb
|
||||
resources/images/ - icon_wood.webp (Icon_Wood, витягнутий з мапи), images.ts
|
||||
resources/images/ - resource_counter_bg.webp (Tool_15.webp з temp/,
|
||||
дизайнерський плейт лічильника), images.ts
|
||||
(icon_wood.webp/iconWoodSrc видалені — стали
|
||||
осиротілими після заміни на resourceCounterBgSrc)
|
||||
resources/vfx/ - VFX_Lootable_Hit.json, VFX_Lootable_Destroy.json
|
||||
(quarks.art префаби, копії з temp/, реально
|
||||
використовуються з коду — див. PropVfxC)
|
||||
```
|
||||
|
||||
`TriggerC.ts` (beginContact/endContact -> onEnter/onExit) і кінематичне
|
||||
@@ -870,8 +910,11 @@ position прямо з GLB node transforms). Жодна з цих гіпотез
|
||||
- `ResourceC`/`BreakablePropC` — нові файли. `PlayerC.ts`/`TestSceneC.ts`/
|
||||
`PhysicsC.ts` — модифіковані. `CameraFollowC.ts`/`ThreeC.ts` — не торкались.
|
||||
`TriggerC.ts` — був створений і видалений в межах цієї ж сесії (див. "Файли").
|
||||
- Ще не закомічено в git (working tree) — користувач сам вирішує коли
|
||||
комітити.
|
||||
- Закомічено й запушено в `origin/master` 2026-08-12 (commit `4a22a9b`,
|
||||
"Add physics/combat foundation, resource pickup flow, VFX polish, and
|
||||
HUD") — усе, що описано в цьому файлі до Day 8 включно, вже в репо.
|
||||
`stats.html` (rollup-visualizer, артефакт білда) свідомо НЕ закомічено —
|
||||
не вихідний код, генерується заново при білді.
|
||||
- Якщо наступного разу знову треба буде правити combat: зона ураження —
|
||||
та сама `INTERACTION_REACH`-аура, що й раніше використовувалась для
|
||||
single-target пошуку (`findNearbyObstacle`, лишився для косметичного
|
||||
@@ -908,3 +951,211 @@ position прямо з GLB node transforms). Жодна з цих гіпотез
|
||||
відсутність зайвих текстур навколо Pay Zone) — стан на кінець Day 5/6;
|
||||
усе, що сталось після (HUD, камера, VFX, прогрес-бар зони), має власні
|
||||
"Перевірено" нотатки нижче за текстом.
|
||||
|
||||
## Day 7: VFX — шлейф зброї, доопрацювання ресурсів (2026-08-12)
|
||||
|
||||
**Важливо про верифікацію в цій секції і нижче**: користувач явно попросив
|
||||
припинити самостійні Playwright/агент-перевірки ("Досить самостійно щось
|
||||
перевіряти і тестувати" — [[feedback-verification-pace]] в пам'яті) —
|
||||
тож усе нижче перевірено ВИКЛЮЧНО через живий фідбек користувача в грі
|
||||
(він тестує, повідомляє що не так, я виправляю), а НЕ через автоматичні
|
||||
скріншоти/Playwright, як було в Day 5/6. Це свідоме рішення, не пропуск.
|
||||
|
||||
### `WeaponTrailC.ts` — новий контролер, шлейф-"вітер" за битою під час замаху
|
||||
Користувач попросив ефект вітру за зброєю під час замаху — hand-rolled
|
||||
screen-facing ribbon (не `three.quarks`, бо трейл має слідкувати за
|
||||
bone-driven точкою щокадру, а не грати фіксований дизайнерський burst,
|
||||
як `PropVfxC`). Технічно: кожен кадр поки `PlayerC.isAttacking` — семплить
|
||||
world-позицію "кінця бити" (обчислюється з реальної local bounding box
|
||||
всіх мешів під `Tool_1`, НЕ вгаданий offset — `computeLocalTipOffset()`,
|
||||
з підстроюваним `TIP_INSET_FRACTION` — трохи не на самий кінець, за
|
||||
проханням користувача), тримає ring buffer точок з віком, будує ribbon-
|
||||
геометрію (пара left/right вершин на точку, перпендикуляр = cross(tangent,
|
||||
viewDirection камери — камера не обертається, тож напрямок погляду
|
||||
захоплений один раз при `init()`), затухання ширини/кольору за
|
||||
`FADE_POWER`-кривою (не лінійно — "не таким плавним", різкіший спад),
|
||||
additive blending, без тон-мапінгу. `PlayerC.updateCombat` викликає
|
||||
`WeaponTrailC.setActive(true/false)` на початку/кінці атаки.
|
||||
|
||||
### `ResourceC.ts` — повний редизайн pickup-анімації (кілька раундів фідбеку)
|
||||
Стара версія (Day 5): scatter -> settle -> instant collect/fly, з
|
||||
ротейтом (`SPIN_SPEED`). Користувач попросив: прибрати ротейт, додати
|
||||
2 баунси від землі, на 2-му баунсі — білий флеш + стиск + вибух зірочок,
|
||||
потім зникнення. Фінальний стейт-машин: `scatter` -> `bounce` (2 цикли,
|
||||
`BOUNCE_HEIGHTS`/`BOUNCE_DURATIONS`, index 0->1) -> `impactHold` (флеш +
|
||||
стиск на 2-му баунсі) -> `toTarget` (політ до HUD).
|
||||
|
||||
**⚠️ Знайдений і виправлений баг: флеш-оверлей був зміщений, а не поверх ресурсу**
|
||||
`buildFlashOverlays()` клонував меш і чіпляв клон як ДИТИНУ САМОГО МЕША
|
||||
(`mesh.add(overlay)`), а не як сиблінга під тим самим батьком (як робить
|
||||
`BreakablePropC.buildStageVisual`). `mesh.clone()` копіює ЛОКАЛЬНУ
|
||||
трансформацію меша (відносно ЙОГО батька) — вставлена на рівень глибше,
|
||||
та сама трансформація інтерпретувалась вже у ВЛАСНІЙ системі координат
|
||||
меша, тобто оверлей був зміщений/спотворений, а не коінцидентний з
|
||||
мешем. **Фікс**: `overlay.position/rotation/scale.set(...)` в identity
|
||||
одразу після clone(), перед `mesh.add(overlay)`.
|
||||
|
||||
**Стиск (squash) — три ітерації**:
|
||||
1. Squash-and-widen (X/Z шириться, Y стискається, пружинить назад) —
|
||||
користувач: "ресурси на прикінці анімації збільшуються, мають навпаки
|
||||
зменшуватись" — розтягнення X/Z понад 1.0 читалось як РІСТ.
|
||||
2. Uniform shrink (`scale.setScalar(1-shrink)`, без розтягування) —
|
||||
краще, але користувач ще раз: "має бути одного розміру від початку до
|
||||
кінця" про `toTarget`-фазу конкретно.
|
||||
3. **Фінал**: стиск ЛИШЕ на 2-му баунсі (`impactHold`, тримається, не
|
||||
пружинить назад — "без повернення до початкового розміру"), а сама
|
||||
`toTarget`-фаза взагалі НЕ чіпає scale (тільки position + opacity
|
||||
флешу-конвергенції). Одного разу я неправильно прибрав СТИСК НА
|
||||
БАУНСІ замість того, щоб залишити його — користувач поправив: "Ти
|
||||
прибрав зміну розміру при баунсі. Я тобі писав не про це" — стиск на
|
||||
баунсі БУЛО повернено, лишається бажаним ефектом.
|
||||
|
||||
**⚠️ Знайдений і виправлений баг: "зміна розміру під час польоту" — насправді перспектива, не scale**
|
||||
Після всіх фіксів вище користувач далі бачив "зростання" саме під час
|
||||
`toTarget`-польоту — а код `toTarget` взагалі не чіпав `.scale`. Причина:
|
||||
камера перспективна, а ціль польоту (`HudC.getWorldAnchorPosition()`)
|
||||
сидить БЛИЗЬКО до камери (`ANCHOR_DISTANCE=2.5`), тоді як крейт (звідки
|
||||
ресурс вилітає) — далеко (~12+ одиниць, через `CAMERA_OFFSET=(0,9,-9)`).
|
||||
Наближення до камери саме по собі візуально збільшує об'єкт (perspective
|
||||
foreshortening), без жодної зміни `.scale` в коді. **Фікс**: компенсація —
|
||||
кожен кадр рахую `currentDistance = camera.position.distanceTo(mesh.position)`,
|
||||
зберігаю `startDistanceFromCamera` (дистанція в момент старту `toTarget`)
|
||||
і `baseScale` (розмір після баунсу), виставляю
|
||||
`scale = baseScale * (currentDistance / startDistanceFromCamera)` —
|
||||
компенсує наближення так, що АПАРЕНТНИЙ (екранний) розмір лишається
|
||||
сталим, яким був щойно після баунсу, незалежно від реальної world-space
|
||||
дистанції. **Урок**: "resource visually grows/shrinks" не завжди означає
|
||||
"хтось десь чіпає .scale" — перспективна камера сама змінює апарентний
|
||||
розмір при зміні дистанції, це треба явно компенсувати, якщо небажано.
|
||||
|
||||
**⚠️ Знайдений і виправлений баг: ціль польоту застигала, якщо камера рухалась**
|
||||
`resource.to` виставлявся ОДИН РАЗ (`this.flyTarget()`) при вході в
|
||||
`toTarget` — якщо камера рухалась під час ~0.5с польоту (гравець йде,
|
||||
camera-follow), ресурс летів у застарілу world-точку, яка вже не
|
||||
збігалась з реальною позицією іконки на екрані (користувач: "втрачають
|
||||
потрібну позицію і летять не туди"). **Фікс**: `this.flyTarget()`
|
||||
викликається ЩОКАДРУ всередині `toTarget`-блоку, не один раз — ресурс
|
||||
щокадру перецілюється на актуальну позицію.
|
||||
|
||||
**Інші правки за фідбеком**: баунси зроблені відчутнішими (висота
|
||||
`[0.16,0.08]->[0.4,0.22]`); флеш подовжений і РОЗВʼЯЗАНИЙ від швидкості
|
||||
стиску (`FLASH_DURATION` vs `SHRINK_RAMP_DURATION` — окремі константи,
|
||||
інакше подовження одного тягне інше); одна спроба зробити політ
|
||||
"пришвидшеним" (ease-in `t²` замість smoothstep) БУЛА ВІДКОЧЕНА —
|
||||
причина: `CONVERGE_START_FRACTION`-конвергенція тригериться по часу `t`,
|
||||
а ease-in робить просторовий прогрес значно повільнішим за часовий,
|
||||
тож ресурс зникав, не доїхавши до цілі ("зникають раніше часу") —
|
||||
**урок**: якщо якийсь ефект прив'язаний до сирого `t`, зміна кривої
|
||||
`eased` для позиції може розсинхронізувати їх — тримати узгодженим або
|
||||
привʼязувати ефект до фактичного пройденого шляху, не до часу.
|
||||
|
||||
### `SparkleFxC.ts` — новий контролер, пул зіркових спалахів
|
||||
Спочатку — наївна версія (`new Mesh`/`new MeshBasicMaterial` на кожен
|
||||
вибух, 5 зірок на баунс). Користувач попросив пулінг (Day 7 бриф явно
|
||||
рекомендує "use pools for VFX", і кожен крейт може дати 2-5 ресурсів,
|
||||
кожен зі своїм вибухом = 10-25 create+GC циклів за секунду). **Фінал**:
|
||||
`POOL_SIZE=30` зіркових мешів/матеріалів створюються ОДИН РАЗ в `init()`
|
||||
(викликається з `TestSceneC`), приховані/scale=0; `spawnBurst()` шукає
|
||||
вільні слоти (`inUse`), активує (позиція/lookAt/scale/opacity), звільняє
|
||||
в `fadeOut.onComplete`. Форма зірки — `ShapeGeometry` з 4-промінним
|
||||
контуром (outer/inner radius alternating), не sprite-атлас (немає такого
|
||||
ассету в проєкті). Анімація: pop-in (`Back.Out`) -> hold -> fade-out,
|
||||
через `TweenC` (обидві ланки чейну додані окремо — той самий Day 6 баг з
|
||||
`.chain()` враховано одразу).
|
||||
|
||||
## Day 8: UI — резорс-каунтер (2026-08-12)
|
||||
|
||||
Референс — скріншот іншої гри ("Zombie Invasion") з двома стековани
|
||||
лічильниками (дерево + метал); у нас лише один тип ресурсу, тож зроблено
|
||||
тільки один лічильник, без плейсхолдера під другий (за проханням
|
||||
користувача, поки не підтверджено, що другий ресурс дійсно буде).
|
||||
|
||||
### Реальний дизайнерський ассет замість CSS-пілла
|
||||
Користувач: "Tool_15 знайди цей файл в temp. Це юай для каунтера
|
||||
ресурсу." `temp/Tool_15.webp` (184×71, темна округла плата з діагональною
|
||||
деревʼяною планкою, вже вбудованою в саму картинку) — скопійований у
|
||||
`src/resources/images/resource_counter_bg.webp`, підключений через
|
||||
`images.ts` (`resourceCounterBgSrc`, той самий `ConvertToBase64WhenRelease`-
|
||||
паттерн). Стара кругла іконка-рамка + окремий `<img>` (з `icon_wood.webp`)
|
||||
прибрані повністю — планка вже частина фонового зображення.
|
||||
`icon_wood.webp`/`iconWoodSrc` після цього стали осиротілими і видалені.
|
||||
|
||||
### Стилі винесені в `ui.css`, живлені реальним аспектом і CSS-змінною
|
||||
Користувач: "Всі стилі для юай мають бути в css файлі, у нас є відповідний
|
||||
файл вже" — весь inline `document.createElement("style")` з `HudC.ts`
|
||||
прибраний, стилі перенесені в `src/css/ui.css` (вже підключений в
|
||||
`index.html`). `HudC.ts` лишає в JS тільки `holder.style.backgroundImage`
|
||||
(шлях до ассету відомий лише в runtime через build-пайплайн, статичний
|
||||
CSS-файл цього не може). Розмір плейта: спочатку `width`+`height` окремо
|
||||
в `vh` (руками підібрана пропорція 184:71) — користувач: "не подобається,
|
||||
що задана і висота і ширина, давай контролювати через аспект рейтіо" ->
|
||||
`aspect-ratio: 184/71` замість другого числа. Потім: CSS custom property
|
||||
`--hud-width` на `.resource-hud`, і `font-size: calc(var(--hud-width) *
|
||||
0.175)` замість фіксованого `vh` — користувач змінював `width`, шрифт не
|
||||
слідував; тепер один параметр (`--hud-width`) керує і розміром плати, і
|
||||
шрифтом (успадковується вниз по DOM).
|
||||
|
||||
### Дві CSS-анімації замість JS-коду (Day 8 технічна вимога)
|
||||
"Use built-in animations/transitions instead of changing elements through
|
||||
code" — (1) `.resource-hud` грає `resource-hud-enter` (fade+slide) один
|
||||
раз при монтуванні, самостійно, без JS-таймингу; (2) `.resource-hud__plate`
|
||||
(НЕ сам `.resource-hud` — окремо, дивись нижче чому) грає
|
||||
`resource-hud-bump` при кожній зміні числа — `HudC.update()` лише
|
||||
toggle-ить клас `is-bumping` (remove -> force reflow через `offsetWidth`
|
||||
-> add), сам keyframe рахує браузер.
|
||||
|
||||
**⚠️ Знахідка: анімацію не можна вішати на ТОЙ САМИЙ елемент, що вже має іншу**
|
||||
Спочатку bump-анімація була на `.resource-hud__count` (сам текст) —
|
||||
користувач: "Анімація має бути на всю юайку не тільки на каунтер". Але
|
||||
просто перенести на `.resource-hud` (той самий елемент, що вже грає
|
||||
`resource-hud-enter`) НЕ можна: перемикання класу, що змінює
|
||||
`animation-name` (навіть тимчасово, назад до того самого значення),
|
||||
ЗАВЖДИ перезапускає анімацію — тобто кожен збір ресурсу знову
|
||||
проганяв би fade+slide-in ("з'явлення") поверх бампу. **Фікс**: два
|
||||
вкладені div — зовнішній `.resource-hud` (позиція/розмір + enter-анімація,
|
||||
статична), внутрішній `.resource-hud__plate` (фон+число разом,
|
||||
bump-анімація) — дві незалежні `animation`-лінії на двох елементах.
|
||||
|
||||
### `getWorldAnchorPosition()` — справжня screen-to-world проєкція
|
||||
Раніше (Day "HUD-лічильник"): фіктивний `Object3D`, дитина камери, з
|
||||
вгаданим локальним офсетом (`WORLD_ANCHOR_LOCAL_OFFSET`, підбирався на
|
||||
око, документований як "не точний screen-to-world розрахунок").
|
||||
Користувач: "Треба дістати позицію правого края юайки і направляти
|
||||
ресурси саме туди." **Фінал**: `getBoundingClientRect()` правого краю
|
||||
`.resource-hud__plate` (реальний DOM), конвертація в NDC відносно
|
||||
`ThreeC.renderer.domElement.getBoundingClientRect()` (canvas, НЕ
|
||||
`window.innerWidth/Height` — SDK рендерить у letterboxed 9:16 бокс,
|
||||
canvas-rect гарантовано збігається з тим, що бачить камера),
|
||||
`new Vector3(ndcX,ndcY,0.5).unproject(camera)` -> напрямок від камери ->
|
||||
точка на фіксованій `ANCHOR_DISTANCE=2.5` вздовж цього променя.
|
||||
Рахується ЖИВО при кожному викликі (не раз при init) — автоматично
|
||||
лишається коректним при resize/зміні орієнтації, без окремого resize-
|
||||
слухача. `Object3D`/`WORLD_ANCHOR_LOCAL_OFFSET`-підхід видалений
|
||||
повністю.
|
||||
|
||||
## PayZoneC: уніфікація депозит-флайту з ResourceC (2026-08-12)
|
||||
|
||||
`playDepositFlight` (політ токена з HUD в Pay Zone) використовував
|
||||
окремий TweenJS-based шлях, не звʼязаний з новою логікою `ResourceC`:
|
||||
мав ротейт (`mesh.rotation.y += 0.3`) і стартовий `scale=1` (дефолт
|
||||
свіжого `ResourceC.createVisual()`, без жодного стиску).
|
||||
|
||||
- **Ротейт прибрано** повністю (користувач: "ротейту не має бути").
|
||||
- **Компенсація перспективи** — та ж сама техніка, що й у
|
||||
`ResourceC.toTarget`, але в ПРОТИЛЕЖНИЙ бік: цей політ стартує БЛИЗЬКО
|
||||
до камери (HUD-анкер) і летить ДАЛІ (Pay Zone, зазвичай далі від
|
||||
камери) — без компенсації токен би візуально ЗМЕНШУВАВСЯ на льоту.
|
||||
- **⚠️ Знайдений і виправлений баг: токен був значно більшим за ресурс з наземної анімації**
|
||||
Причина: `ResourceC.createVisual()` не проходить через `SHRINK_AMOUNT`-
|
||||
стиск (той стосується лише "живих" `FlyingResource` з баунсом) — токен
|
||||
стартував з `scale=1`, тоді як ресурс, який щойно долетів на те саме
|
||||
місце з `ResourceC`, виглядав як `0.85`. **Фікс**: `RESOURCE_ICON_BASE_SCALE
|
||||
= 1 - SHRINK_AMOUNT` (0.85) винесений з `ResourceC.ts` як `export`,
|
||||
`PayZoneC` множить на нього. Плюс окремий `DEPOSIT_FLIGHT_SCALE_MULTIPLIER`
|
||||
(зараз `1`, користувач підкрутив до `0.3` в UI-сесії) — локальний
|
||||
тюнер розміру САМЕ цього польоту, не торкаючись спільної константи
|
||||
(яка вплинула б і на "земля->юай" анімацію).
|
||||
- **Урок**: коли два різні контролери візуально показують "той самий"
|
||||
ресурс в різних сценах польоту — тримати спільну константу базового
|
||||
розміру (`export`), а не дублювати магічне число, інакше вони
|
||||
розходяться, як тут.
|
||||
|
||||
Reference in New Issue
Block a user