diff --git a/docs/DEVLOG.md b/docs/DEVLOG.md index 02233a3..4cb9da2 100644 --- a/docs/DEVLOG.md +++ b/docs/DEVLOG.md @@ -751,16 +751,16 @@ git add -A && git commit -m "что изменилось" && git push ## Этап 41. Размер рыбы при вываживании — от абсолютного веса (0.1 кг → минимум, 100 кг → 2× лодки) -**Задача:** «размер рыбы в воде (когда её вытягиваешь) должен соответствовать её весу в кг, а не минимальному/максимальному весу вида; диапазон больше: 0.1 кг — максимально маленькая как сейчас, 100 кг — в 2 раза больше лодки». Первая ревизия этапа была лог-шкалой (средние рыбы 1–10 кг подросли до 0.9–1.4× лодки — «все рыбы сильно большие»); по решению заменена на линейную. Вторая ревизия: минимум опустили ещё — 0.1 кг с длины 19.6 px до **8 px** («ещё меньше»). Третья ревизия: **100 кг → 256 px** (×2 к 128, т.е. 4× лодки) и **1 кг → 20 px**; предложенная квадратичная шкала 3 якоря не держит монотонно (парабола по w: пик ~420 px на 61 кг, затем схождение к 256 px на 100 кг — кит меньше «средней» рыбы; квадратичная по ln w: провал до ~4 px у 0.2 кг) — взята степенная `L = 3.95 + 16.05·w^0.598`, точная по всем трём якорям и монотонная. +**Задача:** «размер рыбы в воде (когда её вытягиваешь) должен соответствовать её весу в кг, а не минимальному/максимальному весу вида; диапазон больше: 0.1 кг — максимально маленькая как сейчас, 100 кг — в 2 раза больше лодки». Первая ревизия этапа была лог-шкалой (средние рыбы 1–10 кг подросли до 0.9–1.4× лодки — «все рыбы сильно большие»); по решению заменена на линейную. Вторая ревизия: минимум опустили ещё — 0.1 кг с длины 19.6 px до **8 px** («ещё меньше»). Третья ревизия: **100 кг → 256 px** (×2 к 128, т.е. 4× лодки) и **1 кг → 20 px**; предложенная квадратичная шкала 3 якоря не держит монотонно (парабола по w: пик ~420 px на 61 кг, затем схождение к 256 px на 100 кг — кит меньше «средней» рыбы; квадратичная по ln w: провал до ~4 px у 0.2 кг) — взята степенная `L = 3.95 + 16.05·w^0.598`, точная по всем трём якорям и монотонная. Четвёртая ревизия (финальная): **явная узловая таблица пользователя** (веса — степени двойки, длины 16..256 px, «погрешность 10%»): степенная формула не покрыла таблицу в середине (на 25.6 кг было бы +24% к цифрам таблицы; локальный показатель кривой гуляет 0.26..0.61) — заменена линейной интерполяцией по log₂(веса) между узлами: узлы бьются точно (0%), кривая монотонна, вне 0.1–100 кг — кламп в края таблицы. **Решения:** -- **Новый хелпер `fishSizeFromW(w)`** (секция «ОТРИСОВКА», перед `drawHookedFish()`): **степенная по ДЛИНЕ силуэта** (длина = 2.45·fs: тело 2·fs + хвост): `fs = (3.95 + 16.05·(max(0.1,w))^0.5981)/2.45`. Якоря: **0.1 кг → 8 px** (мелочь-мелкая), **1 кг → 20 px**, **100 кг → 256 px = 4× лодки 64 px** из `drawBoat()` (`bx−32..bx+32`). Веса <0.1 кг клампятся в минимум (затрагивает только золотую рыбку 0.05–0.1 кг). Размер лодки (64 px) достигают ~9.1 кг; распределение: 0.1–1 кг 8..20 px (мелочь), 10 кг ≈ 1.05× лодки, 50 кг ≈ 2.7×, 100 кг = 4×. -- **`drawHookedFish()`:** `fs = fishSizeFromW(reel.w)` (было `8+(reel.w/sp.wMax)*10+sp.rarity`). Убраны **`+sp.rarity`** (редкая рыбка не обязана быть крупнее — размер = вес) и **босс-множитель ×1.5** (М4): босс весит 20–50 кг (1.57–2.67× лодки по степенной шкале), с ×1.5 босс-рак 30 кг выглядел бы крупнее кита 100 кг — противоречие «крупнее вес → крупнее рыба»; драматизм босса теперь несёт аура + бейдж + фазы. Золотая аура босса сохранена (читает новый `fs`). +- **Новый хелпер `fishSizeFromW(w)` + таблица `FISH_SIZE_KNOTS`** (секция «ОТРИСОВКА», перед `drawHookedFish()`): узлы `[log2(w/0.1), длина px] = [0,16],[1,20],[2,25],[3,35],[4,48],[5,64],[6,80],[7,100],[8,120],[9,170],[log2(1000),256]`, интерполяция линейна по log₂(веса) (узлы — степени двойки), длина силуэта = 2.45·fs (тело 2·fs + хвост). Узлы: **0.1 кг → 16 px** · 0.2 → 20 · 0.4 → 25 · 0.8 → 35 · 1.6 → 48 · 3.2 → 64 (= лодка) · 6.4 → 80 · 12.8 → 100 · 25.6 → 120 · 51.2 → 170 · **100 кг → 256 px = 4× лодки 64 px** из `drawBoat()` (`bx−32..bx+32`). Веса вне 0.1–100 кг клампятся в края таблицы (нижний кламп затрагивает только золотую рыбку 0.05–0.1 кг). +- **`drawHookedFish()`:** `fs = fishSizeFromW(reel.w)` (было `8+(reel.w/sp.wMax)*10+sp.rarity`). Убраны **`+sp.rarity`** (редкая рыбка не обязана быть крупнее — размер = вес) и **босс-множитель ×1.5** (М4): босс весит 20–50 кг (113–168 px = 1.77–2.6× лодки по узловой шкале), с ×1.5 босс-рак 30 кг выглядел бы крупнее кита 100 кг — противоречие «крупнее вес → крупнее рыба»; драматизм босса теперь несёт аура + бейдж + фазы. Золотая аура босса сохранена (читает новый `fs`). - **Не тронуто:** подплывающая рыба до подсечки (APPROACH/BITE, `12+rarity*2.5` — вес к моменту подплывания ещё не зароллен, `hook()` роллит его при подсечке), фоновые рыбы `rand(8,22)`, 🐟-маркер на дистанционной полосе, emoji-карточка улова. Баланс/роллы не задеты: `wMin/wMax` остаются только в `rollWeight()`/`hook()`/`st0`. -**Размеры (полная длина силуэта; лодка = 64 px):** 0.1 кг → 8 px (0.13×) · 1 кг → 20 px (0.31×) · 5 кг → 46 px (0.72×) · 10 кг → 67.6 px (1.05×) · 20 кг (босс min) → 100 px (1.57×) · 50 кг (босс max) → 170.6 px (2.67×) · 100 кг (кит max) → 256 px (**4×**). Диапазон 8..256 px = ×32 (в исходной формуле ~20..54 px = ×2.7). Тяжёлая рыба в конце вываживания (позиция `boatX+24`, поверх лодки) заметно перекрывает лодку — осознанный эффект «вывезена рядом с лодкой»; на мобильном 360 px кит ≈ 71% ширины экрана. +**Размеры (полная длина силуэта; лодка = 64 px):** 0.1 кг → 16 px (0.25×) · 0.2 → 20 px (0.31×) · 0.4 → 25 px (0.39×) · 0.8 → 35 px (0.55×) · 1.6 → 48 px (0.75×) · 3.2 → 64 px (**1× = лодка**) · 6.4 → 80 px (1.25×) · 12.8 → 100 px (1.56×) · 25.6 → 120 px (1.88×) · 51.2 → 170 px (2.66×) · 100 кг (кит max) → 256 px (**4×**). Диапазон 16..256 px = ×16; между узлами — линейно по log₂(веса) (проверено: узлы 0% отклонения, монотонность 1000 точек). Тяжёлая рыба в конце вываживания (позиция `boatX+24`, поверх лодки) заметно перекрывает лодку — осознанный эффект «вывезена рядом с лодкой»; на мобильном 360 px кит ≈ 71% ширины экрана. -**Тесты:** пины на размер силуэта в `tests/test.js` отсутствуют (проверено: `drawFishShape`/`drawHookedFish`/`fishReelPos` не ассертятся; `reel.w` в тестах — для физики). Итого **193/193 PASS, exit 0**; `check.mjs` OK; `tools/balance.mjs` — пины без изменений (Река 65.1/125.9 · Озёра 194.1/249.0 · Море 297.3/476.7 · Океан 329.1/552.7). Скриншоты перегенерированы (`gen-screenshots.js`, 30 кадров; кадр `reel` форсит `reel.w=12.5` — рыба ~77 px ≈ 1.2× лодки). +**Тесты:** пины на размер силуэта в `tests/test.js` отсутствуют (проверено: `drawFishShape`/`drawHookedFish`/`fishReelPos` не ассертятся; `reel.w` в тестах — для физики). Итого **193/193 PASS, exit 0**; `check.mjs` OK; `tools/balance.mjs` — пины без изменений (Река 65.1/125.9 · Озёра 194.1/249.0 · Море 297.3/476.7 · Океан 329.1/552.7). Скриншоты перегенерированы (`gen-screenshots.js`, 30 кадров; кадр `reel` форсит `reel.w=12.5` — рыба ~99 px ≈ 1.55× лодки). ## Этап 42. SVG-портреты рыб в дневнике и карточке улова diff --git a/index.html b/index.html index 58ea2bb..c0bed3e 100644 --- a/index.html +++ b/index.html @@ -2579,13 +2579,20 @@ function fishReelPos(){ return {x:x,y:y}; } /* Размер силуэта пойманной рыбы — от АБСОЛЮТНОГО веса (кг), не от wMin/wMax вида. - Степенная шкала по ДЛИНЕ силуэта (длина = 2.45·fs: тело 2·fs + хвост), якоря: - 0.1 кг → 8 px (мелочь), 1 кг → 20 px, 100 кг → 256 px = 4× лодки 64 px. - Буквально квадратичная шкала 3 якоря не держит (парабола по w пиковала ~420 px на 61 кг - и сходилась к 100 кг; по ln w провисала до 4 px у 0.2 кг) — степенная A+B·w^0.598 точна и монотонна. - Веса <0.1 кг клампятся в минимум. Средние (длина): 5 кг → 46 px, 10 кг → 67.6 px (размер лодки ~9.1 кг), - 20 кг → 100 px, 50 кг → 170.6 px. */ -const fishSizeFromW=w=>(3.95+16.05*Math.pow(Math.max(0.1,w),0.5981))/2.45; + УЗЛОВАЯ ТАБЛИЦА (длина силуэта = 2.45·fs: тело 2·fs + хвост), узлы по степеням двойки: + 0.1 кг → 16 px · 0.2 → 20 · 0.4 → 25 · 0.8 → 35 · 1.6 → 48 · 3.2 → 64 (= лодка) · + 6.4 → 80 · 12.8 → 100 · 25.6 → 120 · 51.2 → 170 · 100 → 256 px = 4× лодки 64 px. + Интерполяция линейна по log2(веса) — узлы степени двойки, кривая монотонна, узлы бьёт точно. + Веса <0.1 кг клампятся в 16 px, >100 кг — в 256 px. */ +const FISH_SIZE_KNOTS=[[0,16],[1,20],[2,25],[3,35],[4,48],[5,64],[6,80],[7,100],[8,120],[9,170],[Math.log2(1000),256]]; // [log2(w/0.1), длина px] +function fishSizeFromW(w){ + const t=Math.log2(Math.max(0.1,Math.min(100,w))/0.1); + for(let i=1;i