Tilemap что это
Перейти к содержимому

Tilemap что это

Tilemap

The Tilemap component is a system which stores and handles Tile Assets for creating 2D levels. It transfers the required information from the Tiles placed on it to other related components such as the Tilemap Renderer and the Tilemap Collider 2D.

Use this component with the Grid component, or a parent Grid GameObject, to lay out Tiles on the associated Grid. When creating a Tilemap (menu: GameObject > 2D Object > Tilemap), Unity automatically creates a Grid GameObject and sets it as the parent of a child Tilemap GameObject.

To modify and place Tiles onto a Tilemap, open the Tile Palette (menu: Window > 2D > Tile Palette). Refer to the documentation on Tile Palette and Painting Tilemaps for more information.

Tilemap property windowTilemap property window

Свойство: Функция:
Animation Frame Rate The rate at which Unity plays Tile animations. Increasing or decreasing this changes the speed by the equivalent factor (for example, if you set this to 2, Unity plays Tile animations at double the speed).
Color Tints the Tiles on this Tilemap with the selected Color. When set to white, Unity renders the Tiles with no tint.
Tile Anchor The anchoring offset of a Tile on this Tilemap. Adjust the position values to offset the cell position of the Tile on the associated Grid.
Идентификация The orientation of Tiles on the Tilemap. Use this if you need to orientate Tiles on a specific plane (particularly in a 3D view).
XY Unity orients tiles on the XY plane.
XZ Unity orients tiles on the XZ plane.
YX Unity orients tiles on the YX plane.
YZ Unity orients tiles on the YZ plane.
ZX Unity orients tiles on the ZX plane.
ZY Unity orients tiles on the ZY plane.
Custom Unity lays out tiles based on the custom orientation matrix settings set by the parameters below, which become editable when you select this option.
Position Displays the position offset of the current orientation matrix.
You can only edit this property when the Tilemap’s Orientation is set to Custom.
Rotation Rotation of the current orientation matrix.
You can only edit this property when the Tilemap’s Orientation is set to Custom.
Scale Scale of the current orientation matrix.
You can only edit this property when the Tilemap’s Orientation is set to Custom.

Tilemap Workflow

Below is the general workflow to create and paint a Tilemap:

  1. Create a Tilemap GameObject. A Grid GameObject is also created automatically in the process.
  2. Create Tile Assets directly, or generate Tiles from Sprites.
  3. Create a Tile Palette with selected Tile Assets.
  4. Paint on a Tilemap with your Tile Palette.
  5. Optionally, attach the Tilemap Collider component to your Tilemaps to have them interact with Physics2D.

Unity also supports specialized types of Tilemaps such as Hexagonal and Isometric Tilemaps. Refer to the documentation on their respective pages for their specific workflows.

Собственный Tilemap движок в черновиках Из песочницы

В данной статье я научу Вас создавать уровни практически для игр любого жанра и сделать их разработку значительно проще. Мы создадим tile map движок, который Вы сможете использовать в своим проектах. Мы будет использовать Haxe и OpenFL, но процесс создания схож для многих языков.

  • Что такое tile-based игра?
  • Создание или поиск собственных «плиток»
  • Написание кода для отображения уровня
  • Редактирование уровней
Что такое tile-based игра?
  • Tile — плитка — маленькой изображение, обычно прямоугольной формы, которое выступает в роли кусочка пазла при построении больших изображений
  • Карта — группа плиток, объединенных вместе
  • Tile-based отсылает нас к методу созданий уровней в играх. Код размещает плитки в заранее определенных местах
Создание или поиск плиток

Первое, что нужно для построения движка — набор плиток. У Вас есть два варианта: использовать уже готовые tiles или сделать свои собственные. Если Вы решите использовать готовы изображение, то их можно легко найти по всему интернетом. Минусом является то, что эта графика не была сделана специально для вашей игры. С другой стороны, если Вы просто экспериментируете, то данный вариант вполне подойдет.

Думаю, что с поиском плиток возникнуть проблем не должно, поэтому я не буду подробно на этом останавливаться.

Создание плиток

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

Написание кода

Когда у нас имеется все необходимое, мы может погрузиться непосредственно в само программирование.

