Найти тему
ZDG

Пишем платформер на C и JavaScript #2: Гравитация

Предыдущая часть: Введение

Отличительная характеристика платформера – возможность прыгать.

Нашим персонажем на первое время станет обычный прямоугольник. На нём мы будем отрабатывать все приёмы. Назовём его "тело" (в смысле физическое тело). У тела есть координаты (x,y), размеры (w,h), и скорость движения. Эта скорость имеет две составляющие: горизонтальную speed_x и вертикальную speed_y.

Горизонтально тело движется, когда мы нажимаем клавиши "влево" или "вправо". А вертикально – когда нажимаем клавишу "прыжок".

Прыжок мы могли бы сделать вручную. Например: сначала 20 раз уменьшаем координату y, а потом 20 раз её увеличиваем. Тогда персонаж поднимется на 20 пикселов и опустится на 20 пикселов.

Но тогда прыжок будет выглядеть неестественно. Вообще говоря, есть множество платформеров, где "физика" движения персонажа абсолютно разная. Где-то он движется именно неестественно, резко, а где-то плавно разгоняется и тормозит. От того, насколько хорошо это реализовано, зависит всё впечатление от игры. Ведь игроку должно быть в первую очередь комфортно перемещаться.

Нас интересует более реалистичная "физика". Для этого мы вводим гравитацию. Она будет действовать на тело постоянно, заставляя его падать вниз.

Как мы знаем, ускорение свободного падения на Земле это 9.8 метра в секунду в секунду. Это значит, что вертикальная скорость свободно падающего тела каждую секунду увеличивается на 9.8 м/с.

Наш игровой цикл будет работать на частоте 60 кадров в секунду. Значит, в каждом кадре нужно прибавлять к скорости 1/60 ускорения. В земных единицах это 0.16 м/с, но нам не нужно именно земное ускорение, нам нужно такое, с которым будет комфортно играть.

Скорость тела задаётся не в метрах, а в пикселах. Допустим, если скорость равна 5, тело перемещается на 5 пикселов за 1 кадр. Давайте заставим тело падать. Будем смотреть, как оно падает, онлайн на JavaScript. Для начала делаем объект, описывающий тело:

var body = { x:100, y:100, w:16, h:16, speed_x:0, speed_y:0 };

Мы описали его как квадрат размером 16*16 пикселов, с координатами на экране (100, 100) и с нулевыми скороcтями по горизонтали и вертикали.

Введём переменную gravity, которая должна прибавляться к вертикальной скорости:

var gravity = 0.1;

Теперь напишем функцию update(), которая будет вызываться 60 раз в секунду:

function update(event) {
body.y += body.speed_y;
body.speed_y += gravity;
}

В каждом кадре к координате y прибавляется скорость speed_y. Это значит, что в каждом кадре тело будет смещаться на speed_y пикселов. Но кроме того, к скорости speed_y прибавляется ускорение gravity. Это значит, что скорость speed_y будет в каждом кадре расти, и тело будет двигаться всё быстрее и быстрее.

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

if (body.y >= canvas.height) body.y = 0;

А если его скорость стала слишком большой, то ограничим её неким разумным пределом:

if (body.speed_y > 25) body.speed_y = 25;

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

Платформа

Теперь сделаем платформу. Пока что это будет просто некоторая плоскость, на которой может стоять тело. Она будет занимать всю ширину экрана, поэтому описать её можно всего лишь одной координатой:

var ground_y = 300;

Если тело упало ниже чем ground_y, то мы поставим его на платформу и обнулим его вертикальную скорость.

Изменим условия в функции update():

if (body.y + body.h >= ground_y) {
body.y = ground_y - body.h;
body.speed_y = 0;
}

Так как у тела координаты (x,y) обозначают левый верхний угол, а проваливается черeз платформу оно в первую очередь своей нижней стороной, то в сравнении участвует не координата body.y, а body.y + body.h. А чтобы поставить тело на уровень ground_y, нужно от ground_y отнять высоту тела:

body.y = ground_y - body.h;

Смотрим симуляцию ещё раз. Теперь тело падает на плоскость и останавливается.

Прыжок

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

body.speed_y = -10;

И всё! Эта скорость заставит тело двигаться вверх, но как только оно начнёт двигаться вверх, в дело сразу же вступит гравитация, и тело постепенно замедлится и начнёт падать вниз.

Сделаем обработчик события нажатия клавиши (подробнее см. в игре Robots):

document.addEventListener('keydown', process_input);

При нажатии любой клавиши будет вызываться функция process_input(). В ней мы определим, какая клавиша нажата, и если это стрелка вверх, то присвоим вертикальной скорости тела значение -10:

if (event.code == 'ArrowUp') body.speed_y = -10;

Опять смотрим симуляцию. Вы можете подпрыгивать, нажимая стрелку вверх. (Если не прыгает, значит у окна нет фокуса ввода, нужны тыкнуть мышкой в окно с симуляцией).

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

Ходьба

Что ж, раз мы умеем прыгать, то можно начать ходить. Для этого добавим в process_input() обработку стрелок влево и вправо. Но не всё так просто. Если для прыжка достаточно только нажать клавишу, то для горизонтального движения нужно её и нажимать, и отпускать. Пока клавиша нажата – мы движемся, когда отжата – перестаём двигаться.

Поэтому необходимо усложнить схему управления. Для начала нужно добавить обработчик отжатой клавиши:

document.addEventListener('keyup', process_input);

Обрабатывать будет та же функция process_input(), только теперь ей надо различать тип события: keydown или keyup. Если это keydown, мы назначаем скорости speed_x значение -5 или 5, а если keyup, то обнуляем скорость.

Также в функции update() вводим для координаты x ограничения, чтобы она не вышла за левый или правый край экрана.

Смотрим симуляцию ещё раз. Теперь вы можете перемещать тело влево и вправо, прыгать, а также совмещать прыжок и перемещение. При этом двигаться влево и вправо можно даже в воздухе. Некоторые платформеры дают персонажу такую возможность, некоторые нет. Мы посмотрим позже, нужно ли нам это.

Собственно, всё, движение у нас готово.

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

И заодно перепишем всё на языке C. Мы будем снова использовать библиотеку SDL, но уже другие её функции. Теперь мы вместо программного рендеринга будем использовать аппаратный, то есть задействовать графический ускоритель. Поэтому про это надо будет рассказать подробно.

Чтобы скачать и установить всё необходимое, обратитесь к Сапёру на C.

Наука
7 млн интересуются