GameMaker: Вид от 3-его лица в 3D

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

Вид от третьего лица

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

На картинке выше можно увидеть представление векторов для пары углов (обозначающих "горизонтальный" и "вертикальный" поворот камеры).
На левой части показано, что происходит в плоскости XY. Скорее всего вы уже знаете, о чем это (если пытаетесь сделать трехмерную игру) - компоненты вектора единичной длины вычисляются с помощью функций cos и sin соответственно.
Правая часть немного сложнее - тут показано (сбоку) что происходит при добавлении третьей оси и второго угла. Бывший XY вектор теперь плоский (потому что мы смотрим на него сбоку), и обозначен пурпурным цветом. Вращение вектора по вертикали уменьшает его длину в плоскости XY, и добавляет значение оси Z. Код для этого получается следующий:
vx = cos(pan) * cos(tilt);
vy = sin(pan) * cos(tilt);
vz = sin(tilt);
Или, если вы больше любите функции lengthdir_ (и/или градусы),
vx = lengthdir_x(lengthdir_x(1, pan), tilt)
vy = lengthdir_x(lengthdir_y(1, pan), tilt)
vz = lengthdir_y(1, pan)
После формирования вектора, настройка положения камеры проходит крайне просто:
d3d_set_projection(
	target.x + vx * distance,
	target.y + vy * distance,
	target.z + vz * distance,
	target.x, target.y, target.z,
	0, 0, 1)
(тут, distance - переменная, обозначающая расстояние между камерой и объектом)

Cel shading

На момент написания этой записи, GameMaker все еще не поддерживает шейдеры. Тем более в версии 8.0, для которой я предоставляю примеры (ради совместимости). Но, если в вашей игре не так уж и много полигонов, то есть один старый фокус для cel shading'а:
  1. Включаем скрытие обратных сторон полигонов (backface culling)
  2. Рисуем модель как обычно
  3. Рисуем немного большего размера, черный вариант модели с нормалями (полигонами) смотрящими в обратно направлении.
Поскольку скрытие включено, и внешняя модель "смотрит" вовнутрь, видно только ее части за\вокруг обычной, что выглядит как контур.
Конечно, это не очень хорошая стратегия для больших моделей (поскольку количество операций рисования удваивается), но для низко-полигональных моделей это не заметно.

Тени

Это еще одна вещь, которую не стоит делать, если у вас высоко-полигональные модели, и что применимо тут в связи с отсутствием таковых (и простотой реализации).
Используемый тут "фокус" заключается в том, что с помощью 3d трансформаций (d3d_transform_) можно "расплюснуть" модель (в данном случае сделать ее размер по оси Z нулевым), и нарисовать ее черным цветом, что будет выглядеть как тень. Опять таки, это удваивает количество рисуемых полигонов, поэтому для более сложных моделей лучше отрисовывать модель в поверхность, и потом рисовать оную.

Простая трехмерная физика

Несмотря на типичные представления об этом, реализация трехмерного движения лишь немного сложнее реализации двухмерного. С различием в нужде добавления лишней переменной (обычно z), которая будет меняться и использоваться при рисовании. В этом примере прыжки и столкновения между персонажем и полом занимают всего лишь 6 строк:
// Z movement:
if (z > 0) zspeed -= 0.5 // accelerate downwards if in air
z += zspeed
if (z < 0) { // hit ground
    z = 0
    zspeed = 0
}
if ((z <= 0) && keyboard_check(vk_space)) zspeed = 5 // jumping
Я постараюсь сделать отдельную запись по поводу трехмерных столкновений позже.

d3d_transform_stack_*

Несмотря на их полезность в управлении рисованием, эти несколько функций (по крайней мере d3d_transform_stack_push и d3d_transform_stack_pop) обычно остаются забытыми в пользу d3d_transform_set_identity. Польза тут заключается в том, что вы можете сохранить (задвинуть в стек) текущую матрицу трансформаций с помощью _push, и позже восстановить ее с помощью _pop. Поскольку состояние матрицы сохраняется на момент вызова, эти функции позволяют легче организовывать много-уровневое рисование, или же совмещать "общие" фрагменты трансформаций для оптимизации и избежания повторяемого кода. В общем, этот пример должен быть довольно полезным.

Скачать GMK

Похожие записи

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.