Utility and polishing + bag fixes
This commit is contained in:
@@ -0,0 +1,104 @@
|
||||
# HUD-лічильник + перенаправлення анімацій (2026-08-12)
|
||||
|
||||
Користувач попросив: (1) справжню 2D UI-іконку ресурсу з лічильником у
|
||||
правому верхньому куті, "як на скріні" (темна округла табличка + іконка в
|
||||
круглій рамці зліва + число справа), (2) ресурс замість миттєвого
|
||||
зникнення має анімовано летіти ДО цього лічильника, (3) політ у Pay Zone
|
||||
має бути ВІД лічильника до зони (не від гравця).
|
||||
|
||||
## Іконка
|
||||
Витягнув сам PNG/WebP з тієї ж текстури `Icon_Wood`, яку вже юзає 3D-меш
|
||||
`UI_Wood` (`src/resources/meshes/ZombiePunk_Map.glb`, `bufferView` з
|
||||
`images[6]`) — маленьким одноразовим Node-скриптом (парсинг glb JSON-чанка,
|
||||
пошук `images[].name === "Icon_Wood"`, зріз байтів з BIN-чанка за
|
||||
`bufferViews[bufferView]`). Зберіг як `src/resources/images/icon_wood.webp`
|
||||
(webp з альфа-каналом, 512×512). Новий `src/resources/images/images.ts`
|
||||
експортує `iconWoodSrc = ConvertToBase64WhenRelease("./icon_wood.webp")` —
|
||||
**той самий паттерн, що і `meshes.ts`** (той же helper з `@hitplay/ads_common`,
|
||||
викликаний з файлу в ТІЙ САМІЙ директорії, що й ассет — важливо: цей
|
||||
хелпер в dev/build режимі просто рядково замінює провідний `.` на
|
||||
`resources` (`ConvertToBase64WhenRelease.js`), а окремий AST-плагін
|
||||
(`convertToBase64InAST`), підключений через `defineConfigTemplate` в
|
||||
`vite.config.js`, на build-time переписує сам виклик у справжній inline
|
||||
`data:...;base64,...` — це працює для ВСІХ режимів (dev/build/export), не
|
||||
тільки для "export").
|
||||
|
||||
## HudC.ts — новий контролер
|
||||
DOM-паттерн підглянутий у `InstallBanner` з SDK (немає спільного
|
||||
DOM-builder helper-а в пакетах, усе руками через `document.createElement`
|
||||
+ власний `<style>`, що вставляється в `<head>`): статичний клас, монтує
|
||||
DOM-елемент у `#ui` (SDK-контейнер, `position:absolute`, зафіксований
|
||||
9:16 blocks — `calc(100vh*9/16)` × `100vh`, центрований — це і є "екран
|
||||
гри", не весь браузер, тож `top/right` у % рахуються відносно НЬОГО).
|
||||
`.resource-hud { pointer-events:none }` — щоб не перехоплював тач/клік від
|
||||
джойстика під ним. Стиль — власний CSS, вигаданий (в проєкті НЕ було
|
||||
жодного готового "плата/банер" стилю для запозичення — перевірено, в
|
||||
`ui.css`/`main.css` нуль хітів на `border-radius`).
|
||||
|
||||
Другий обов'язок `HudC` — **світова точка** (`worldAnchor`, порожній
|
||||
`Object3D`, дитина камери через `CameraC_internal.getCamera().add(...)`,
|
||||
локальний офсет — спочатку `(1.0, 0.8, -2.2)`, потім підкручено до
|
||||
`(1.0, 1.2, -2.0)` (див. нижче, чому)), яка приблизно проєктується туди,
|
||||
де візуально сидить DOM-іконка. **Це не точний screen-to-world розрахунок**
|
||||
(FOV/aspect не враховані математично) — просто підібраний на око офсет;
|
||||
якщо HUD переїде/зміниться розмір екрану, можливо треба підкрутити
|
||||
координати ще раз. `getWorldAnchorPosition()` — це і є точка, куди тепер
|
||||
летять ресурси (`ResourceC.setFlyTarget`) і звідки стартує депозит-політ
|
||||
(`PayZoneC.playDepositFlight`).
|
||||
|
||||
## Що змінилось у ResourceC/PayZoneC
|
||||
- `ResourceC`: `scatter` -> settle -> (якщо `flyTarget` заданий, а тепер
|
||||
він завжди заданий — `HudC.getWorldAnchorPosition`) новий стейт
|
||||
`toTarget` (0.5с, smoothstep + згасаюча дуга вгору, прямо до лічильника)
|
||||
-> `collect()`. Без `flyTarget` — стара миттєва поведінка (fallback).
|
||||
**На відміну від попередньої версії — НЕ телепортується на позицію
|
||||
гравця перед польотом** (той крок був заточений під "летить З гравця",
|
||||
зараз відповідь користувача про сам HUD не згадувала цей крок, тож
|
||||
прибрав його — політ іде прямо з місця, де ресурс осів, до лічильника).
|
||||
- `PayZoneC.playDepositFlight`: `from` тепер `HudC.getWorldAnchorPosition()`
|
||||
замість позиції гравця — "від лічильника до пей зони", як попросив
|
||||
користувач. Тригер (proximity до зони) не змінився — усе ще потребує
|
||||
стояння гравця в зоні, змінилась лише точка ВИЛЬОТУ візуалу.
|
||||
|
||||
Перевірено в браузері (Playwright, scratchpad): іконка рендериться коректно
|
||||
(512×512 webp, валідний `data:` URI, `naturalWidth`/`naturalHeight` не 0),
|
||||
лічильник в DOM оновлюється синхронно з `console.log`-ами збору (звірено
|
||||
скріншотом — "8" на екрані == 8-й `[ResourceC] gathered wood` в консолі).
|
||||
|
||||
## Доопрацювання: лічильник має бути "живим балансом", не lifetime-total (2026-08-12)
|
||||
Спочатку `HudC` показував `ResourceC.getCollectedCount()` напряму — тобто
|
||||
lifetime-суму, яка ТІЛЬКИ росте (депозит в Pay Zone на неї не впливав).
|
||||
Користувач попросив: число має рости при зборі І **зменшуватись при
|
||||
депозиті** — тобто показувати поточний "баланс", а не історичний тотал.
|
||||
|
||||
Розв'язання без нової мутабельної змінної (і без циклічного імпорту —
|
||||
`PayZoneC` вже імпортує `HudC` для `getWorldAnchorPosition()`, тож
|
||||
`HudC` імпортувати `PayZoneC` напряму означало б цикл):
|
||||
- `PayZoneC.getDepositedCount()` — новий публічний гетер, повертає
|
||||
внутрішній `deposited` (лічильник, який і раніше рахував "скільки вже
|
||||
влетіло в зону", просто не був назовні доступний).
|
||||
- `HudC.setBalanceGetter(fn)` — інжектований гетер (той самий паттерн, що
|
||||
й `ResourceC.setFlyTarget`/`onDestroyed` в `BreakablePropC`), замінив
|
||||
пряму залежність `HudC -> ResourceC`. `HudC` більше НЕ імпортує
|
||||
`ResourceC` взагалі.
|
||||
- `TestSceneC` зв'язує: `HudC.setBalanceGetter(() =>
|
||||
ResourceC.getCollectedCount() - PayZoneC.getDepositedCount())` — чиста
|
||||
похідна величина, рахується на льоту щокадру в `HudC.update()`, без
|
||||
жодного окремого "decrement"-виклику. Росте коли `collected` росте
|
||||
(щось зібрали), падає коли `deposited` росте (щось долетіло в зону) —
|
||||
саме по собі, без спеціальної синхронізації.
|
||||
|
||||
Перевірено: зібрав 7 ресурсів (консоль: `gathered wood (7 total)`), весь
|
||||
цей час стояв в Pay Zone -> усі 7 злились в зону протягом ~2.1с
|
||||
(`DEPOSIT_INTERVAL=0.3` × 7) -> лічильник на екрані повернувся до **0**,
|
||||
хоча `collected` лишився 7 — підтверджує, що баланс дійсно "живий", а не
|
||||
lifetime-сума.
|
||||
|
||||
## Доопрацювання: точка вильоту ресурсів була занизько (2026-08-12)
|
||||
`WORLD_ANCHOR_LOCAL_OFFSET` підняли з `(1.0, 0.8, -2.2)` до
|
||||
`(1.0, 1.2, -2.0)` — більший Y (вище в camera-space) і трохи менший |Z|
|
||||
(ближче до камери, тому той самий Y дає більше вертикальне зміщення на
|
||||
екрані через перспективу) — все ще підібрано на око, не розраховано
|
||||
математично з FOV/aspect. **Це найбільш "на око" підібрана частина
|
||||
роботи — якщо після цього фіксу політ все ще не влучає точно в іконку,
|
||||
підкрутити ці три числа ще раз** (в `HudC.ts`).
|
||||
Reference in New Issue
Block a user