Документация процесса разработки (docs/DEVLOG.md)
- этапы: ТЗ, реализация, среда проверки, автотесты, визуал, баги, публикация - таблица инструментов с версиями и командами установки - найденные автотестом баги и выводы - гигиена секретов (отзыв токена, чистка remote) - как развивать игру дальше
This commit is contained in:
@@ -24,6 +24,10 @@
|
||||
- Звуки на WebAudio, вибрация на телефоне
|
||||
- Вся графика нарисована на Canvas — внешних ресурсов нет
|
||||
|
||||
## Документация
|
||||
|
||||
[📋 Процесс разработки](docs/DEVLOG.md) — этапы (ТЗ → прототип → автотесты → публикация), инструменты, найденные баги, гигиена секретов и как развивать игру дальше.
|
||||
|
||||
## Запуск
|
||||
|
||||
Просто открой [index.html](index.html) в браузере (десктоп или телефон). Для локальной разработки:
|
||||
|
||||
+175
@@ -0,0 +1,175 @@
|
||||
# Процесс разработки
|
||||
|
||||
Как игру «Рыбалка» спроектировали, собрали, проверили и опубликовали. Документ описывает этапы, инструменты и повторяемые команды — чтобы любой (включая вас через полгода) мог воспроизвести и продолжить процесс.
|
||||
|
||||
```
|
||||
ТЗ → макет-прототип → среда проверки → автотесты → визуал → баги → публ. → поддержка
|
||||
1 2 3 4 5 6 7 8
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Этап 1. Требования и дизайн (ТЗ)
|
||||
|
||||
**Исходное ТЗ:** браузерная игра про рыбалку, играбельная на телефоне.
|
||||
|
||||
Ключевые решения:
|
||||
|
||||
| Решение | Зачем |
|
||||
|---|---|
|
||||
| Один самодостаточный `index.html` (HTML+CSS+JS) | Нет сборки, зависимостей и бэкенда. Файл можно открыть где угодно: телефон, десктоп, статический хостинг |
|
||||
| Вся графика на Canvas, без внешних ассетов | Игра работает офлайн, грузится мгновенно |
|
||||
| Портретная ориентация, управление одним пальцем | Все действия — тап/удержание по экрану, больших тач-мишеней (кнопки ≥ 44 px) |
|
||||
| HTML-оверлеи для меню/магазина/карточек, Canvas — только мир игры | Кнопки и текст резкие и доступные, игровой мир — 60 fps |
|
||||
| WebAudio для звуков (без файлов), `navigator.vibrate` для тактильного отклика | Снова ноль внешних ресурсов; на телефоне — вибрация на клёв/рывки/обрыв |
|
||||
| Прогресс в `localStorage` | Мобильная игра без аккаунтов и сервера |
|
||||
|
||||
Механика (единый цикл):
|
||||
|
||||
```
|
||||
бросок (удержание = мощность) → ожидание → клёв («!») → подсечка (тап в окно)
|
||||
→ вываживание (тяни/отпускай) → {улов / обрыв / срыв} → монеты → магазин
|
||||
```
|
||||
|
||||
## Этап 2. Реализация
|
||||
|
||||
Структура `index.html` (все секции помечены комментариями в файле):
|
||||
|
||||
1. **Данные** — `SPECIES` (8 рыб: сила, редкость, цена, мин. дистанция), `RODS`, `LURES`. *Баланс игры крутится здесь.*
|
||||
2. **Сохранение** — `save` + `localStorage` (монеты, снасти, коллекция, статистика).
|
||||
3. **Холст** — масштабирование под `devicePixelRatio`, пересчёт layout'а при `resize`.
|
||||
4. **Звук** — генеративный WebAudio: 12 эффектов из осцилляторов и шума.
|
||||
5. **Состояния** — машина из 9 состояний: `MENU → IDLE → CHARGE → CAST → WAIT → APPROACH → BITE → REEL → SNAP/CARD → (IDLE)`.
|
||||
6. **Физика вываживания** — `updateReel()`: напряжение шнура, дистанция, фазы «тянет/отдыхает». *Сложность крутится здесь.*
|
||||
7. **Отрисовка** — небо, вода, рыбы-силуэты, лодка, поплавок, частицы, риплы, метры.
|
||||
8. **Ввод** — Pointer Events (`pointerdown/up`), работают и палец, и мышь (важно для автотестов!).
|
||||
9. **UI** — магазин, дневник, карточка улова.
|
||||
|
||||
## Этап 3. Среда проверки
|
||||
|
||||
Игра проверена в контейнере **Alpine Linux 3.24**. Минимальный набор инструментов:
|
||||
|
||||
| Инструмент | Версия (в нашем прогоне) | Зачем | Установка |
|
||||
|---|---|---|---|
|
||||
| Node.js | v24.18.1 | Статический анализ JS, запуск автотестов | `apk add nodejs npm` |
|
||||
| Chromium | 151.0.7922 | Headless-браузер для настоящего прогона игры | `apk add chromium` |
|
||||
| puppeteer-core | 25.9.0 | Управление Chromium через CDP (клики, скриншоты, чтение состояний) | `npm i puppeteer-core` (в `tests/`) |
|
||||
| Noto Color Emoji | — | Чтобы в headless-скриншотах эмодзи рендерились как на телефоне | `apk add font-noto-emoji` |
|
||||
| git | 2.54.0 | Публикация | `apk add git` |
|
||||
| curl | — | Проверка API Gitea, smoke-запросы | уже есть в Alpine |
|
||||
|
||||
> В браузере на телефоне для *игры* не нужен ни один инструмент из таблицы — только сам браузер.
|
||||
|
||||
## Этап 4. Статическая проверка
|
||||
|
||||
Первый рубеж — компиляция кода настоящим движком (V8):
|
||||
|
||||
```bash
|
||||
# вытащить JS из HTML и проверить синтаксис
|
||||
node --check game.js
|
||||
```
|
||||
|
||||
Ловит опечатки, несбалансированные скобки, висячие конструкции — до запуска в браузере.
|
||||
|
||||
## Этап 5. Автотесты (плейтест через CDP)
|
||||
|
||||
`tests/test.js` — сценарный автотест: headless Chromium загружает игру, а «игрок» управляет мышью (в браузере мышь порождает те же Pointer Events, что и палец). Тест читает и подталкивает внутренние состояния игры (`state`, `biteTimer`, `reel.d`) через `page.evaluate`, чтобы покрыть все ветки без ожидания случайностей.
|
||||
|
||||
**Что покрыто (21 проверка):**
|
||||
|
||||
- меню → старт → зарядка → бросок → ожидание
|
||||
- клёв (ускорен через `biteTimer`) → подсечка → `REEL`
|
||||
- **все три исхода вываживания**: улов → карточка, обрыв шнура (`SNAP`), срыв рыбы
|
||||
- магазин: открытие, покупка удочки и приманки (с проверкой баланса и экипировки)
|
||||
- дневник: рендер, пойманная рыба в коллекции
|
||||
- **сохранение после перезагрузки страницы** (coins/снасти/статистика)
|
||||
- ноль ошибок в консоли и `pageerror`
|
||||
|
||||
Запуск:
|
||||
|
||||
```bash
|
||||
cd tests
|
||||
npm install
|
||||
node test.js # при необходимости: CHROMIUM=/путь/к/хромью
|
||||
```
|
||||
|
||||
## Этап 6. Визуальная проверка
|
||||
|
||||
`tests/shots.js` — та же техника, но с фиксацией скриншотов каждого состояния (`screenshots/shot-*.png`). Скриншоты просматривает разработчик: ловит проблемы, которые не видны по коду и логам (сбившиеся метки, отсутствующие глифы, нечитаемые метры).
|
||||
|
||||
## Этап 7. Найденные баги (ради чего всё это)
|
||||
|
||||
Автотест + скриншоты поймали то, что ручное «посмотрел глазами» пропустило:
|
||||
|
||||
| # | Баг | Как нашли | Лечение |
|
||||
|---|---|---|---|
|
||||
| 1 | **Критический:** после поимки рыбы игра вешалась навсегда. `catchFish()` ставил `reel=null`, но кейс `REEL` в `updateGame()` на следующей строке читал `reel.holding` → исключение убивало цикл `requestAnimationFrame` | Автотест: второй бросок не происходил; `pageerror` показал точную строку | `if(state==='REEL'&&reel){...}` |
|
||||
| 2 | Точка крепления лески висела в углу экрана в меню/карточке | Визуальный осмотр скриншотов | Условие отрисовки по состояниям |
|
||||
| 3 | Рыбка-маркер не стояла на краю полосы «дистанция» | Визуальный осмотр | Полоса = оставшаяся дистанция, маркер на её конце |
|
||||
| 4 | Глиф `✕` (U+2715) отсутствовал в некоторых шрифтах | Скриншот магазина | Заменён на `×` (U+00D7) |
|
||||
|
||||
**Вывод:** для игр с таймерами и случайностями автотест, который *управляет* временем и состоянием, покрывает за минуту то, что вручную ищут часами.
|
||||
|
||||
## Этап 8. Публикация в Gitea
|
||||
|
||||
Использовано: Gitea API (создание репозитория) + обычный `git push`.
|
||||
|
||||
```bash
|
||||
# 1. Создать репозиторий (токен: Настройки → Приложения → Токены, права: Repository)
|
||||
curl -X POST -H "Authorization: token <ТОКЕН>" -H "Content-Type: application/json" \
|
||||
-d '{"name":"fishing-game","private":false,"auto_init":false}' \
|
||||
https://git.shstk.ru/api/v1/user/repos
|
||||
|
||||
# 2. Наполнить ветку и запушить
|
||||
git init -b main
|
||||
git add -A
|
||||
git commit -m "..."
|
||||
git remote add origin https://git.shstk.ru/andrey/fishing-game.git
|
||||
git push -u origin main # git попросит логин/пароль (или токен в URL — см. ниже)
|
||||
```
|
||||
|
||||
Игра доступна анонимно по сырой ссылке:
|
||||
`https://git.shstk.ru/andrey/fishing-game/raw/branch/main/index.html`
|
||||
|
||||
### 🔐 Гигиена секретов (проверено на себе)
|
||||
|
||||
1. **Токен — одноразовый.** Для публикации достаточно кратковременного токена с правами на репозиторий; после push его **отзываем** (в нашем случае — отозван, старый токен теперь отдаёт `401`).
|
||||
2. **Токен не попадает в историю и конфиг.** Если передавать токен в URL (`https://user:TOKEN@host/...`), после push удалите его из конфига:
|
||||
`git remote set-url origin https://git.shstk.ru/andrey/fishing-game.git`
|
||||
3. **В репозиторий и в документы — только плейсхолдеры** (`<ТОКЕН>`), реальные секреты нигде не фиксируются.
|
||||
|
||||
## Этап 9. Поддержка и развитие
|
||||
|
||||
**Крутить баланс:** константы `SPECIES` / `RODS` / `LURES` в начале `index.html`; физика вываживания — в `updateReel()`.
|
||||
|
||||
**Цикл изменений:**
|
||||
|
||||
```bash
|
||||
# 1. поправить index.html
|
||||
# 2. прогнать автотест
|
||||
cd tests && node test.js # ждём 21/21
|
||||
# 3. (опционально) свежие скриншоты
|
||||
node shots.js
|
||||
# 4. закоммитить и запушить
|
||||
git add -A && git commit -m "что изменилось" && git push
|
||||
```
|
||||
|
||||
**Идеи развития** (по нарастающей сложности):
|
||||
- ночной клёв (своя таблица рыб по времени)
|
||||
- босс-рыба с механикой «разрывать и переподсекать»
|
||||
- продажи улова / рыбный прайс по редкости
|
||||
- мировая таблица лидеров (нужен простой бэкенд или Gitea-Actions с webhook'ом)
|
||||
- офлайн-режим PWA (service worker в тот же файл)
|
||||
|
||||
---
|
||||
|
||||
## Шпаргалка: минимум инструментов по этапам
|
||||
|
||||
| Этап | Инструменты |
|
||||
|---|---|
|
||||
| Игра (конечный пользователь) | Любой браузер на телефоне/десктопе |
|
||||
| Написание/изменение кода | Текстовый редактор (или LLM-сессия) |
|
||||
| Статическая проверка | Node.js |
|
||||
| Автотесты | Node.js + npm + Chromium + puppeteer-core |
|
||||
| Визуальная проверка | Скриншоты из автотеста + Noto Color Emoji в headless |
|
||||
| Публикация | git + curl + Gitea (токен с минимальными правами, отзываемый) |
|
||||
Reference in New Issue
Block a user