1
0
george e84ffa754d Этап 9: сквозь границы (тор)
Змейка проходит сквозь край поля и появляется с противоположной стороны.

- координаты головы считаются по модулю: (x+dx+COLS)%COLS, (y+dy+ROWS)%ROWS
- столкновение с краем больше не убивает; смерть только от себя/препятствий

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-17 18:34:45 +03:00

6.9 KiB
Raw Blame History

🐍 Змейка на Jetpack Compose

Учебный пример простого Android-приложения для студентов: классическая игра «Змейка» на одном экране. Цель примера — показать, как устроено реальное Android-приложение на современном стеке (Kotlin + Jetpack Compose) без лишней сложности.

Что внутри

  • Игровое поле-сетка 20×30
  • Управление свайпами (вверх/вниз/влево/вправо)
  • Змейка растёт, когда съедает еду; ведётся счёт и рекорд за сессию
  • Столкновение со стеной или с собой = Game Over, тап — рестарт
  • Вся отрисовка — через Compose Canvas, игровой цикл — на корутине

Стек

Что Версия
Язык Kotlin 2.0.20
UI Jetpack Compose (BOM 2024.10.01, Material 3)
Android Gradle Plugin 8.13.2
Gradle 8.13
compileSdk / minSdk 36 / 24

Как запустить

Вариант 1: Android Studio (рекомендуется)

  1. Открыть папку проекта в Android Studio (File → Open).
  2. Дождаться Gradle Sync.
  3. Подключить телефон по USB (с включённой отладкой по USB) или запустить эмулятор.
  4. Нажать ▶ Run.

Вариант 2: командная строка

# нужен JDK 17+ и установленный Android SDK
./gradlew installDebug    # соберёт и поставит приложение на подключённое устройство

Файл local.properties с путём к SDK создаётся автоматически Android Studio и не хранится в репозитории — у каждого свой путь.

Структура проекта

app/src/main/
├── java/com/example/snake/
│   ├── MainActivity.kt   # точка входа: ComponentActivity + setContent { SnakeGame() }
│   └── SnakeGame.kt      # вся игра: состояние, игровой цикл, отрисовка, управление
├── res/values/themes.xml # тема приложения
└── AndroidManifest.xml

👉 Главный файл для изучения — SnakeGame.kt. Там по шагам видно идеи Compose:

  • состояние через remember { mutableStateOf(...) } — UI сам перерисовывается при его изменении;
  • игровой цикл через LaunchedEffect { while(true) { delay(); step() } };
  • ввод через Modifier.pointerInput { detectTapGestures / detectDragGestures };
  • рисование через Canvas { drawRoundRect / drawLine }.

Управление

Действие Жест
Начать игру свайп или тап
Повернуть свайп ↑ ↓ ← →
Рестарт после проигрыша тап по экрану

Этапы (ветки)

Проект задуман как серия этапов — каждый в своей ветке, чтобы можно было сравнивать версии:

  • snake-stage-1 — базовая рабочая игра.

  • snake-stage-2 — ускорение: змейка ускоряется с каждой съеденной едой (задержка шага 150 → 60 мс), на экране индикатор «Скорость». Смотри функции stepDelay() / speedLevel() и игровой цикл в SnakeGame.kt.

  • snake-stage-3 — рекорд сохраняется между запусками через Jetpack DataStore (ScoreStore.kt): чтение — Flow, запись — suspend-функция, диск не блокирует UI. Смотри LaunchedEffect для загрузки рекорда и scope.launch { ScoreStore.saveBest(...) } при новом рекорде.

  • snake-stage-4 — звук при поедании еды через SoundPool: короткий WAV в res/raw/eat.wav грузится один раз, играется при каждом съедании (низкая задержка). Смотри настройку SoundPool и soundPool.play(...) в step(); освобождение ресурса — в DisposableEffect.

  • snake-stage-5 — анимация поедания: в момент укуса на месте еды расходится затухающее кольцо. Смотри Animatable (popProgress 0→1), запуск анимации в step() и отрисовку кольца в drawBoard().

  • snake-stage-6 — пауза: тап по полю во время игры ставит/снимает паузу (свайпы по-прежнему рулят направлением). Смотри флаг paused, условие в игровом цикле и оверлей «ПАУЗА».

  • snake-stage-7 — бонус-еда с таймером: иногда (1 из 4 при поедании обычной еды) появляется золотая еда на ~36 шагов и даёт +3 очка; вокруг неё рисуется дуга-таймер, по истечении она исчезает. Время считается в шагах игры, поэтому пауза учитывается автоматически. Смотри bonusFood / bonusStepsLeft, логику в step() и отрисовку (drawArc) в drawBoard().

  • snake-stage-8 — препятствия и уровни: каждые 5 очков — новый уровень, на поле добавляется порция серых стен; врезался в стену — Game Over. Еда и бонус не спавнятся в препятствиях, новые стены не ставятся вплотную к голове. В шапке — «Уровень». Смотри obstacles/level, addObstacles(), проверку коллизий и повышение уровня в step().

  • snake-stage-9 — сквозь границы (тор): змейка проходит сквозь край поля и появляется с противоположной стороны; смерть остаётся только от самой себя и от препятствий. Реализовано %-арифметикой по координатам головы в step().

Идеи для следующих этапов: два игрока, выбор размера поля, экран настроек.