Отображение одной плитки на экране

Давайте начнем с простейшей задачи, отображение одной плитки на экране. Убедитесь, что все Ваши изображения имеют один размер и сохранены в разных файлах (о хранении спрайтов в одном фале мы поговорим позже).

Как только все Ваши плитки находятся в папке с ресурсами проекта, Вы можете написать простой Tile класс. Вот пример на Haxe

Сейчас, все, что мы делаем — помещаем плитку на экран. Единственная вещь, которую делает класс — импортирование изображение из папки с ресурсами и добавление в качестве дочернего объекта. То, как будет выглядеть данный класс очень сильно зависит от языка программирования, который Вы используете.

Теперь, когда у нас есть класс Tile , нам нужно создать экземпляр Tile и добавить его в нашем главном классе.

Класс Main создает новый объект Tile при вызове конструктора и добавляет его в список отображения.

Когда запускается игра, будет вызвана функция main() и новый объект типа Main будет добавлен на сцену. Обратите внимание, что Ваша новая плитка появится в левом верхнем углу экрана.

Использование массивов для отображения всех плиток

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

У нас есть выбор: использовать обычный массив или матрицу. Если Вы не знакомы с матрицами, то просто знайте, что это массив, который содержит в себе еще массивы. Большинство языков программирования представляют это, как nameOfArray[x][y].

X и Y мы используем, как координаты на экране. Может быть нам удастся использоваться эти X и Y для отображения наших плиток? Итак, давайте взглянем на матрицу

Заметим, что нулевой элемент в данном массиве — массив из пяти чисел. Это значит, что сначала вы получаете элемент y, а затем x. Если Вы попытаетесь взять элемент [1][0], то Вы получите доступ к шестой плитке.

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

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

Теперь, давайте напишем код, создающий наш массив. Заполним его 1. Цифра один будет означать ID нашей первой плитки.

Для хранения массива нам нужно создать переменную внутри класса Main

Может выглядеть немного странно, поэтому я поясню.
Имя переменной — map, а тип — Array (массив). означает, что массив содержит числа.
Теперь, добавим немного кода в наш конструктор нашего класса, чтобы инициализировать нашу карту

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

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

Здесь мы задаем значение 10 для переменной w и 6 для h, как я уже сказал. Дальше, мы должны пройтись циклом по массиву, чтобы уместить 10 * 6 чисел.
image
Теперь у нас есть простенькая карта, но нам же нужно расположить плитки правильно, так? Для этого вернемся обратно в класс Tile и создадим функцию, позволяющую нам это сделать

Когда мы вызываем функцию setLoc() , мы передаем координаты x и y. Функция берет эти значения и переводит их в координаты в пикселях, умножая на TILE_WIDTH и TILE_HEIGHT

Единственная вещь, которую осталось сделать — описать в классе Main процесс создания и позиционирования плиток на карте

Да! Все правильно. Экран заполнен плитками. Давайте разберемся, что происходит выше

Формула

Давайте обсудим формулу, о которой я упоминал выше.

Мы вычисляем x , присваивая ему остаток от деления i на w . Это делается для того, чтобы вернуть x значение 0 в начале каждой линии.
image
Для y мы берем floor() от i / w.

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

Например: Экран размером 500х500, а плитки — 100х100, а Ваш мир — 1000х1000. Вам нужно делать простую проверку перед отрисовкой плитки.

Все, что нам осталось — создать разные типы плиток и отобразить что-нибудь красивое.

Разные типы плиток

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

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

Вернемся в конструктор класса Main и отредактируем наш цикл

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

Сейчас все стало на свои места, но нужно придумать дизайн карты вместо того, чтобы заполнять ее случайными блоками. Первое, удалите цикл в конструкторе Main , заполняющий массив единицами. А затем создайте Вашу карту вручную

Если отформатировать массив, как сделано у меня, то можно легко увидеть примерный облик уровня. Но никто не запрещает Вам забить массив просто в одну строку.

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

Эта короткая проверка избавит нас от надоедливой ошибки с нулевым указателем. Последнее изменение затронет функцию setLoc() . Мы пытаемся использовать переменные x и y , которые не были инициализированы

