Verse 퍼시스턴스가 적용된 스피드웨이 경주(Speedway Race with Verse Persistence) 템플릿은 UEFN으로 변환된 포크리 스피드웨이 경주 디자인하기 템플릿으로, 프로젝트에 다음 기능이 추가되어 있습니다.
게임 시작 전 대기실에서 Verse 퍼시스턴스를 사용하여 첫 번째 라운드에만 표시되는 퍼시스턴스 로컬 순위표
Verse 퍼시스턴스를 사용하여 이전 라운드 완주 순서에 따라 출발선에 있는 자동차에 플레이어를 할당하는 시스템
시네마틱과 Verse를 사용하여 각 플레이어의 통계를 표시하는 시작 라인업
그리고 더 많은 기능이 있습니다!
포크리 스피드웨이 경주 디자인하기 템플릿은 경주 트랙 에셋을 사용하여 몇 가지 유익한 기능을 바탕으로 독특한 경주 모드를 제작할 수 있도록 마련된 것입니다. 이 UEFN 템플릿에서는, 맵 전반에서 많은 기능을 대체하고 업그레이드하여 UEFN의 강력한 기능을 활용할 수 있도록 전체적인 접근 방식을 취했습니다.
다음 섹션에서는 이러한 업데이트에 대해 자세히 살펴보겠습니다.
튜토리얼 구역 업그레이드하기
순위표는 튜토리얼 구역에서 찾을 수 있습니다. 맵에서 첫 번째 라운드를 로드할 때마다 30초 동안 현재 순위표를 확인하고 튜토리얼 구역을 탐색할 수 있습니다.
이 구역은 경주의 재미를 찾는 플레이어에게 시각적으로 흥미를 주는 한편, 템플릿처럼 맵을 제작하는 방법에 대한 풍부한 세부 정보를 제공하도록 만들어졌습니다. 튜토리얼 구역은 포크리 템플릿에서 더 깨끗하고 개방된 느낌으로 다시 디자인되었으며, 스카이라이트가 추가되어 자연스러운 루멘 라이트 몇 가지를 적용했습니다.
UEFN에서 템플릿을 로드할 때 각 장치 그룹의 구성과 Verse 스크립트를 읽어보고 템플릿이 제작된 방식을 알아볼 수 있으며, 자신만의 경험에 이를 구현해 볼 수 있습니다.
튜토리얼 구역은 대부분의 장치가 있는 곳이므로 해당 장치를 살펴보고 로직을 이해할 수 있습니다. 여기에는 핵심 리텐션, 업적 및 분석 자료 장치가 포함됩니다. 업적 장치는 한 랩을 다 돌거나 경주를 마칠 때만 XP를 지급합니다.
분석 자료 장치를 설정하면 다양한 데이터 포인트를 추적하면 향후 업데이트에서 프로젝트를 개선할 수 있습니다. 이 템플릿은 각 체크포인트를 완료하는 빈도와 경주 중에 플레이어가 실버 코인을 지나가는 빈도를 추적하는데, 둘 모두 특정 체크포인트나 코인을 얼마나 쉽게 또는 얼마나 어렵게 달성할 수 있는지에 대한 데이터를 제공합니다. 이 데이터에 기반하여 향후 릴리즈에서 이러한 오브젝트의 위치나 개수를 조정하면, 전체 게임 흐름이 더 매끄러워져 더 뛰어난 경주 경험을 제공할 수 있습니다.
아웃라이너 정리하기
UEFN으로 프로젝트를 변환한 후에 아웃라이너(Outliner)에는 정리되지 않은 에셋이 정말 많았습니다.
그래도 모든 에셋이 작동하긴 했지만 탈것, 장벽 및 다른 아이템의 이름에 번호가 추가되어 있어 프로젝트 구조를 이해하기가 어려웠습니다. 이는 각 에셋과 장치가 고유한 이름을 가지도록 변환 프로세스에서 숫자를 자동으로 추가한 것입니다.
이를 관리하기 위해 프로젝트에 파일 시스템을 추가하여 모든 오브젝트를 위치와 기능에 따라 정리했습니다. 정리하는 데 시간이 걸리긴 하지만, 이 시스템을 사용하면 오브젝트나 전체 영역 그룹을 포크리보다 훨씬 효율적으로 이동하거나 삭제할 수 있습니다.
퍼시스턴스 로컬 순위표
오리지널 포크리 맵에는 퍼시스턴스 데이터가 없기 때문에 이전 경주 승자와 플레이어 통계를 추적할 수 없었습니다. 업데이트된 UEFN 템플릿 맵에서 Verse와 Verse 퍼시스턴스를 사용하면 게임 세션 간에 플레이어 데이터를 저장하고, 지금까지 기록한 플레이어 통계를 모니터링하고, 로컬 순위표를 만들 수 있습니다. 현재 세션에 있는 플레이어의 플레이어 데이터에만 액세스할 수 있으므로, 순위표에는 현재 플레이 중인 플레이어의 통계만 반영됩니다.
저희는 플레이어별로 추적할 수 있는 가장 중요한 퍼시스턴스 통계로 '시상대'와 '랩타임'을 정했습니다. 상위 3위 안에 드는 플레이어만 시상대에 오를 수 있으며, 최고 랩타임은 가장 빨리 완주한 레이서를 추적합니다. 또한 'points'로 명명한 통계를 추가하기도 했습니다. 플레이어는 경주 중 자신의 순위에 따라 포인트를 받으므로, 경주를 많이 하지만 좋은 순위를 꼭 차지하지는 못하는 플레이어의 경우 그래도 많은 포인트를 획득할 수 있습니다. 이러한 통계를 통해 가장 치열하게 경주하고, 가장 빠르고, 가장 헌신적인 레이서 모두를 인정할 수 있는 방법을 찾을 수 있었습니다.
변환된 템플릿은 로컬 순위표가 있는 게임 시작 전 대기실을 사용하며, 여기에서 각 플레이어가 지금까지 기록한 통계를 보여줍니다. 이러한 통계는 지금까지 기록한 것 중 최고 포인트 통계를 가진 플레이어가 맨 앞에 나타나도록 정렬되며, 상위 3명의 플레이어가 강조되어 본인의 스킬을 뽐냅니다. 또한 이러한 통계가 출발 라인업 시네마틱 중 HUD에 표시되므로, 플레이어는 미리 경쟁 상대를 살펴보고 경주 중에 누구를 조심해야 할지 알아둘 수 있습니다.
퍼시스턴스 로컬 순위표를 만드는 방법에 대한 자세한 내용은 나만의 게임 내 순위표 만들기를 확인하세요.
출발선에서 레이서 순서
변환된 템플릿은 오리지널 프로젝트에서 출발선에 있는 레이서의 랜덤 순서를 이전 라운드의 레이서 순위에 따른 순서로 대체합니다. 이는 플레이어가 1위가 아닐 때도 경주를 빠르게 완료하도록 유도합니다.
첫 번째 라운드에서는, 레이서가 랜덤 순서로 배치되지만, 첫 라운드 이후에는 이전 라운드를 완주한 순위대로 순서가 지정됩니다. 이 정보는 라운드 간에 저장되지만 게임 종료 후에는 유지되지 않습니다. 이를 사용하면 이전 완주 순서에 따라 플레이어를 정렬하는 방식으로 시작 순서를 결정할 수 있습니다. 라운드 정보를 저장하고 데이터를 정렬하는 방법을 알아보려면 다음 튜토리얼을 확인하세요.
# Orders and returns players by their finish order in the previous round.
# During the first round, players are given random starting placements.
GetPlayerStartOrder<public>(Players:[]player):[]player=
var OrderedPlayers:[]player = Players
if:
IsFirstRound[GetRound[]]
then:
# Randomize player order because it's first round.
set OrderedPlayers = Shuffle(OrderedPlayers)
탈것에 플레이어를 할당하고 출발선에 플레이어를 설정할 때, 플레이어가 실제로 활성 상태이며 경주에 참여할 플레이어인지 확인해야 합니다. 이를 위해 GetAllValidPlayers()로 명명된 함수를 만들어, 모든 플레이어를 한 명씩 확인하면서 아직 활성 상태이면서(아직 경기를 떠나지 않음) 관전자가 아닌(실제로 경주에 참여할 예정임) 플레이어를 반환할 수 있습니다.
# Get all players that are able to race.
GetAllValidPlayers(Players:[]player):[]player=
# Valid players are ones that are active and not spectating.
for:
Player : Players
Player.IsActive[]
not Player.IsSpectator[]
do:
Player이렇게 반환된 결과로, 프로젝트는 starting_game_sequence 장치를 사용하여 첫 번째 라운드에서 순위표 대기실을 구성한 다음, 경주 시작 전에 선수들에게 시작 위치와 탈것을 할당합니다.
# This file handles the logic for the pregame lobby and the cinematics that play at the beginning of a race.
# It controls the length of the starting lineup based on the number of players, and plays an intro for each
# player by displaying their stats.
using { /Fortnite.com/Characters }
using { /Fortnite.com/Devices }
using { /Fortnite.com/FortPlayerUtilities }
using { /Verse.org/Native }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }
플레이어 통계가 포함된 출발선 시네마틱
포크리 스피드웨이 경주 디자인하기 템플릿의 오리지널 버전은 파동 트리거 장치를 사용하여 경주에 제자리-준비-출발 도입 부분을 구성했습니다. 파동 트리거 장치는 트리거를 활성화하여 텍스트를 표시하고 출발선에서 라이트를 활성화하는 방식으로 정해진 시간 동안 일련의 이벤트를 재생했습니다.
변환된 템플릿에서는 파동 트리거 장치를 UEFN의 시네마틱 시퀀스 장치로 대체하여 그랜드 오프닝 느낌의 시네마틱을 완성했습니다. 시퀀서를 사용하여 다양한 카메라, 헤드업 디스플레이(HUD) 엘리먼트 및 활성 플레이어의 수에 따라 조정되는 다이내믹 라인업 뷰를 추가할 수 있습니다. 이전에 파동 트리거 장치를 설정한 방식과 마찬가지로 레벨 시퀀스가 중요한 순간에 장치를 활성화하고, 그러면 다음 플레이어의 점수를 표시할 시점이나 인트로에서 전환할 시점을 결정할 수 있습니다.
자세히 살펴보면, 레벨 시퀀스는 플레이어 인트로가 시작될 때마다 StartPlayerIntroEvent로 명명된 트리거 장치를 활성화하고, 플레이어 인트로가 끝날 때마다 EndPlayerIntroEvent로 명명된 트리거 장치를 활성화합니다. Verse 코드는 이 정보를 사용하여 이미 표시된 플레이어 인트로 수를 확인하고, 그 수가 게임 내 플레이어 수와 동일한 경우 시네마틱 재생을 중지합니다. 이는 race 표현식이므로, 시네마틱이 먼저 완료되면 플레이어 인트로 대기 작업도 취소합니다.
Verse 코드가 각 플레이어에 대해 WaitForPlayerIntro()를 호출하고, 이는 다시 각 플레이어에 대해 루프를 시작합니다. 그러면 플레이어의 시작 위치 순서에 따라 StartPlayerIntroEvent 트리거 장치가 활성화되기를 기다리고 HUD에서 플레이어의 통계를 표시할 시점을 파악합니다. 이러한 각 WaitForPlayerIntro() 루프는 ArraySync() 함수에서 호출되며, 이는 분할 정복 동시성 알고리즘을 사용하여 여러 비동기 함수 및 배열 엘리먼트에서 sync를 진행합니다.
# A Verse-authored creative device that can be placed in a level
starting_game_sequence := class(creative_device):
# The cinematic that intros the players and their stats.
@editable
StartingLineupCinematic:cinematic_sequence_device = cinematic_sequence_device{}
# The cinematic that we cut to after the lineup and before the race starts.
@editable
RaceStartCinematic:cinematic_sequence_device = cinematic_sequence_device{}
프로젝트에는 팝업 대화창 장치를 사용하여 위젯 에디터의 위젯을 디자인하고 Verse를 사용하여 정보를 대체합니다. 팝업 대화창 장치의 버튼에 텍스트를 설정하여 이를 수행합니다.
# Updates the Popup UI to display the lifetime stats of the given player during the
# race starting sequence.
UpdatePopupUI<public>(Player:agent, PopupDialogUI:popup_dialog_device):void=
if:
CurrentPlayerStats := GetPlayerStats[Player]
then:
PopupDialogUI.SetButtonText(PlayerText(Player), 0)
PopupDialogUI.SetButtonText(PointsText(CurrentPlayerStats.Points), 1)
PopupDialogUI.SetButtonText(PodiumsText(CurrentPlayerStats.Podiums), 2)
BestLapText:message = if(IsValidBestLapTime[CurrentPlayerStats.BestLapTime]):
Level Design
이 업데이트에서는 랜드스케이프 모드를 사용하여 오프로드 트랙을 만들었습니다. 에셋을 적게 사용하여 메모리 사용을 줄였고, 현재 트랙을 둘러싸고 있는 산에 깊이감을 더했습니다. 또한 워터 볼륨과 폭포를 사용하여 새로운 타입의 지형을 만들어 경주 트랙에서 다음 부분으로 시선이 집중되도록 했습니다.
오리지널 프로젝트의 기존 낮/밤 주기에서 고급 포트나이트 챕터 4 라이팅으로 업그레이드하기도 했습니다. 이러한 새로운 주기에서 루멘을 사용할 수 있게 되면서, 더 부드러운 섀도와 사실적인 글로벌 일루미네이션을 연출할 수 있습니다.
오리지널 경주 트랙 템플릿에 120개가 넘는 장벽이 있다는 것을 알고 계셨나요? 장벽은 플레이어를 트랙에 유지하고 자동차가 경계를 벗어나지 않도록 하는 데 사용됩니다. 이 업데이트에서는 장벽이 경주가 시작되기 전에 플레이어를 제자리에 머물게 하는 데만 사용되며, 트랙 주변에는 사용되지 않았다는 것을 알 수 있습니다. 대신 다음과 같이 경주 체크포인트, 수집품 및 몇 가지 환경 에셋을 사용하여 플레이어가 트랙을 벗어나지 않도록 유도했습니다.
부스트용 코인: 플레이어가 트랙을 벗어나지 않고 가장 효율적으로 완주하도록 유도하기 위해, 각 연속 코인의 마지막 코인 아래 속도 부스트 패드를 추가하는 것이 좋습니다. 코인은 랩마다 재생성되므로 플레이어가 처음에 코인을 지나치지 못한 경우 다시 지나칠 수 있습니다.
플레이어가 트랙을 벗어나지 않도록 하는 비주얼 디자인: 의도된 트랙의 연결을 강조하기 위해 트랙 곳곳에 짧은 흰색 장벽을 사용했습니다. 트랙은 몇 대의 자동차가 나란히 달릴 수 있을 정도로 충분히 넓게 디자인되었습니다. 나무, RV, 기타 디자인 등 추가 장식과 사물을 배치하여 플레이어의 탈것이 막히지 않고 쉽게 길을 찾을 수 있도록 하는 한편, 의도치 않은 경로를 가는 걸 방지하도록 했습니다.
지름길 및 점프: 오리지널 맵은 단순한 8자 모양이었는데, 플레이테스트를 통해 플레이어가 점프를 사용해 지름길을 택하는 걸 좋아한다는 걸 알게 되었습니다. 새로운 디자인에서는 플레이어가 맵을 원하는 방식으로 완주할 수 있도록 몇 가지 지름길과 점프를 추가했습니다.
마지막에는 의도적으로 배치된 경주 체크포인트가 있는데, 완주하기 위해서는 이를 지나쳐야 하므로 플레이어가 트랙을 따라 달려야 하는 마지막 길이 됩니다.