Первый шаг в создании логики игровой доски — выбор программного представления плитки игровой доски.
Чтобы выбрать способ представления плитки доски, подумайте о том, как вы и игрок будете использовать плитки доски. Настольная игра, как правило, состоит из некоторого множества пространств, которые отделены друг от друга и не пересекаются. Это отличается от мирового пространства в UEFN.
В мировом пространстве координаты представляются местоположениями vector3, то есть они могут находиться друг к другу настолько близко, насколько это позволяют числа с плавающей запятой. Поэтому мировые координаты являются скорее непрерывными, чем дискретными. Более того, множество различных позиций vector3 могут располагаться на одной и той же плитке доски. Из этого можно сделать несколько выводов:
Поскольку плитки доски являются дискретными, для представления наших позиций может потребоваться использовать дискретный тип данных (дискретные данные — это данные, принимающие диапазоны значений, соответствующих целым числам). Это значит, что вместо типа
floatследует использоватьint.Доска является двухмерной, поэтому вам нужно сохранить местоположение только в двух измерениях. Для хранения местоположения плитки доски не нужна трёхмерная структура данных.
Определение типов данных доски
Класс tile_coordinate представляет расположение плитки на игровой доске. Чтобы создать класс tile_coordinate, создайте новый файл Verse с именем utility.verse. В этом файле создайте новый модуль с именем DataTypes.
DataTypes<public> := module:
Добавьте в этот модуль новый класс TileCoordinate и определите компоненты класса.
using { /Verse.org/Simulation }
DataTypes<public> := module:
tile_coordinate<public> := class<concrete>:
@editable
Left<public>:int = 0
@editable
Forward<public>:int = 0
В игре «Бой по координатам» вы строите сетку доски 5 x 5. Это означает, что нужно определить границы игровой доски. Для этого создайте новый класс bounds, который определяет нижнюю и верхнюю границу возможных значений Left или Forward для tile_coordinate.
using { /Verse.org/Simulation }
DataTypes<public> := module:
tile_coordinate<public> := class<concrete>:
@editable
Left<public>:int = 0
@editable
Forward<public>:int = 0
Требуется структура, которая будет содержать границы одной игровой доски в одной структуре данных. Для этого создайте новый класс board_bounds, который будет определять нижнюю и верхнюю границу для каждого из компонентов tile_coordinate.
using { /Verse.org/Simulation }
DataTypes<public> := module:
tile_coordinate<public> := class<concrete>:
@editable
Left<public>:int = 0
@editable
Forward<public>:int = 0
Определение игровой доски
Теперь у вас есть структуры, которые позволяют:
определить представление плитки в пространстве доски;
определить границы пространства доски;
По-прежнему не хватает важного элемента — самой игровой доски. Для определения игровой доски создайте новый файл Verse с именем board.verse и добавьте новое устройство Verse под названием board.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }
using { /UnrealEngine.com/Temporary/SpatialMath }
using { /Verse.org/Assets }
using { DataTypes }
using { UtilityFunctions }
board<public> := class(creative_device):
Доска должна включать несколько элементов:
Где находится доска в мировом пространстве?
Каковы границы доски?
Каков размер плитки доски?
В первом вопросе новая переменная не нужна; вы можете использовать встроенное значение преобразования самого устройства. Вы можете получить transform устройства творческого режима с помощью функции API GetTransform.
Второй вопрос можно определить с помощью переменной board_bounds.
Третий вопрос можно решить, определив переменную vector2 для отслеживания размера плитки.
Два последних добавляются в качестве полей для устройства board.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }
using { /UnrealEngine.com/Temporary/SpatialMath }
using { /Verse.org/Assets }
using { DataTypes }
using { UtilityFunctions }
board<public> := class(creative_device):
Преобразование из пространства доски в мировое пространство
Затем определите расположение плитки в мировом пространстве как vector3, исходя из её местоположения на игровой доске, заданного как tile_coordinate. Назовите эту функцию ToVector3. Это нужно делать в пределах игровой доски, чтобы знать, где располагается её центр.
Сначала необходимо устранить неоднозначный момент. Для одной tile_coordinate может существовать множество различных мировых позиций vector3 на одной и той же плитке. На языке математики это функция «один ко многим». В идеале нужно выбрать одно местоположение в мире, которое будет обозначать, где именно плитка расположена в мировом пространстве. Естественным выбором будет центр плитки.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }
using { /UnrealEngine.com/Temporary/SpatialMath }
using { /Verse.org/Assets }
using { DataTypes }
using { UtilityFunctions }
board<public> := class(creative_device):
Эта функция выполняет следующие действия:
получает преобразование доски в мировом пространстве;
получает расположение доски в мировом пространстве из преобразования;
вычисляет смещение входной плитки относительно центра доски;
добавляет смещение к центру местоположения на доске, чтобы получить местоположение относительно центра мира.
Преобразование из мирового пространства в пространство доски
Если у вас есть местоположение в мировом пространстве в виде vector3, нужно преобразовать его в tile_coordinate.
Создайте функцию с именем ToTileCoordinate. Эта функция принимает в качестве аргумента vector3 и возвращает tile_coordinate. Если задана позиция в мировом пространстве в виде vector3, определить соответствующее расположение на игровой доске как tile_coordinate немного сложнее.
Основная сложность в том, что доска является дискретной сеткой, и многие позиции в мировом пространстве могут не принадлежать игровой доске. Следовательно, если задана позиция в мировом пространстве в виде vector3, она может вовсе не принадлежать игровой доске. Поэтому ToTileCoordinate является отличным кандидатом для использования спецификатора эффекта функции <decides>. Это связано с тем, что в игровом мире существует множество местоположений, не привязанных ни к одной координате плитки. В этом случае попытка преобразования не удастся. Важно знать, когда это преобразование выполняется успешно, а когда — нет. Функция ToTileCoordinate сначала определяет, находится ли местоположение на игровой доске, и, если да, возвращает соответствующее местоположение tile_coordinate.
Ещё одна причина повышенной сложности заключается в том, что одна плитка состоит из множества различных мировых местоположений. В математике это делает функцию ToTileCoordinate функцией «многие к одному».
Чтобы всё упростить, выделите часть ToTileCoordinate, допускающую ошибки, определите функцию IsTileCoordinateOnBoard отдельно и вызовите её в ToTileCoordinate.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }
using { /UnrealEngine.com/Temporary/SpatialMath }
using { /Verse.org/Assets }
using { DataTypes }
using { UtilityFunctions }
board<public> := class(creative_device):
Функция IsTileCoordinateOnBoard выполняет следующее:
определяет, находится ли левый компонент входной координаты плитки в пределах границ доски;
определяет, находится ли компонент Forward входной координаты плитки в пределах границ доски.
Функция IsTileCoordinateOnBoard выполняется успешно, если входная координата плитки находится в пределах границ доски; в противном случае она завершается с ошибкой.
Функция ToTileCoordinate выполняет следующее:
получает преобразование доски в мировом пространстве;
получает центр местоположения доски из мирового пространства;
вычисляет относительное мировое местоположение по отношению к центру доски;
преобразует относительное мировое местоположение в координату плитки;
определяет, находится ли координата плитки на доске;
возвращает координату плитки, если она находится на доске.
Функция ToTileCoordinate выполняется успешно тогда и только в том случае, если успешно выполняется IsTileCoordinateOnBoard.
Пример
В следующем разделе рассмотрен пример использования tile_coordinate и преобразования в vector3 с последующим обратным преобразованием vector3 в tile_coordinate.
Преобразование координаты плитки в Vector3
Предположим, у вас есть:
игровая доска размером 5 на 5 плиток;
игровая плитка размером 512,0 × 512,0 квадратных единиц.
Игровая доска находится по оси X := 5000,0; Y := 0,0; Z := 1000,0 в мировом пространстве.
Ниже описаны шаги для преобразования плитки с координатами Left := -1, Forward := 2,0 в мировое пространство.
ToVector3(tile_coordinate{Left := -1, Forward := 2.0})
BoardTransform:transform = GetTransform()
# BoardTransform := transform{Translation := vector3{X := 5000.0, Y := 0.0, Z := 1000.0}, ...}
CenterOfBoard:vector3 = BoardTransform.Translation
# CenterOfBoard := vector3{X := 5000.0, Y := 0.0, Z := 1000.0}
TileOffsetFromCenter:vector3 = vector3:
X := (TileLocation.Forward * TileSize.X)
Далее приведены шаги по обратному преобразованию с помощью функции ToTileCoordinate.
ToTileCoordinate(vector3{X := 6024.0, Y := 512.0, Z := 1000.0}):
BoardTransform:transform = GetTransform()
# BoardTransform := transform{Translation := vector3{X := 5000.0, Y := 0.0, Z := 1000.0}, ...}
CenterOfBoard:vector3 = BoardTransform.Translation
# CenterOfBoard := vector3{X := 5000.0, Y := 0.0, Z := 1000.0}
ShiftedWorldLocation:vector3 = WorldLocation - CenterOfBoard
# ShiftedWorldLocation := vector3{X := 6024.0, Y := 512.0, Z := 1000.0} - vector3{X := 5000.0, Y := 0.0, Z := 1000.0}
Это последнее значение tile_coordinate точно совпадает с начальным значением, то есть всё работает, как задумано.
Описание
Подведём итог. На этой странице вы выполнили следующие шаги:
определить представление плитки в пространстве доски;
определить границы пространства доски;
определить, где будет находиться пространство доски в мировом пространстве;
выполнить преобразование между пространством доски и мировым пространством.
Файлы
using { /Verse.org/Simulation }
DataTypes<public> := module:
tile_coordinate<public> := class<concrete>:
Left<public>:int = 0
Forward<public>:int = 0
bounds<public> := class<concrete>:
@editable
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }
using { /UnrealEngine.com/Temporary/SpatialMath }
using { /Verse.org/Assets }
using { DataTypes }
using { UtilityFunctions }
board<public> := class(creative_device):
тип