Utility and polishing + bag fixes

This commit is contained in:
Oleksandr Vlasiuk
2026-08-14 15:03:43 +03:00
parent 250f4a0d2c
commit 1f72420da0
45 changed files with 2542 additions and 1618 deletions
+69
View File
@@ -0,0 +1,69 @@
# Health bar для дестройбл-елементів (2026-08-13)
Референс-скріншот: прямокутний хелз бар з бордером, синя заливка HP,
чорним — вже відняте попередніми ударами, білим — відняте саме поточним
ударом (з коротким затуханням у чорне), число нанесеного урону над баром.
Нехай 10 урону за удар, 100хп у цілого ящика.
## `BreakablePropC` — перехід з дискретного лічильника хітів на HP
`HITS_PER_STAGE`/`hitsOnStage` повністю видалені. `BreakableProp` тепер
несе `currentHp`/`maxHp` (`MAX_HP = 100`, `export`-нутий, щоб `HealthBarC`
рахував той самий `0..1` дріб без дублювання числа) + `startStageNumber`/
`totalPossibleStages` — реальні номери з `_SN` у назвах стейдж-нод (не
вигадані), з яких рахується, скільки HP пошкоджений з коробки крейт вже
має "по дефолту" (пошкоджені S2/S3-старт крейти стартують не з 100).
`hit()` тепер: відняти `HIT_DAMAGE`, повідомити `HealthBarC.onHit(...)`,
знищити на HP<=0 (раніше — "просунувся за останній стейдж"), інакше —
перевести `stageIndex` на `Math.floor((1 - currentHp/maxHp) *
totalPossibleStages)` (з відступом на `startStageNumber`), змаплений у
межі власного (можливо короткого) масиву стейджів.
## `HealthBarC.ts` — новий контролер, world-tracking DOM-бари
Одна мапа `BreakableProp -> BarInstance`, живиться з `BreakablePropC.hit()`
через `onHit`/`onDestroyed` (аналогічний DI-паттерн до `ResourceC.setFlyTarget`).
**Позиціювання**: `position:fixed` + сирі px з `canvasRect` (та ж техніка,
що й `HudC.getWorldAnchorPosition`, лише в протилежний бік — тепер
винесена в `src/utils/screenWorldProjection.ts`, обидва напрямки). Точка
прив'язки — реальний `Box3().setFromObject(prop.root)` (верх+центр X/Z),
не вгаданий офсет.
**Три кольори — чистий CSS, без пофреймової JS-анімації**: `.health-bar__white`
й `.health-bar__blue` — два накладені div. На кожен хіт: білий миттєво
(`transition-duration: 0s`) стрибає на ПОПЕРЕДНІЙ `%`, форс-reflow через
`offsetWidth`, потім і білий (з `transition-delay`), і синій одразу
виставляються на ПОТОЧНИЙ `%` — синій доїжджає без затримки, білий
"зависає" на старому значенні й наздоганяє з лагом, показуючи чорний трек
під собою в проміжку. Ніякого `requestAnimationFrame`/tween — сама
CSS-transition timing і є ефектом.
**Авто-приховування**: `idleTime` рахується щокадру, `>= HIDE_DELAY_S` (2с)
без нового хіта — `is-hiding` клас + `FADE_OUT_MS` (250мс) opacity-transition,
потім видалення з DOM. Скидається на 0 при кожному `onHit`. `onDestroyed`
видаляє бар негайно (порожній бар не має лишатись висіти).
**Числа урону — кілька раундів фідбеку, фінал**:
- Спочатку плавали вгору з затуханням — користувач попросив натомість
різку появу непрозорого числа (`-webkit-text-stroke`, не text-shadow-глов)
з різким скейл-панчем до 1.5x + ротейтом і поверненням, і тільки ПОТІМ
затуханням (не рухом).
- Ротейт — послідовно звужувався: спершу довільний напрямок/кут, потім
користувач уточнив "тільки по годинниковій стрілці, до 2 години дня"
(тобто 0..60°, `--damage-rotate`, рандомізується в JS на кожен спавн,
читається в keyframe через `var()`).
- **Баг знайдений і виправлений**: затухання на спокої (force=0, у
контексті джойстика — не плутати з цим, тут йдеться про сам панч)
показувало прозору прогалину замість базового кольору, бо альфа
інтерполювалась до 0 — фікс: альфа фіксована, змінюється лише
RGB-канал (той самий принцип пізніше повторився і в джойстику, див.
нижче).
- Тривалість/розмір/швидкість анімації (920мс, +20% розмір шрифту,
expo-out крива "швидкий старт — повільний кінець") — прямі числові
правки за проханням користувача.
## `src/css/health-bar.css` — новий файл
Слідує тому ж house convention, що й `ui.css` (одна `--health-bar-width`
змінна, `--lvh` не сирий `vh`) — **окремо зазначено користувачем не
чіпати**: файл (як і `ui.css`) свідомо не отримав landscape
`@media`-блоку і досі на `vh`, не `rem`/`%` — відомий, прийнятий
відступ від Day 8 чекліста, відкладений на потім.