revew and cert
This commit is contained in:
@@ -6,3 +6,5 @@
|
||||
- [Умный дом](smart-house/README.md)
|
||||
- [Умный дом WEB](smart-house-web/README.md)
|
||||
- [Игра "Змейка"](snake-game/README.md) -- проектная работа
|
||||
|
||||
[Сертификат](https://otus.ru/certificate/aa2140d27fdd4561aa8890bfdc26eb87/) - файл `otus_cert.pdf`
|
||||
|
||||
Binary file not shown.
@@ -2,6 +2,8 @@
|
||||
|
||||
Проектная работа по курсу **Rust Developer. Professional** образовательной платформы [OTUS](https://otus.ru/).
|
||||
|
||||
[Код-ревью проекта «Змейка»](REVIEW.md) от преподавателя Кирилла Федченко
|
||||
|
||||
## Запуск
|
||||
Сразу после запуска игра будет на паузе. Чтобы начать игру нужно снять её с паузы клавишей "Пробел".
|
||||
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
# Код-ревью проекта «Змейка»
|
||||
|
||||
## Общая оценка
|
||||
|
||||
Крепкая, аккуратно организованная работа. Автор хорошо владеет идиомами Bevy ECS:
|
||||
разделение на модули по расписаниям (`startup` / `update` / `fixed_update` / `post_update`),
|
||||
использование событий и обзёрверов, разнесение доменной модели в `domain/`. Логика движения
|
||||
по сетке с разбиением шага на границе (`split_by_grid`) — нетривиальная и покрыта хорошим
|
||||
юнит-тестом. Документирующие комментарии присутствуют почти везде.
|
||||
|
||||
Есть один реальный функциональный баг (таймер спавна еды) и несколько игровых/стилистических
|
||||
замечаний.
|
||||
|
||||
---
|
||||
|
||||
## Критичные замечания
|
||||
|
||||
### 1. Таймер спавна еды тикается общим временем вместо дельты кадра
|
||||
`src/fixed_update.rs:92`
|
||||
|
||||
```rust
|
||||
if meal_timer.tick(time.elapsed()).just_finished() && query.count() < MAX_MEALS_ON_FIELD as usize {
|
||||
```
|
||||
|
||||
`Timer::tick` принимает **дельту** времени за кадр, а `time.elapsed()` возвращает **суммарное**
|
||||
время с момента старта (постоянно растущее). В результате:
|
||||
|
||||
- Первые ~2 секунды таймер копит `elapsed`, затем на каждом fixed-шаге тикается на всё
|
||||
накопленное время (2.0s, 2.03s, 2.06s …). Для `Repeating`-таймера это значит `just_finished()`
|
||||
становится `true` практически **каждый кадр** после первых 2 секунд.
|
||||
- Как следствие поле мгновенно заполняется до `MAX_MEALS_ON_FIELD` (5 штук), а после поедания
|
||||
еды тут же добивается обратно — заявленной механики «одна еда раз в 2 секунды» нет.
|
||||
|
||||
**Исправление:**
|
||||
```rust
|
||||
if meal_timer.tick(time.delta()).just_finished() && query.count() < MAX_MEALS_ON_FIELD as usize {
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Средние замечания
|
||||
|
||||
### 2. Еда может появиться прямо под змеёй
|
||||
`src/fixed_update.rs:93-103`
|
||||
|
||||
`used_positions` собирается **только из других объектов еды** — позиции головы и сегментов хвоста
|
||||
не учитываются. Поэтому еда легко спавнится под телом змеи, что портит игровой процесс
|
||||
(съедается «бесплатно» либо появляется в недосягаемом месте). Стоит добавить в исключаемые
|
||||
позиции клетки, занятые `Head`/`Tail`.
|
||||
|
||||
### 3. Столкновение с границей триггерится каждый кадр
|
||||
`src/post_update.rs:6-16`
|
||||
|
||||
После выхода за границу скорость обнуляется, но координаты головы остаются за пределами поля,
|
||||
поэтому `Collision::Bounds` генерируется на **каждом** `PostUpdate`, и `handle_collisions`
|
||||
бесконечно переустанавливает скорость/цвет. У столкновения с хвостом такой проблемы нет
|
||||
(там есть отсечка `velocity.0 == 0.0`). Логичнее ввести явное состояние «игра окончена»
|
||||
(например, компонент-маркер `GameOver` или `State`), которое остановит проверки и позволит
|
||||
сделать рестарт. Сейчас после проигрыша игру можно только перезапустить процессом.
|
||||
|
||||
---
|
||||
|
||||
## Мелкие замечания и стиль
|
||||
|
||||
### 4. Диапазон случайной позиции еды меньше поля и смещён
|
||||
`src/fixed_update.rs:96-99`
|
||||
|
||||
```rust
|
||||
const ABS: i8 = (FIELD_SIZE as f32 / 2.0) as i8; // = 10
|
||||
let rand_x = rng.random::<i8>() % ABS; // диапазон -9..=9
|
||||
```
|
||||
|
||||
При `FIELD_SIZE = 20` поле по логике занимает клетки `-10..=10`, но еда никогда не появляется
|
||||
в крайних клетках `±10`. Также остаток от деления даёт чуть неравномерное распределение и `0`
|
||||
встречается вдвое чаще краёв. Для равномерного распределения удобнее
|
||||
`rng.random_range(-ABS..=ABS)`.
|
||||
|
||||
### 5. Неограниченное ускорение/замедление времени
|
||||
`src/update.rs:30-40`
|
||||
|
||||
`Equal`/`Minus` умножают `relative_speed` без верхней/нижней границы — можно довести скорость до
|
||||
неиграбельных значений (или почти до нуля). Стоит ограничить, например, диапазоном `[0.125, 8.0]`.
|
||||
|
||||
### 6. Опечатки в именах (для читаемости кода)
|
||||
- `check_bounds_colisions`, `check_tail_colisions` → `collisions` (`src/post_update.rs`, `src/game.rs`)
|
||||
- `GridBarier` → `GridBarrier` (`src/domain/events.rs` и все использования)
|
||||
- `splited` → `split` (`src/fixed_update.rs:23`)
|
||||
|
||||
Не влияет на работу, но публичные имена типов/систем лучше писать без ошибок.
|
||||
|
||||
### 8. Учебный «мусор» в репозитории поставки
|
||||
- `tests/rust_learning.rs` — это личные эксперименты (`dbg!` по `saturating_sub`, `ceil`,
|
||||
`floor` и т.п.), а не тесты проекта. В сдаваемой работе их лучше убрать или вынести за пределы
|
||||
`tests/`.
|
||||
- `examples/` содержит туториалы по Bevy (`bevy_learning.rs`, `paddle_demo.rs` …), не относящиеся
|
||||
к игре. Для учебного проекта допустимо, но стоит хотя бы упомянуть их статус в README.
|
||||
|
||||
---
|
||||
|
||||
## Что сделано хорошо
|
||||
|
||||
- **Чистая модульная структура**: доменная модель отделена от систем, системы сгруппированы
|
||||
по расписаниям Bevy.
|
||||
- **Идиоматичный ECS**: события (`Collision`, `GrowUp`, `GridBarier`), обзёрверы, `Single`-запросы,
|
||||
ресурсы (`SnakePath`, `MealRespawnTimer`).
|
||||
- **Аккуратная механика поворотов**: змея не может развернуться в себя (только `rotate_left`/
|
||||
`rotate_right`), а первый сегмент за головой исключён из проверки столкновений — грамотное
|
||||
решение классических проблем «Змейки».
|
||||
- **`split_by_grid`** — сложная логика движения через узлы сетки покрыта развёрнутым
|
||||
юнит-тестом со множеством сценариев.
|
||||
- Настроен `rustfmt.toml`, продуманный релизный профиль (`opt-level="z"`, `lto`, `strip`),
|
||||
ведётся логирование в файл и stdout.
|
||||
Reference in New Issue
Block a user