Программирование 2D-игр на языке C: Snake

Цель этого урока - научить программированию 2D-игр и C-языку на примерах. Автор программировал игры в середине 1980-х годов и был дизайнером игр в MicroProse в течение года в 90-х. Хотя многое из этого не относится к программированию современных больших 3D-игр, для небольших казуальных игр это послужит полезным введением.

Реализация Змея

Такие игры, как змея, где объекты движутся по 2D-полю, могут представлять игровые объекты либо в 2D-сетке, либо в виде одномерного массива объектов. «Объект» здесь означает любой игровой объект, а не объект, используемый в объектно-ориентированном программировании.

Управление игрой

Клавиши перемещаются с W = вверх, A = влево, S = вниз, D = вправо. Нажмите Esc, чтобы выйти из игры, f, чтобы переключить частоту кадров (она не синхронизируется с дисплеем, поэтому может быть быстрой), нажмите клавишу табуляции, чтобы переключить отладочную информацию, и p, чтобы приостановить ее. Когда он приостановлен, заголовок меняется, и змея мигает,

У змеи основными игровыми объектами являются

instagram viewer
  • Змея
  • Ловушки и фрукты

Для целей игрового процесса массив целых будет содержать каждый игровой объект (или часть для змеи). Это также может помочь при рендеринге объектов в экранный буфер. Я разработал графику для игры следующим образом:

  • Горизонтальное тело змеи - 0
  • Вертикальное тело змеи - 1
  • Голова в 4 х 90 градусов вращения 2-5
  • Хвост в 4 х 90 градусов поворотов 6-9
  • Кривые для изменения направления. 10-13
  • Яблоко - 14
  • Клубника - 15
  • Банан - 16
  • Ловушка - 17
  • Посмотреть графический файл змеи snake.gif

Таким образом, имеет смысл использовать эти значения в типе сетки, определенной как блок [WIDTH * HEIGHT]. Поскольку в сетке всего 256 мест, я решил сохранить ее в одном массиве измерений. Каждая координата в сетке 16 x16 является целым числом 0-255. Мы использовали целые, чтобы вы могли увеличить сетку. Все определяется #defines с WIDTH и HEIGHT и 16. Поскольку змеиная графика имеет размер 48 x 48 пикселей (GRWIDTH и GRHEIGHT #defines), окно изначально определяется как 17 x GRWIDTH и 17 x GRHEIGHT, чтобы быть немного больше, чем сетка.

Это имеет преимущество в скорости игры, так как использование двух индексов всегда медленнее, чем одного, но это означает, что вместо сложения или вычитания 1 из Y-координат змеи для вертикального перемещения вы вычитаете WIDTH. Добавьте 1, чтобы двигаться вправо. Однако, будучи хитрым, мы также определили макрос l (x, y), который преобразует координаты x и y во время компиляции.

Что такое макрос?

 #define l (X, Y) (Y * WIDTH) + X

Первый ряд - индекс 0-15, второй 16-31 и т. Д. Если змея находится в первом столбце и движется влево, то проверка попадания в стену, прежде чем двигаться влево, должна проверить координату% WIDTH == 0 и координату правой стены% WIDTH == WIDTH-1. % Является оператором модуля C (как арифметика часов) и возвращает остаток после деления. 31 деление 16 оставляет остаток 15.

Управляющий Змея

В игре используются три блока (массива int).

  • змея [], кольцевой буфер
  • shape [] - содержит графические индексы Snake
  • dir [] - содержит направление каждого сегмента змеи, включая голову и хвост.

В начале игры змея состоит из двух сегментов длиной с головой и хвостом. Оба могут указывать в 4 направлениях. На севере голова имеет индекс 3, хвост - 7, на восток - 4, хвост - 8, на юг - 5, хвост - 9, а на западе - голова 6 и хвост - 10., В то время как змея имеет длину в два сегмента, голова и хвост всегда находятся на расстоянии 180 градусов, но после роста змеи они могут быть на 90 или 270 градусов.

Игра начинается с головы, обращенной к северу в точке 120, и хвоста, обращенного к югу в точке 136, примерно по центру. При небольшой стоимости хранения около 1600 байт мы можем добиться заметного улучшения скорости в игре, удерживая местоположения змеи в кольцевом буфере snake [], упомянутом выше.

Что такое кольцевой буфер?

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

Каждое местоположение змеи (то есть единственная int-координата) от хвоста до головы (то есть назад) сохраняется в кольцевом буфере. Это дает преимущества в скорости, потому что независимо от того, сколько времени проходит змея, необходимо менять только голову, хвост и первый сегмент после головы (если она существует) при движении.

Хранение в обратном направлении также полезно, потому что, когда змея получает пищу, змея будет расти, когда ее в следующий раз перемещают. Это делается путем перемещения головки на одну позицию в кольцевом буфере и изменения прежней позиции головки, чтобы она стала сегментом. Змея состоит из головы, 0-п сегментов), а затем из хвоста.

Когда змея ест пищу, переменная atefood устанавливается на 1 и проверяется в функции DoSnakeMove ()

Перемещение Змеи

Мы используем две индексные переменные, headindex и tailindex, чтобы указывать на расположение головы и хвоста в кольцевом буфере. Они начинаются с 1 (headindex) и 0. Таким образом, местоположение 1 в кольцевом буфере содержит местоположение (0-255) змеи на доске. Местоположение 0 содержит местоположение хвоста. Когда змея перемещается на одну позицию вперед, как tailindex, так и headindex увеличиваются на единицу, округляясь до 0, когда они достигают 256. Так что теперь место, где была голова, - это то, где находится хвост.

Даже с очень длинной змеей, которая извивается и извивается в 200 сегментах. только головной индекс, сегмент рядом с головой и хвостовой индекс меняются при каждом движении.

Обратите внимание, из-за способа SDL работает, мы должны нарисовать всю змею каждый кадр. Каждый элемент рисуется в буфере кадра, затем переворачивается, чтобы он отображался. Это имеет одно преимущество: мы можем нарисовать змею, плавно перемещающуюся на несколько пикселей, а не на всю позицию сетки.

instagram story viewer