Как сделать змейку на клавиатуре

Обновлено: 06.07.2024

Используя модуль graph или ctr языка программирования Паскаль написать программу "Змейка".

Решение

Змейка - это игра, в которой по экрану движется полоска, изменяющая свое направление при нажатии клавиш вверх, вниз, влево и вправо. Цель игры, управляя движением змейки, не столкнуться с бордюром, "врагами", собрать "бонусы". При столкновении с последними длина змейки увеличивается.

Написать полную версию игры на любом языке программирования, в том числе Паскаль, - достаточно сложная задача для начинающих. Можно остановиться на варианте, когда по экрану движется полоска, управляемая клавиатурой.

Ниже представлен вариант кода, при выполнении которого по экрану перемещается курсор, управляемый нажатием клавиш d, a, w, s. Игра заканчивается, как только его позиция выходит за края дозволенной области, которая указана в заголовке цикла while.


HTML5 Canvas позволяет создавать 2D приложения любой сложности. Удобство этой технологии заключается в её кроссплатформенности, ибо любое устройство, где есть современный браузер, может запустить подобное приложение.

В этой статье я покажу как создать игру-змейку, на примере своей реализации этой игры (демо, GitHub).

Подготовка

Для начала создадим файловую структуру проекта, в моём случае она выглядит таким образом:

Информация о файлах:
  • В README.md находится небольшое описание проекта, в LICENSE — текст MIT лицензии.
  • В index.html находится HTML код, который подключает все файлы с JavaScript кодом.
  • В каталоге client/ находится клиентская часть исполняемого кода, в моей игре нет серверной части, но я всё же решил назвать каталог соответствующим образом.
  • client/app.js — файл приложения, в этом файле находится цикл игры и здесь же она запускается.
  • client/input.js — небольшая библиотека для более удобного определения нажатой клавиши.
  • client/game.js — файл игры, в этом файле объединяются все части игры, создаётся Canvas, обновляются и перерисовываются данные.
  • client/apple.js — файл яблока, здесь находятся функции для создания, удаления и рендеринга яблока.
  • client/snake.js — файл змейки, отвечает за передвижение и увеличение змейки.

index.html

Здесь всё просто, обычный HTML код с подключением всех JavaScript файлов.

client/app.js — приложение

Файл приложения — это файл, в котором инициализируется приложение и запускается бесконечный таймер.

Инициализация

Код инициализации приложения выглядит следующим образом:

Здесь мы инициализируем объект Game и создаём функцию init(), в которой запускается метод game.init() и запускается бесконечный таймер.

Бесконечный таймер

Функция main() — это функция которая будет вызываться постоянно, выглядит она следующим образом:

Здесь мы вызываем методы игры — метод обновления, а потом метод для рендеринга.

Обработка клавиш

Добавляем обработчик события keydown, который будет вызывать метод game.handleInput(e);

Запуск

Здесь всё просто — в самом конце мы вызываем функцию init(), что повлечёт за собой запуск всего приложения.

Полный код client/app.js выглядит так:

client/input.js — определение нажатой клавиши

Эта маленькая библиотека была создана для удобного определения нажатых клавиш.

Функция isKey(key) проверяет наличие key в объекте keys, чтобы заменить слово на код клавиши и если его там нет, то считается, что была введена какая-то буква. Потом полученный код сравнивается с введённым.

Для удобства здесь создаётся метод объекта window — input, который позволяет использовать библиотеку следующим образом: input.isKey(‘SPACE’).

client/game.js — тело игры

В этом файле объединяются все части игры, создаётся Canvas, обновляются и перерисовываются данные.

Объект Game создаётся следующим образом:

В блоке // default settings определяются параметры игры по умолчанию, создаются константы, которые будут использовать остальные файлы.

Далее мы создаём объект Canvas стандартными методами Javascript и располагаем его по центру страницы. Настраиваем его ширину и высоту, задаём стиль рамке.

Потом, на основе параметров высоты, ширины и размера ячейки мы высчитываем количество ячеек на поле в ширину и высоту.

И в самом конце мы подключаем объекты Snake и Apple, чтобы использовать их в методах объекта Game.

Сброс игры

Функция сброса игры нужна для её первоначальной инициализации и сброса игры, если игрок пожелает сыграть заново.

В предыдущей статье мы писали сапёра за 15 минут, теперь займёмся классической змейкой.

В этот раз нам снова понадобятся:

  • 15 минут свободного времени;
  • Настроенная рабочая среда, т.е. JDK и IDE (например Eclipse);
  • Библиотека LWJGL (версии 2.x.x) для работы с Open GL. Обратите внимание, что для LWJGL версий выше 3 потребуется написать код, отличающийся от того, что приведён в статье;
  • Спрайты, т.е. картинки самой змеи и фрукта, который она будет есть. Можно чисто символически нарисовать самому, или скачать использовавшиеся при написании статьи.

Подключение библиотек

