Unlimited WordPress themes, graphics, videos & courses! Unlimited asset downloads! From $16.50/m
Advertisement
  1. Game Development
  2. Isometric Games

Создание изометрических миров: Руководство для разработчиков игр

by
Difficulty:IntermediateLength:LongLanguages:

Russian (Pусский) translation by Alex Grigorovich (you can also view the original English article)

В этом уроке я сделаю обзор того, что вам нужно знать для создания изометрических миров. Вы узнаете, что такое изометрическая проекция и как представить изометрические уровни в виде 2D массивов. Мы определим отношения между представлением и логикой, так что мы сможем легко управлять объектами на экране и контролировать взаимодействие структурных плиток. Мы также немного углубимся в процесс анимации персонажа.

Полезные статьи

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


1. Изометрический мир

Изометрическая проекция представляет собой метод, используемый для создания иллюзии 3D, или другими словами 2D игры - которая иногда называется псевдо 3D или 2.5D. Эти изображения, (взяты из Diablo 2 и Age of Empires) показывают, что я имею в виду:

diablo

Diablo 2
AOE

Age of Empires

Реализация изометрической проекции может быть выполнена разными способами, но для простоты я сосредоточусь на плиточном подходе, который является наиболее эффективным и широко используемым методом. Я наложил на каждый скриншот выше сетку, которая показывает как местность разделена на плитки.


2. Плиточные игры

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

Для примера давайте рассмотрим стандартное представление 2D с двумя плитка - плитка травы и плитка стены - как показано здесь:

base 2d tiles

Несколько простых плиток

Эти плитки одинакового размера, квадратной формы, поэтому высота и ширина у плиток одинаковы.

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

Здесь 0 обозначает плитки травы и 1 обозначает плитку стены. Организация плиток в соответствии с данными создаст примерно такой результат, как на картинке ниже:

2d level simple

Простой уровень, в представлении вида сверху.

Мы можем усложнить это добавив плитки углы и отдельные вертикальные и горизонтальные плитки стен, это потребует пять дополнительных видов плиток:

2d level complex

Усложнённый уровень с номерами плиток

Я надеюсь, что теперь концепция подхода, основанного на плитках понятна. Это реализация простой 2D сетки, которую мы могли бы представить в виде кода следующим образом:

Предположим, что ширина и высота плиток одинаковы (это верно для всех плиток) и соответствует разрешению изображения плитки. Итак, ширина и высота плитки для нашего примера 50px, а а размер всего уровня 300x300px - то есть, шесть рядов и шесть столбцов по 50x50px для каждой плитки.

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


3. Изометрическая проекция

Лучшее техническое объяснение того, что означает "изометрическая проекция", насколько мне известно, размещено в статье Clint Bellanger:

Мы меняем угол камеры по двум осям (смещаем камеру на 45 градусов в одну сторону, затем на 30 градусов вниз). Это создает похожую на алмаз (ромб) сетку, где пространство удвоено в ширину, так как оно вытянуто. Этот стиль был популярен в RPG и стратегических играх. Если мы посмотрим на куб в этом представлении, видны три стороны (верх и две лицевые стороны).

Хотя это звучит немного сложно, на самом деле реализация этого представления очень проста. То, что нам нужно понять, это отношение между 2D пространством и изометрическим - то есть, связь между уровнем данных и представлением; преобразование от прямых "Декартовых" координат к изометрических координатам.

the_isometric_grid

Декартова сетка против Изометрической.

(Мы не рассматриваем технику шестиугольных плиток, которая является еще одним способом реализации изометрических миров).

Размещение изометрических плиток

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

Мы постараемся создать изометрическую проекции для данных нашей стены пастбища:

В этом случае мы можем определить зону по которой можно перемещаться, проверяя, является ли элемент массива 0, определяя тем самым плитку с травой. 2D представление уровня было простой итерацией с двумя циклами, разместившей квадратные плитки, с отступами друг от друга с фиксированной высотой и шириной.

Для изометрическая проекции код остается тем же самым, но изменится функция placeTile().

Для изометрического вида необходимо вычислить соответствующие координаты внутри цикла.
Уравнения чтобы выполнить это будут такими, где isoX и isoY представляют изометрические x - и y координаты, а cartX и cartY декартовы координаты x и y:

Эти функции показывают как вы можете их конвертировать из одной системы в другую:

Псевдокод для цикла выглядит следующим образом:

isolevel screenshot

Наши стены пастбища в изометрической проекции.

В качестве примера давайте посмотрим, как обычная 2D позиция преобразуется в изометрическую:

Аналогичным образом, указание [0,0] приведет к результату [0, 0] а [10, 5] выдаст результат [5, 7,5].

Вышеуказанный метод позволяет нам создать соответствие между 2D уровнем данных и изометрическими координатами. Мы можем найти координаты плиток из данных декартовых координат с помощью следующей функции:

(Предполагается, что ширина высота и плитка плитка равны, как и в большинстве подобных случаев).

Следовательно из пары координат экрана (изометрических), мы можем найти координаты плитки путем выполнения команды:

Точкой экрана может быть, например, положение клика мышкой или какая-либо другая позиция.

Совет: Другим способом размещения является модель Зигзага, которая использует совсем другой подход.

Перемещение в изометрических координатах

Движение это очень просто: вы манипулируете данными вашего игрового мира в декартовых координатах и используете вышеупомянутые функции для обновления результата на экране. Например, если вы хотите переместить персонаж вперед по оси y, можно просто увеличить значение y и затем преобразовать позицию в изометрические координаты:

Создание глубины

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

Простейший метод создания глубины, это просто использовать значение декартовой координаты y, как уже упоминалось в этом Совете: чем дальше объект на экране, тем раньше он прорисовывается. Это работает хорошо до тех пор, пока у нас не появляются спрайты, которые занимают больше, чем одну плитку пространства.

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

split big tile

Большое изображение делится на несколько фрагментов стандартного изометрического измерения

4. Создание рисунков

Изометрические искусство может быть пиксельным, но не обязательно. Когда имеешь дело с изометрическим пиксельным рисунком, руководство RhysD расскажет вам почти все, что нужно знать. Некоторые техники можно найти на Википедии.

При создании изометрического рисунка, общие правила таковы

  • Начинайте с пустой изометрические сетки и придерживайтесь точности в пикселях.
  • Попробуйте разделить рисунок на несколько одиночных плиток.
  • Убедитесь, что каждая плитка определена как свободная для передвижения или нет. Будет трудно, если нам нужно разместить один элемент, содержащий как свободную, так и закрытую для перемещений области.
  • Для большинства плиток нужно будет создать плавный переход в одном или нескольких направлениях.
  • Тени сложно реализовать, пока мы не применим многослойный подход, в котором мы нарисуем слой тени на земле и нарисуем героя (или деревья, или другие объекты) на верхнем слое. Если подход, который вы используете не многослойный, убедитесь, что тени падают вперёд, таким образом, чтобы они не падали, например, на героя, когда он стоит за деревом.
  • В случае, если вам нужно использовать изображение плитки больше стандартных размеров, попробуйте использовать разрешение, кратное размеру плитки. Лучше применять многоуровневый подход в таких случаях, где рисунок можно разделить на несколько частей, в соответствии с его высотой. Например, дерево может быть разделено на три части: корень, ствол и листья. Это делает процесс создания глубины проще, так как мы можем нарисовать части на слоях, соответствующих их высоте.

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


5. Изометрические персонажи

Реализация персонажей в изометрической проекции не такая сложная, как может показаться. Изображение персонажа должно быть создано согласно определенным правилам. Сначала нам нужно будет определить, какие направления движения допускаются в нашей игре - обычно игры поддерживают четырёхсторонний или 8-и сторонний способ передвижения.

Eight-way navigation directions in top-down and isometric views

8-и сторонний способ передвижения в изометрической проекции.

Для вида сверху мы могли бы создать набор анимаций персонажей, задействованный в одном направлении и просто поворачивать их для всех остальных сторон. Для изображения изометрического персонажа нам нужно перерисовать каждую анимацию для каждом из возможных направлений - так для восьми сторон движения нам нужно создать восемь анимации для каждого действия. Для простоты понимания мы обычно обозначаем направления как Север, Северо-запад, Запад, Юго-Запад, Юг, Юго-Восток, Восток и Северо-Восток, против часовой стрелки, в данном случае.

spriteSheet

Изометрический персонаж перемещается в различных направлениях.

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

Мы установим две переменные, dX и dY, в зависимости от нажатой кнопки. По умолчанию эти переменные будут равны 0 и будут обновлены в соответствии с указаниями ниже, где U, D, R и L указывают вверх, вниз, вправо и влево, соответственно. Значение 1 под соответствующим ключом говорит о нажатии; 0 означает, что кнопка не нажата.

Теперь используя значения dX и dY, мы можем обновить декартовы координаты:

Итак, dX и dY ожидают изменения в x - и y позициях персонажа, основываясь на нажатия клавиш.

Мы можем легко вычислить новые изометрические координаты, как мы уже обсуждали:

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

Обнаружение взаимодействий

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

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

Глубина для персонажей

Рассмотрим персонаж и плитку  дерево для изометрического мира.

Для правильного понимания глубины, мы должны знать, что всякий раз, когда x - и y координаты персонажа  меньше, чем у дерева, дерево перекроет персонаж. Всякий раз, когда x - и y координаты персонажа больше, чем дерева, персонаж перекроет дерево.

Когда они имеют одинаковые x координаты, то мы решаем, основываясь на единственном y координате: у кого он больше, тот и перекроет другого. Когда они имеют одинаковые y координаты, то мы решаем, основываясь на единственном x координате: у кого он больше, тот и перекроет другого.

Чтобы проще понять это, последовательно нарисуйте уровень, начиная от дальних плиток - то есть, tile[0][0] - затем нарисуйте все плитки ряд за рядом. Если персонаж занимает плитку, мы сначала нарисуем плитки земли и затем отобразить плитку персонажа. Это будет работать, так как персонаж не может занимать плитку стены.

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


6. Вперёд!

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

Нажмите, чтобы SWF был в фокусе, а затем используйте клавиши со стрелками. Нажмите здесь чтобы получить полную версию.

Это класс может быть полезным (я написал его на AS3, но вы должны быть в состоянии понять на любом другом языке программирования):

Если вы запутались, вот код моего демо (в виде кода Flash и AS3):

Точки соприкосновений

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

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

Обнаружение взамодействий

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

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

Хитрости

В демоверсии я просто перерисовываю каждый кадр сцены на основе новой позиции героя.  Мы находим плитку, которую герой занимает и рисуем героя поверх плитки земли, когда цикл рендеринга достигает этих плит.

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

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


Заключение

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

Advertisement
Advertisement
Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.