Благодаря этим двум простым условиям Вы теперь можете запустить игру и увидеть простой уровень. Тайлы, которые умеют id 0 мы воспринимаем, как пустое место. Добавьте какой-нибудь фон. чтобы это выглядело более привлекательно.
image

Что такое тайловые карты?

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

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

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

Рисование тайловой карты

Исходный код этого раздела находится в папке chapter-3/example-1-simple-tilemap или здесь. Файл HTML такой же как и в прошлых примерах: он просто загружает Phaser и наш файл game.js, в котором на самом деле происходят все интересные моменты этого раздела.

Предварительная загрузка таблицы спрайтов

Текстурный атлас (texture atlas или spritesheet — спрайт-лист) представляет собой файл изображения, который сочетает в себе множество различных графических объектов в одном файле. Веб-игры, как правило, используют их, потому что они позволяют одним файлом передать все необходимые изображения на компьютер игрока.

В нашем примере используется простой текстурный атлас, в котором все изображения имеют одинаковый размер и размещаются рядом друг с другом, как хорошо организованный набор марок на странице. Например, предположим, что каждое изображение имеет размер 10 на 10 пикселей и у вас есть десять изображений в двух строках в спрайт-листе — это означает, что у вас есть один файл изображения размером 20 на 50 пикселей со всеми вашими изображениями внутри. Многие часто называют эти изображения, содержащиеся в текстурном атласе, спрайтами. Однако вы также увидите, что это же слово применяется к элементам игры, которые движутся по экрану, что может сбивать с толку, если вы новичок в разработке игр. Мы будем называть их тайлами или плитками, если они не относятся к игровым элементам, которые представляют собой движущиеся объекты, такие как игрок или монстры. Тем не менее, все они взяты из одного файла.

Наша таблица спрайтов взята из свободно доступного пакета игровых изображений Кенни и выглядит великолепно (рис. 3-1 ). Рисунок 3-1. Образец текстурного атласа.

Как видно, в нем много разных плиток, и мы сможем комбинировать их для карты для игры в жанре roguelike. Каждое изображение в этой таблице тайлов представляет собой квадрат шириной 16 пикселей. Они разделены промежутками в 1 пиксель. Исходный код для предварительной загрузки таблицы спрайтов требует передачи всей этой информации. Теперь в файле game.js функция preload() выглядит так:

Как и другие методы, функция preload() использует функцию из пространства имен this.load.* для загрузки спрайт-листа. Аргументы этой функции:

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

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

Базовая карта тайлов

Чтобы отображать сетку тайловой карты, мы будем использовать двумерный массив, где каждый элемент — это число, которое соответствует тайлу в нашем текстурном атласе. Подземелье 5×5 с текстурированными стенами с каждой стороны и свободным пространством в центре будет задаваться:

И это приведет к подземелью, которое выглядит так: Рисунок 3-2. Пример простого подземелья 5×5.

Если вы проверите спрайт-лист, то увидите, что область пола являются первым изображением на листе, а область стен — вторым изображением. Поскольку массивы в JavaScript имеют нулевой индекс, то они становятся изображением 0 и изображением 1 из текстурного атласа.

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

В функции create() мы соберем нашу тайловую карту. Карта, используемая в примере кода для этого раздела имеет размер 10×10 плиток.

Мы выбрали 0 для пола и 1 для стены на нашей карте. После этого нам нужно переназначить их на правильные значения для текстурного атласа, который мы используем. Пол в нашем текстурном таласе действительно имеет то же значение, что и значение, которое мы используем, но для стены мы собираемся использовать изображение 826, которое представляет собой кирпичную стену. (Позиция тайлов может меняться в зависимости от версии текстурного атласа).

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

Давайте воспользуемся этим объектом config , чтобы создать тайловую карту и прекрипить к ней tileset (набор тайлов, который содержит данные о наших плитках). Набор тайлов — это то, что сопоставит наш текстурный атлас с тайловой картой.

Тайловая карта создается путем передачи объекта config в метод this.make.tilemap() , а затем унаследованный метод созданной карты используется для добавления к ней набора тайлов . Вы можете создавать всевозможные игровые объекты, используя методы из this.make.* , которые являются частью класса GameObjectCreator.