В прошлый раз у многих возникли с этим вопросом проблемы, поэтому мне показалось уместным посвятить этому немного времени. Во-первых, выше я дал ссылку на скачивание архива с библиотеками, которые использую я, чтобы не было путаницы с версиями и вопросов, где найти что-то. Папку из архива требуется поместить в папку проекта и подключить через вашу IDE.

Во-вторых, у многих пользователей InteliJ IDEA возникли проблемы как раз с их подключением. Я нашёл в сети следующий видеогайд:

После того, как я сделал всё в точности по нему, у меня библиотеки подключились корректно и всё заработало.

Работа с графикой

С этой стороны наша задача мало отличается от той, что мы выполняли при написании Сапёра. Снова создаём класс GUI, который будет хранить и обновлять состояние всех графических элементов. Если точнее:

  • Должен хранить текущие состояния ячеек:
  • Должен отрисовывать эти самые ячейки:
  • И обновляться, когда этого запросит главный цикл:

Как вы можете видеть, здесь я уже использовал несколько констант. Для них был создан отдельный класс Constants с public static полями. Вот он целиком:

Enum Sprite , который отвечает за подгрузку текстур, полностью идентичен тому, что мы писали для Сапёра, за исключением того, что нам нужно только две текстуры — для змеи и для ягод. Вот код:

Механика игры

Самое время поговорить о том, как наша змея будет, собственно, перемещаться. Вам наверняка доводилось видеть вывески, вокруг которых по кругу бегают огоньки? Разумеется, сами лампочки в них не перемещаются, просто каждый тик последняя гаснет, а первая зажигается. Таким же образом будет перемещаться и наша змея.

Пишем класс клетки

Добавляем геттер и сеттер для состояния клетки поля в GUI

Добавляем метод, создающий начальное поле в GUI

Просто инициализируем OpenGL, затем массив Cell[][] cells и заполняем последний клетками со случайным полем state .


Статья написана на основе примера из clickteam — скачать пример.

Подготовка объектов.

Snake заполнена анимация головы

Вам понадобится как минимум 3 активных объекта: голова змеи, хвост змеи и точка которую нужно собирать. Важно, что бы голова змеи имела 4 базовых направления в статической анимации.

В отношении объекта хвоста змеи это не обязательно особенно если у вас этот объект квадратный.

Внимание: Точку привязки координат у всех трех объектов нужно сделать слева вверху. Формулы и логика представленные в данном примере будут работать корректно только с таким положением точки привязки координат для всех трех объектов.

Snake точка привязки объекта

Ширина хвоста змеи должна быть равна шагу змеи в нашем случае — 32.

Snake ширина хвоста - 32

Активный объект являющейся головой змеи должен быть статического типа.

Snake тип объекта голова

Голова змеи. Управление и движение.

По кнопке вверх, вниз, влево и вправо соответственно меняется свойство направления (Direction) объекта головы змеи. Создаем 4 события нажатия кнопок для 4-х сторон движения.

Snake события установка кнопок

Snake клавиша для события

Лично мне нравиться использовать кнопки W, S, A, D.

Snake меняем направление головы змеи

В следующем событии устанавливается событие таймера для регулярного отслеживания какого-то временного промежутка для одного шага, скажем, каждые 30 миллисекунд. И еще устанавливается второе событие с направлением головы змеи. Этим событиям дается действие, которое изменяет координату головы змеи в зависимости от направления. Так, например, если движение вправо, то координата X устанавливается в значение: текущая координата X головы змеи плюс шаг( 32).

Snake изменение координаты движения

Общий алгоритм движения и управления выглядит так:

Snake управление головой

Создание хвоста.

В каждом из последних четырех событий добавляем еще одно действие — создание части хвоста в координатах головы. Голова змеи перемещается на один шаг, а на её месте появляется хвост. Так же можно добавить изменение свойства направления у объекта хвоста, если у вас он не квадратный, а прямоугольный как в данном случае.





Теперь если вы запустите игру, то увидите, что за змеёй тянется хвост.

Snake хвост тянется за головой

Единственной загвоздкой остается сохранение нужного количества частей хвоста.

Сохранение длинны хвоста.

Так как каждая следующая часть хвоста создается с разницей в один ход, то и исчезать они тоже будут друг за другом с каждым ходом и длинна змейки будет сохраняться.

Snake сохраняя три хвоста

Съел вкусняшку — стал длиннее

Я думаю вы уже догадались, что теперь по событию подбора точки надо просто прибавлять счетчик на 1.
Разместите где нибудь объект точки и создайте событие столкновения головы с точкой. И не забудьте удалять точку.

Теперь змейка растет!

Появление точки в случайном месте

Snake минимальная координата

Диапазоном возможных координат у нас будет вся сцена. Так минимальная координата находится в левом верхнем углу и равна нулю (помните, точка привязки координат у объекта слева вверху).

А максимальная координата будет справа внизу. Вычислить значение максимальной координаты очень просто надо от размеров сцены отнять размеры объекта.

X координата: 640 (ширина Сцены) — 32 (ширина точки) = 608,

Snake максимальная координата

Y координата: 480 (высота сцены) — 32 (высота точки) = 448.

