게임보드의 로직을 생성하는 첫 단계는 프로그래밍 방식으로 게임보드 타일을 표현하는 방법을 결정하는 것입니다.
보드 타일 표현 방식을 설계하려면, 여러분과 플레이어가 보드 타일을 사용하는 방법을 생각해 보세요. 보드게임은 일반적으로 서로 개별적으로 분리되어 있고 고유한 별도 공간으로 구성되어 있습니다. 이는 UEFN 월드 스페이스와는 다릅니다.
월드 스페이스에서 좌표는 vector3 위치로 표현됩니다. 이는 좌표가 부동 소수점 수준으로 근접할 수 있다는 뜻으로, 월드 좌표가 별개라기보다는 보다 계속적이게 됩니다. 이에 더해 모두 같은 보드 타일에 있는 서로 다른 여러 vector3 위치도 있습니다. 이를 토대로 몇 가지 결론을 내릴 수 있습니다.
보드 타일은 서로 별개이므로, 별개의 데이터(별개 데이터란 integer 또는 정수값과 일치하는 값 범위를 취하는 데이터를 말함) 타입을 사용해 위치를 표현하는 것이 좋습니다. 즉,
float.type 대신int를 사용해야 한다는 뜻입니다.보드는 2차원이므로 2차원 내에서만 위치를 저장하면 됩니다. 보드 타일 위치 저장을 위해 3차원 구조는 필요하지 않습니다.
보드 데이터 타입 정의하기
tile_coordinate 클래스는 게임보드상의 타일 위치를 나타냅니다. tile_coordinate 클래스를 만들려면 이름이 utilities.verse인 새 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
좌표 전투에서는 5x5 보드 그리드를 만듭니다. 즉, 게임보드의 경계를 정의해야 한다는 뜻입니다. 이를 위해서는 tile_coordinateLeft 또는 Forward 값이 얼마나 작거나 클 수 있는지를 정의하는 새 클래스 bounds(각각 하한 및 상한 바운드)를 만듭니다.
using { /Verse.org/Simulation }
DataTypes<public> := module:
tile_coordinate<public> := class<concrete>:
@editable
Left<public>:int = 0
@editable
Forward<public>:int = 0
하나의 데이터 구조 내에서 단일 게임보드 바운드를 갖는 구조가 필요합니다. 이를 위해서는 tile_coordinate의 각 컴포넌트에 대해 하한 및 상한 바운드를 정의하는 새 클래스 board_bounds를 만듭니다.
using { /Verse.org/Simulation }
DataTypes<public> := module:
tile_coordinate<public> := class<concrete>:
@editable
Left<public>:int = 0
@editable
Forward<public>:int = 0
게임보드 정의하기
이제 다음을 위한 구조가 갖춰졌습니다.
보드 스페이스에서 타일 표현을 정의합니다.
보드 스페이스의 제한을 정의합니다.
아직 큰 조각이 하나 빠져 있습니다. 바로 게임보드 자체입니다. 게임보드를 정의하려면 이름이 board.verse인 새 Verse 파일을 만들고 이름이 board인 새 Verse 장치를 추가합니다.
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):
보드의 경우 몇 가지 사항을 고려해야 합니다.
월드 스페이스 내 보드의 위치는 어디인가?
보드의 바운드는 얼마나 되는가?
보드 타일의 크기는 얼마나 되는가?
첫 번째 질문에는 새 변수가 필요하지 않습니다. 장치의 내장형 트랜스폼을 사용하면 됩니다. GetTransform API 함수로 포크리 장치의 transform을 확보할 수 있습니다.
두 번째 질문은 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):
보드 스페이스에서 월드 스페이스로 변환
다음으로는 게임보드상 tile_coordinate 형식의 위치에 따라 월드 내에서 타일이 vector3 형식으로 위치할 곳을 정의합니다. 이 함수를 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가 완벽한 후보인 이유는 게임 월드 내에 타일 좌표상에 없는 여러 위치가 있기 때문입니다. 이 경우, 위치 변환 시도는 실패합니다. 변환이 언제 성공하고 실패하는지 아는 것이 중요합니다. 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 함수는 다음을 수행합니다.
입력 타일 좌표의 좌측 컴포넌트가 보드 바운드 사이에 있는지 확인
입력 타일 좌표의 전방 컴포넌트가 보드 바운드 사이에 있는지 확인
IsTileCoordinateOnBoard 함수는 입력 타일 좌표가 보드 바운드 내에 있을 경우 성공하고, 아닐 경우 실패합니다.
ToTileCoordinate 함수는 다음을 수행합니다.
보드의 월드 스페이스 트랜스폼을 구합니다.
월드 스페이스에서 보드 위치의 중앙을 구합니다.
보드 중앙을 고려하여 월드 위치의 상대적 위치를 계산합니다.
상대적 월드 위치를 타일 좌표로 변환합니다.
타일 좌표가 보드상에 있는지 확인합니다.
보드상에 있으면 타일 좌표를 반환합니다.
ToTileCoordinate 함수는 IsTileCoordinateOnBoard가 성공하는 경우에만 성공합니다.
예시
아래 섹션에서는 tile_coordinate를 가져다 vector3로 변환한 후, 동일한 vector3를 다시 tile_coordinate로 변환하는 예시를 살펴봅니다.
타일 좌표에서 Vector3로
다음 조건이 갖춰졌다고 가정합니다.
5x5타일 크기의 게임보드가 있습니다.
게임 타일은 512.0x512.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는 초기 값과 정확히 동일합니다. 모든 것이 의도한 대로 기능했다는 뜻입니다.
요약
요약해 보면, 이 페이지에서는 다음 단계를 살펴보았습니다.
보드 스페이스에서 타일 표현을 정의합니다.
보드 스페이스의 제한을 정의합니다.
월드 스페이스 내에서 보드 스페이스의 위치를 정의합니다.
보드 스페이스와 월드 스페이스 간 변환합니다.
Files
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):
type