Phaser поддерживает множество различных форматов данных карт, помимо используемых нами массивов. Многие разработчики используют редакторы карт, такие как Tiled, для создания своих карт. Эти редакторы могут экспортировать карту в расширенных форматах, которые Phaser может импортировать. Поскольку мы не используем такие инструменты, нам приходится вручную указывать много данных, которые будут присутствовать в экспортированных данных карты.

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

Параметры метода addTilesetImage :

  • tilesetName — строка, являющаюся именем создаваемого набора тайлов;
  • key — строка-ключ изображения из Phaser.Cache, используемого для этого набора тайлов;
  • tileWidth — ширина тайла;
  • tileHeight — высота тайла;
  • tileMargin — поле вокруг тайла;
  • tileSpacing — расстояние между каждой плиткой на текстурном атласе;
  • gid — Если добавляется несколько наборов тайлов на пустую карту, то здесь указывается начальный GID, который этот набор будет использовать.

Первый аргумент addTilesetImage — это имя набора тайлов, экспортированное в данные map . У нас нет данных карты, поскольку мы не используем редактор карт. Мы передаем тайлы, которые являются тем же ключом, который мы использовали при загрузке текстурного атласа. Второй аргумент — это ключ кэшированного изображения из preload() , то есть ’tiles’. Если мы не передадим этот второй параметр, он будет использовать первый как ключ для поиска изображения, что немного сбивает с толку. Мы просто передаем их оба, чтобы было понятно, что мы делаем. Остальные аргументы — это все данные, которые будут присутствовать при экспорте из редактора карты, и все они нам необходимо явно передать, поскольку мы собираем все вручную. Третий и четвертый аргументы — это размер тайла: их ширина и высота. Пятый и шестой аргументы связаны с полем вокруг таблицы спрайтов и промежутком между изображениями. Все значения в пикселях.

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

До версии Phaser v3.50.0 слои разделялись на статический и динамический. статический слой был обладал большей производительностью, но не позволял применять эффекты к тайлам. Для создания таких слоев использовались соответственно методы: createStaticLayer и createDynamicLayer . В новых версиях библиотеки оба этих метода являются устаревшими и по факту остались только динамические слои и создаются методом createLayer:

Несмотря на то, что мы назначаем наш слой переменной ground , в дальнейшем мы ничего не будем с ней делать. Мы это делаем просто чтобы задокументировать, что это нижний слой, где расположены пол и стены. Первый аргумент createLayer() — это идентификатор слоя; это может быть число или строка и используется другими функциями для ссылки на слой. Мы используем число 0, потому что присвоение ему строкового имени используется только при загрузке карт, экспортированных из редактора карт Tiled. Второй аргумент — это ранее созданный набор плиток. Третий и четвертый — координаты x и y, по которым надо размещать слоя в мире.

Если вы загрузите этот пример в свой браузер, вы увидите тайловую карту, похожую на рисунок 3-3. Рисунок 3-3. Базовая карта тайлов

И вот так вы рисуете тайловую карту. В этом разделе было много что стоит обмозговать, и очень полезно проверить связанную документацию по функциям Phaser. Еще одно важное упражнение, которое нужно сделать сейчас — это поэкспериментировать с этим массивом карт и различными значениями. Можете ли вы разместить в этой комнате четыре колонны? Скелет на земле?

А как насчет рисования темницы? Что ж, это наш следующий пример.

Базовое подземелье

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

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

Следующий пример находится в папке chapter-3/example-2-basic-dungeon или здесь. Это практически тот же код, что и в предыдущем примере. Единственное изменение состоит в том, что мы изменили массив level , чтобы он стал настоящей картой, похожей на подземелье, а не простой сеткой 10 на 10. Еще одно небольшое изменение заключалось в изменении загрузки файла game.js в HTML, так как нам надо пометить его как модуль JavaScript, чтобы мы могли использовать внутри него импорт для загрузки данных карты из другого файла:

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

Загрузите его, и вы увидите подземелье, как на рис. 3-4. Рисунок 3-4. Базовое подземелье.

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

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