Таким образом нам нужно генерировать возможные координаты в диапазоне от 0 до 608 по X и от 0 до 448 по Y. И вы также должны помнить, что точка может появляться только на воображаемой клетке поля, про которые шла речь в начале статьи. Получается, что для точки есть 20 возможных координат по ширине и 15 возможных координат по высоте сцены из всего возможного диапазона.
Для генерации случайных координат появления точки нужно использовать генератор случайных чисел — это функция Random(n). Где n — это количественное значение начинающееся с нуля. Допустим выражение Random(3) будет генерировать числа: 0, 1, 2, но не 3!
Итак, что бы сгенерировать координаты в диапазоне всей сцены нужна следующая формула:

Random (Размер сцены / Размер Объекта) * Размер Объекта

Таким образом формула для X-координаты:
Random (Ширина сцены / Ширина Объекта) * Ширина Объекта
или
Random (20) * 32

640/32 получается 20, значит максимум Random может выдать 19, что в свою очередь означает что максимально мы сможем получить значение 608 (т.к. 19*32=608), а 608 и является максимально допустимым значением. Если же Random выдаст минимальное значение-0, то вся формула будет 0, это минимальная координата. В остальных вариантах (от 0 до 19) мы будем получать координату в пределах диапазона с шагом в 32. И в итоге получим 20 ПРАВИЛЬНЫХ случайных варианта для создания съедобной точки в координате X.

Формула для Y-координаты:
Random (Высота сцены / Высота Объекта) * Высота Объекта
или
Random (15) * 32

Если в вашем варианте минимальная координата начинается не с нуля, то формула корректируется простым прибавлением минимального значения координаты:
Минимальная координата + (Random (Размер сцены / Размер Объекта) * Размер Объекта)

Теперь код.

Snake отчищать от точки при старте

Что бы событие работало нужно удалить объект точки из области редактирования кадра, даже если объект находится не на самой сцене. Объект останется в игре благодаря событию Create Object, только сначала создайте его.
Либо можете сделать проще — удалять точку при запуске игры:

Snake змея вскользь с точкой

Теперь можете запустить игру и пособирать точки. Если у вас происходит баг того, что точка и змея на разных линиях,

значит голова змеи изначально находится в не соответствующих координатах, поставьте объект в координату кратную 32 (например 160х96).

Но это еще не все! Точка может появится в недопустимых местах: на хвосте змеи или на препятствии.

Нужно создать событие переопределения координат если такое происходит.

Условие OR (logical) означает, что для выполнения достаточно произойти какому-то одному из двух событий.

Игрок может увидеть момент когда точка на какой-то миг появляется на хвосте или на декорации, а это все таки баг. Нужно сделать точку невидимой пока она не найдет правильное место.
При создании точки задаем действие — сделать точку невидимой:


Делаем событие обратное событию столкновений точки с хвостом либо препятствием, и возвращаем видимость:

Negate — означает противоположное действие (есть не у всех событий). Иными словами, если не происходит столкновения точки с чем либо, то сделать её видимой.

Укусил за хвост или врезался в препятствие — проиграл

Ну тут все просто. Создаете событие столкновения головы с хвостом или с препятствием и включаете флаг №1 у объекта головы, а затем ставите условие, что змея движется только при отключенном флаге.

Препятствия

Snake тип obstacle

Далее стоит сделать препятствия, хотя бы для того, что бы создать границу уровня. Заранее предупреждаю, что событие ухода за сцену работать не будет.
Вам стоит делать препятствие размером 32×32 или какой там у вас размер клетки. Препятствие должно быть объектом backdrop и иметь тип Obstacle.

C препятствиями вы сможете строить различные уровни.

Snake хвост тянется за головой

В игре осталось доделать что бы хвост на повороте сменял анимацию и выглядел красиво с изгибом, а не так:

Задавайте вопросы в комментариях).

Машина для бурения тоннелей. Копает землю.

Превращение active в backdrop на примере машины для бурения

Создание базового движения змейки как в slither.io

Змейка io. Создание базового движения змейки как в slither.io

Дать имя персонажу в игре

Как сделать ввод имени для персонажа в игре

расширенный Choco breake

Совсем другой Chocobreak tutorial. Создание игр первый уровень

Почему хвост создаётся прямо поверх головы?
В этом случае поедание объекта становится невозможным, т.к. при соприкосновении тела и еды запускается алгоритм создания новой еды в рандомном месте. Что за дела

Но хвост не создаётся поверх головы. Скачайте и проверьте исходник

он создаётся прямо на голове, а вот если установить координаты появления относительно головы, т.е. тело появляется на расстоянии 32 по Х или У с плюсом или минусом (смотря в какую сторону поворачивать), то всё будет норм))

Очень полезный и понятный урок.Спасибо вам большое за вашу работу.Жду новых уроков

Спасибо за подробность. Очень полезно, что бы разобраться в принципе работы программы.)

Seyanis, полностью согласен.

отличный гайд, не думал что будет на столько подробно,огромное спасибо. Очень ценный урок, которых очень мало по CTF2.5

Читайте также: