이 튜토리얼은 퍼시스턴스 플레이어 통계에 있는 개념을 바탕으로 하므로, 해당 문서를 먼저 확인해 보세요.
순위표는 경쟁 게임에서 플레이어가 자신의 실력을 뽐내고 이름을 알릴 수 있도록 하기 위한 필수 요소입니다. 순위표는 플레이어의 게임 진행 감각을 발전시키고, 플레이어가 자신이 상위에 오른 모습을 볼 수 있도록 계속해서 게임으로 돌아오게끔 독려합니다.
Verse 퍼시스턴스는 크리에이터가 이러한 순위표를 제작하여 경험에 경쟁력을 더할 수 있는 툴을 제공합니다. 이미 퍼시스턴스 플레이어 통계 튜토리얼에서 플레이 세션 간에 퍼시스턴스 데이터를 추적할 수 있는 방법, 그리고 다양한 이벤트에 따라 해당 데이터를 수정 및 업데이트하는 방법을 확인했습니다. 이제 이 지식을 적용하여 완전한 로컬 순위표를 제작하고, 플레이어 통계를 정렬하고, 레이싱 게임에서 이와 같은 요소를 모두 결합하는 방법을 알아보겠습니다!
사용된 Verse 언어 기능
클래스: 이 예시에서는 플레이어별로 통계 그룹을 추적하는 퍼시스턴스 Verse 클래스를 생성합니다.
생성자: 생성자는 관련 클래스의 인스턴스를 생성하는 특수 함수입니다.
weak_map: weak_map은 반복작업할 수 없는 단순한 맵입니다. Verse 퍼시스턴스 데이터는 weak_map에 저장되어야 합니다.
레벨 구성하기
이 예시에서는 다음과 같은 사물과 장치를 사용합니다.
게시판 장치(3): 게시판 장치는 각 플레이어가 지금까지 기록한 통계를 표시하며, 통계를 지금까지 기록한 포인트를 기준으로 정렬하여 대기실에 최상위 플레이어를 표시합니다.
플레이어 레퍼런스 장치(3): 게시판 장치와 함께 사용되는 플레이어 레퍼런스 장치는 최상위 플레이어의 이름과 얼굴을 표시하여 다른 플레이어에게 게임 중에 조심해야 할 사람을 알려줍니다.
체크포인트 장치(3): 체크포인트 장치는 플레이어가 완주하기 위해 통과하는 체크포인트입니다.
경주 관리 장치(1): 경주 관리 장치는 플레이어가 경주를 시작 및 종료하는 시점을 추적하고, 완주 등수에 따라 플레이어에게 포인트를 지급합니다.
픽업 트럭 생성 장치(1): 픽업 트럭 생성 장치는 경주 중에 사용할 탈것을 생성하지만, 경험에 어울리는 다른 탈것으로 변경할 수 있습니다.
레벨을 구성하려면 다음 단계를 따릅니다.
게시판 및 플레이어 레퍼런스
플레이어 통계를 표시하려면 게시판과 플레이어 레퍼런스를 함께 사용합니다. 각 게시판은 플레이어가 지금까지 기록한 통계를 표시하는 반면, 플레이어 레퍼런스는 해당 플레이어의 시각적 표현을 표시합니다. 이러한 엘리먼트를 추가하려면 다음 단계를 따릅니다.
레벨에 3개의 플레이어 레퍼런스(Player Reference) 장치를 추가하고, 서로 옆에 배치합니다.
각 플레이어 레퍼런스는 아웃라이너(Outliner)에서 선택합니다. 디테일(Details) 패널의 사용자 옵션(User Options)에서 커스텀 색상(Custom Color)을 대기실에서 가장 우수한 성적을 보여준 플레이어 1위, 2위, 3위를 나타낼 색상으로 설정합니다. 이 예시에서는 골드, 실버, 브론즈 컬러를 사용합니다.
레벨에 3개의 게시판(Billboard) 장치를 추가하고, 각 플레이어 레퍼런스 앞에 하나씩 배치합니다. 이러한 게시판 장치는 게임이 시작되면 Verse를 사용하여 각 플레이어의 통계로 업데이트됩니다.
체크포인트, 픽업 트럭, 경주 관리 장치
경주에는 경주할 수단이 필요하며, 통과할 체크포인트와 게임 중에 경주를 안내할 경주 관리 장치도 필요합니다. 이러한 엘리먼트를 추가하려면 다음 단계를 따릅니다.
레벨에 3개의 경주 체크포인트(Race Checkpoint) 장치를 추가합니다. 경주 체크포인트 장치를 플레이어가 통과할 순서대로 배치합니다. 아웃라이너에서 각 체크포인트의 체크포인트 번호(Checkpoint Number)는 플레이어가 체크포인트를 통과하는 순서와 일치해야 합니다.
레벨에 1개의 경주 관리 장치(Race Manager)를 추가합니다. 이 장치는 경주를 실행하고 플레이어가 체크포인트를 향하도록 처리합니다. 나중에 이 장치에서
RaceCompletedEvent()를 수신하여 플레이어의 완주 시점을 알게 됩니다.레벨에 1개의 픽업 트럭 생성 장치(Pickup Truck Spawner)를 추가합니다. 탈것은 선택 사항이지만, 이 가이드에서는 스피드웨이 템플릿에 어울리면서도 플레이어가 운전할 수단을 제공하기 위해 픽업 트럭을 사용합니다.
통계 테이블 수정하기
이 예시에서는 퍼시스턴스 플레이어 통계에서 player_stats_table 파일의 수정된 버전을 사용합니다. 이 버전은 해당 예시의 파일과 비슷해 보이지만, 구현을 변경하는 몇 가지 중요한 차이점이 있습니다.
플레이어 통계 테이블을 생성하려면 아래 단계를 따릅니다.
player_stats_table클래스에서 다음 작업을 수행합니다.Losses통계를 제거합니다.Score통계를Points로 변경합니다.Verse# Tracks different persistable stats for each player. player_stats_table<public>:= class<final><persistable>: # The version of the current stats table. Version<public>:int = 0 # The Points of a player. Points<public>:int = 0 # The number of Wins for a player.
파일의
MakePlayerStatsTable()생성자 함수가 업데이트된 통계를 반영하도록 수정합니다.Verse# Creates a new player_stats_table with the same values as the previous player_stats_table. MakePlayerStatsTable<constructor>(OldTable:player_stats_table)<transacts> := player_stats_table: Version := OldTable.Version Points := OldTable.Points Wins := OldTable.Winsplayer_stats_table.verse 파일에 새 구조체
player_and_stats를 추가합니다. 이 구조체에는player및 해당 플레이어의player_stats_table클래스에 대한 레퍼런스가 포함되어 있으며, 그 목적은 함수에서 두 데이터를 반복해서 얻을 필요 없이 사용하기 위해서입니다. 완성된player_and_stats구조체는 다음과 같습니다.Verse# Structure for passing a player and their stats as arguments. player_and_stats<public> := struct: Player<public>:player StatsTable<public>:player_stats_table
통계 관리하기
퍼시스턴스 플레이어 통계에서처럼, 매니저 파일을 사용하여 플레이어의 통계 변경 사항 관리 및 기록을 처리합니다.
수정된 player_stats_manager 파일을 빌드하려면 아래 단계를 따릅니다.
InitializeAllPlayers()및InitializePlayer()의 함수 시그니처를InitializeAllPlayerStats()및InitializePlayerStat()으로 수정합니다. 이러한 이름으로GetPlayerStat()함수와의 관계가 보다 잘 반영됩니다. 업데이트된 함수는 다음과 같습니다.Verse# Initialize stats for all current players. InitializeAllPlayerStats<public>(Players:[]player):void = for (Player : Players): InitializePlayerStat(Player) # Initialize stats for the given player. InitializePlayerStat<public>(Player:player):void= if: not PlayerStatsMap[Player] set PlayerStatsMap[Player] = player_stats_table{}AddScore()의 함수 시그니처를AddPoints()로 수정합니다. 그런 다음player_stats_table에 더 이상 해당 값이 포함되지 않으므로AddLosses()함수를 제거합니다. 완성된player_stats_manager파일은 다음과 같습니다.Verse# This file handles the code for initializing, updating, and returning player_stats_tables # for each player. It also defines an abstract stat_type class to use for updating stats, and the # StatType module to use when displaying stats. using { /Fortnite.com/Devices } using { /Verse.org/Simulation } using { /UnrealEngine.com/Temporary/Diagnostics } # Return the player_stats_table for the provided Agent. GetPlayerStats<public>(Agent:agent)<decides><transacts>:player_stats_table=
플레이어 순위표 제작하기
순위표에 플레이어 데이터를 표시하려면 몇 가지 사항이 필요합니다. 게시판의 텍스트와 플레이어 레퍼런스 장치의 플레이어를 업데이트할 방법이 있어야 합니다. 또한 최상위 플레이어들이 순위표에서 가장 눈에 띄어야 하므로 이러한 장치를 정렬할 방법도 필요합니다. 이러한 함수는 레벨 내 장치를 수정하는 것과 목표가 유사하므로 공통 파일에서 함수를 그룹화하는 것이 좋습니다.
레벨 내 장치를 업데이트하는 함수를 생성하려면 아래 단계를 따릅니다.
player_leaderboards.verse로 명명한 새 Verse 파일을 생성합니다. 이 파일은 레벨 내 순위표 업데이트에 공통으로 사용되는 함수를 저장합니다.
게시판의 텍스트에는 실행인자를 전달할 수 있는 메시지를 사용합니다. 모든
message타입, 즉CurrentPlayer,Points,Wins를 받아 결합된 텍스트를message로 반환하는 새 메시지를 생성하여StatsMessage로 명명합니다.Verse# The message to display on the stats billboard. StatsMessage<localizes>(CurrentPlayer:message, Points:message, Wins:message):message= "{CurrentPlayer}:\n{Points}\n{Wins}"StatsMessage의 각 입력에 하나씩,message변수를 3개 더 추가합니다.PlayerText메시지는Agent,PointsText메시지는 해당 에이전트의 포인트,WinsText메시지는 해당 에이전트의 승리 횟수를 받습니다.StatsMessage는 이 모든 데이터에서 메시지를 빌드하여 레벨에 메시지를 명확하게 표시합니다.Verse# The message to display on the stats billboard. StatsMessage<localizes>(CurrentPlayer:message, Points:message, Wins:message):message= "{CurrentPlayer}:\n{Points}\n{Wins}" PlayerText<localizes>(CurrentPlayer:agent):message = "Player {CurrentPlayer}" PointsText<localizes>(Points:int):message = "Total Points {Points}" WinsText<localizes>(Wins:int):message = "{Wins} Total Wins"게시판을 업데이트하려면 퍼시스턴스 플레이어 통계 튜토리얼에서
UpdateStatsBillboard()함수를 호출합니다. 이 함수는 Verse 장치와는 분리된 별도 파일에서 정의되므로,StatsBillboard를 부가적인 실행인자로 추가하여 어떤 게시판을 업데이트할지 지정해야 합니다.Verse# Updates the given billboard device to display the stats of the given player. UpdateStatsBillboard<public>(Player:agent, StatsBillboard:billboard_device):void=먼저
GetPlayerStats[]를 사용하여 실행인자로 전달된 플레이어의 통계를 구합니다.player_stats_manager는 더 이상 별도의 클래스가 아니므로 이에 대한 레퍼런스는 필요하지 않습니다. 그런 다음 플레이어 및 해당 플레이어의CurrentPlayerStats에서 가져온Points및Wins를 사용하여 새StatsMessage를 생성합니다. 마지막으로StatsBillboard에서SetText()를 호출하여 레벨 내 게시판 텍스트를 업데이트합니다. 완성된UpdateStatsBillboard()함수는 다음과 같습니다.Verse# Updates the given billboard device to display the stats of the given player. UpdateStatsBillboard<public>(Player:agent, StatsBillboard:billboard_device):void= if: CurrentPlayerStats := GetPlayerStats[Player] then: PlayerStatsText := StatsMessage( PlayerText(Player), PointsText(CurrentPlayerStats.Points), WinsText(CurrentPlayerStats.Wins)) StatsBillboard.SetText(PlayerStatsText)
최상위 플레이어 정렬 및 표시하기
계속 진행하기에 앞서 이러한 게시판을 정렬할 방법을 고려하는 것이 중요합니다. 포인트가 가장 많은 플레이어가 상단에 위치하도록 할지, 또는 가장 많이 승리한 플레이어가 상단에 위치하도록 할지 생각해 보아야 합니다. 다양한 통계에 따라 정렬할 수도 있습니다. 이를 모두 처리할 방법이 필요하다면 정렬 알고리즘이 그 해답입니다. 정렬 알고리즘과 비교 함수를 사용하여 정렬 기준을 지정할 수 있습니다. 그런 다음 게시판 및 플레이어 레퍼런스를 정렬하여 경험에 최상위 플레이어들을 표시할 수 있습니다. 이 예시에서는 병합 정렬 알고리즘을 사용하지만, 자신만의 알고리즘을 구현해도 됩니다.
게시판에 비교 및 정렬을 추가하고 레벨의 장치 업데이트를 마치려면 아래 단계를 따릅니다.
player_stats_table파일로 돌아와 각 통계의 비교 함수를 정의합니다. 각 함수는Left및Rightplayer_and_stats구조체를 받아 특정 통계를 기준으로 비교합니다. 이러한 함수에는<decides><transacts>모디파이어가 있으므로, 비교에 실패하면 함수도 실패합니다. 예를 들면Left가Right보다 적음을 알리는 경우 실패합니다. player_stats_table.verse 파일에MorePointsComparison()으로 명명된 새 함수를 추가합니다. 이 함수는Left.Points가Right.Points보다 큰지 확인하며, 크지 않으면 실패합니다. 성공하는 경우Left를 반환합니다.Verse# Returns Left if Left has greater Points than Right. MorePointsComparison<public>(Left:player_and_stats, Right:player_and_stats)<decides><transacts>:Left= Left.StatsTable.Points > Right.StatsTable.Points Left이 함수를 3번 복사합니다. 하나는 더 적은 포인트 비교용, 둘은 승리 횟수 비교용입니다. 비교 함수는 다음과 같습니다.
Verse# Returns Left if Left has greater Points than Right. MorePointsComparison<public>(Left:player_and_stats, Right:player_and_stats)<decides><transacts>:player_and_stats= Left.StatsTable.Points > Right.StatsTable.Points Left # Returns Left if Left has less Points than Right. LessPointsComparison<public>(Left:player_and_stats, Right:player_and_stats)<decides><transacts>:player_and_stats= Left.StatsTable.Points < Right.StatsTable.Points Left병합 정렬 알고리즘을 추가합니다. 이 알고리즘을 별도의 파일 또는 모듈에 배치하여 제공된 테스트 파일에서 알고리즘을 테스트할 수 있습니다.
player_leaderboards로 돌아와 새 함수UpdateStatsBillboards()를 추가합니다. 이 함수는 에이전트 배열 및 게시판 배열을 받아 정렬하고UpdateStatsBillboard()를 호출하여 레벨의 각 게시판을 업데이트합니다.Verse# Update the stats billboards by sorting them based on the amount of lifetime points # each player has. UpdateStatsBillboards<public>(Players:[]agent, StatsBillboards:[]billboard_device):void=UpdateStatsBillboards()에서PlayerAndStatsArray로 명명된player_and_stats의 새 배열 변수를 초기화합니다. 이 값을for표현식의 결과와 동일하게 설정합니다. 해당for표현식의 각agent에서 해당agent의player를 구하고GetPlayerStats[]를 사용하여player_stats_table을 얻습니다. 그런 다음player및 플레이어의 통계 테이블에서 생성된player_and_stats구조체를 반환합니다.VerseUpdateStatsBillboards<public>(Players:[]agent, StatsBillboards:[]billboard_device):void= var PlayerAndStatsArray:[]player_and_stats = for: Agent:Players Player := player[Agent] PlayerStats := GetPlayerStats[Player] do: player_and_stats: Player := Player StatsTable := PlayerStatsPlayerAndStatsArray를 정렬하려면 새 변수SortedPlayersAndStats를MergeSort()호출 결과로 초기화하여 배열 및MorePointsComparison을 전달합니다.for표현식에서 정렬한 후SortedPlayerAndStats에서 각 엘리먼트를 반복작업하여 변수PlayerIndex에 엘리먼트 인덱스를 저장합니다.PlayerIndex를 사용하여StatsBillboards배열에 인덱싱한 다음, 플레이어 및 업데이트할 게시판을 전달하는UpdateStatsBillboard를 호출합니다. 완성된UpdateStatsBillboards()함수는 다음과 같습니다.Verse# Update the stats billboards by sorting them based on the amount of lifetime points # each player has. UpdateStatsBillboards<public>(Players:[]agent, StatsBillboards:[]billboard_device):void= var PlayerAndStatsArray:[]player_and_stats = for: Agent:Players Player := player[Agent] PlayerStats := GetPlayerStats[Player] do: player_and_stats:플레이어 레퍼런스를 업데이트하기 위해
UpdatePlayerReferences()로 명명된 매우 유사한 함수를 사용합니다. 이 함수는 게시판 대신player_reference_device배열을 받으며, 끝에서UpdateStatsBillboard()를 호출하는 대신 각 플레이어의 플레이어 레퍼런스 장치에서Register()를 호출합니다.UpdateStatsBillboard()코드를 위 변경사항이 적용된 새 함수UpdatePlayerReferences()에 복사합니다. 완성된UpdatePlayerReferences()함수는 다음과 같습니다.Verse# Update the player references devices by sorting them based on the amount # of lifetime points each player has. UpdatePlayerReferences<public>(Players:[]player, PlayerReferences:[]player_reference_device):void= var PlayerAndStatsArray:[]player_and_stats = for: Agent:Players Player := player[Agent] PlayerStats := GetPlayerStats[Player] do: player_and_stats:
레벨의 플레이어 순위표
모든 요소가 구성되었으니, 이제 플레이어들을 보여줄 차례입니다! 플레이어가 버튼과 상호작용하면 포인트를 지급하는 장치를 생성하고, 최상위 플레이어가 맨 앞 중앙에 오도록 플레이어 레퍼런스 및 게시판을 정렬합니다. 레벨의 순위표를 테스트하는 Verse 장치를 만들려면 아래 단계를 따릅니다.
player_leaderboards_example로 명명한 새 Verse 장치를 생성합니다. 단계별 과정은 Verse를 사용하여 나만의 장치 만들기를 참고하세요.
player_leaderboards_example클래스 정의 상단에 다음 필드를 추가합니다.PlayerReferences로 명명된 플레이어 레퍼런스 장치의 편집 가능 배열로, 경주에서 각 플레이어의 시각적 표현을 제공합니다.Verse# Visual representations of each player. @editable PlayerReferences:[]player_reference_device = array{}Leaderboards로 명명된 게시판 장치의 편집 가능 배열로, 레벨 내 게시판에 각 플레이어의 통계를 표시합니다.Verse# Billboards that display each player's stats. @editable Leaderboards:[]billboard_device = array{}RaceManager로 명명된 편집 가능 경주 관리 장치로, 플레이어가 완주하는 시점을 알기 위해 경주 관리 장치의 이벤트에 등록합니다.Verse# Tracks when players complete a race, with the players in the first spot being awarded a win. @editable RaceManager:race_manager_device = race_manager_device{}PlacementRequiredForWin으로 명명된 편집 가능 인티저로, 플레이어가 승리를 부여받기 위해 차지해야 하는 등수입니다.Verse# The placement of a player must be at or below to award a win. @editable PlacementRequiredForWin:int = 1PointsPerPlace로 명명된 인티저의 편집 가능 배열로, 각 플레이어가 등수에 따라 획득한 포인트입니다.Verse# The number of points a player in each place earns. # Adjust this to award your players the desired amount of score # based on their placement. @editable PointsPerPlace:[]int = array{5, 3, 1}CurrentFinishOrder로 명명된 인티저 변수로, 가장 최근에 완주한 플레이어의 등수입니다.Verse# The spot of the player who just finished the race. # The first three players to finish the race will be awarded a win. var CurrentFinishOrder:int = 0
등수에 따라 통계 부여하기
플레이어가 완주하면 등수에 따라 플레이어의 통계를 업데이트해야 합니다. 높은 순위를 차지한 플레이어는 더 많은 포인트를 받고, 1등을 차지한 플레이어는 승리를 획득해야 합니다.
플레이어가 완주했을 때 플레이어에게 통계를 부여하려면 다음 단계를 따릅니다.
이를 처리하려면 새 함수
RecordPlayerFinish()를player_leaderboards_example클래스 정의에 추가합니다. 이 함수는 플레이어를 받아 통계를 파라미터로 부여합니다.Verse# When a player finishes the race, award them points based on their placement, and award them a win if # their placement was better than the PlacementRequiredForWin. RecordPlayerFinish(Player:agent):void=RecordPlayerFinish()에서PlayerFinishOrder로 명명된 새int의CurrentFinishOrder현재 값을 구해 이 플레이어의 등수를 구합니다. 그리고 완주한 다음 플레이어가 동일한 등수로 완주하지 않도록CurrentFinishOrder를 증분합니다.VerseRecordPlayerFinish(Player:agent):void= PlayerFinishOrder:int = CurrentFinishOrder set CurrentFinishOrder += 1이제 통계를 부여할 차례입니다. 이 플레이어에게 포인트를 얼마나 지급할지 알기 위해
if표현식에서PlayerFinishOrder를 사용하여PointsPerPlace배열에 인덱싱합니다. 그런 다음AddPoints()를 호출하여 해당 플레이어에게 그만큼의 포인트를 지급합니다.Verseset CurrentFinishOrder += 1 if: PointsToAward := PointsPerPlace[PlayerFinishOrder] then: AddPoints(Player, PointsToAward)플레이어의 등수가 승리를 얻을 만큼 높은 경우 해당 플레이어의 통계 테이블에 승리를 기록해야 합니다. 다른
if표현식에서PlayerFinishOrder가PlacementRequiredToWin미만인지 확인합니다. 미만인 경우AddWin()을 호출하여 플레이어 및 플레이어에게 부여할 승리를 전달합니다. 완성된RecordPlayerFinish()함수는 다음과 같습니다.Verse# When a player finishes the race, award them points based on their placement, and award them a win if # their placement was better than the PlacementRequiredForWin. RecordPlayerFinish(Player:agent):void= PlayerFinishOrder:int = CurrentFinishOrder set CurrentFinishOrder += 1 if: PointsToAward := PointsPerPlace[PlayerFinishOrder] then: AddPoints(Player, PointsToAward)
플레이어의 완주 기다리기
이제 통계 기록이 준비되었으니, 플레이어가 완주하여 통계를 업데이트하는 시점을 알아야 합니다. 이를 위해 경주 관리 장치의 RaceCompletedEvent()를 수신합니다. 이 이벤트는 플레이어가 완주할 때마다 발동하므로, 비동기화 함수에서 계속 수신해야 합니다.
새 함수
WaitForPlayerToFinishRace()를player_leaderboards_example클래스 정의에 추가합니다. 이 함수는 플레이어를 받고 해당 플레이어가 완주하기를 기다립니다.Verse# When a player finishes the race, record a finish in their stats table. WaitForPlayerToFinishRace(Player:agent)<suspends>:void=WaitForPlayerToFinishRace()의race표현식에서 두 번의 루프를 시작합니다. 첫 번째 루프는 플레이어가 완주하기를 기다리고, 두 번째 루프는 플레이어가 완주 전에 세션을 떠나면 발생하는 일을 처리합니다. 플레이어가 떠났을 때 루프가 영구적으로 실행되지 않으려면, 이러한 상황에서 루프를 중단할 방법이 필요합니다.Verse# When a player finishes the race, record a finish in their stats table. WaitForPlayerToFinishRace(Player:agent)<suspends>:void= race: # Waiting for this player to finish the race and then record the finish. loop: # Waiting for this player to leave the game. loop:첫 번째 루프에서
RaceManager.RaceCompletedEvent를 대기하고FinishingPlayer로 명명된 변수에 결과를 저장합니다. 이 이벤트는 플레이어가 완주할 때마다 발동하므로, 저장한 플레이어가 모니터링하던 플레이어인지 확인해야 합니다.FinishingPlayer를 이 루프가 모니터링하는 플레이어와 비교합니다. 두 플레이어가 같은 경우 해당 플레이어를RecordPlayerFinish()에 전달하고 루프를 중단합니다.Verse# Waiting for this player to finish the race and then record the finish. loop: FinishingPlayer := RaceManager.RaceCompletedEvent.Await() if: FinishingPlayer = Player then: RecordPlayerFinish(Player) break두 번째 루프에서 플레이스페이스 이벤트인
PlayerRemovedEvent()를 대기합니다. 전과 마찬가지로, 방금 떠난 플레이어를 구해 변수LeavingPlayer에 저장합니다. 방금 떠난 플레이어가 이 루프에서 기다리던 플레이어인 경우, 루프를 중단합니다. 완성된WaitForPlayerToFinishRace()함수는 다음과 같습니다.Verse# When a player finishes the race, record a finish in their stats table. WaitForPlayerToFinishRace(Player:agent)<suspends>:void= race: # Waiting for this player to finish the race and then record the finish. loop: FinishingPlayer := RaceManager.RaceCompletedEvent.Await() if: FinishingPlayer = Player then: RecordPlayerFinish(Player)
모든 요소 연결하기
함수가 구성되었으니, 이제 장치에 연결하여 경주를 시작할 차례입니다!
로직을 장치에 연결하려면 다음 단계를 따릅니다.
OnBegin()에서GetPlayers()를 사용하여 플레이스페이스의 모든 플레이어를 구합니다. 이 배열을InitializeAllPlayerStats()에 전달하여 각 플레이어의player_stats_tables를 구성합니다.Verse# Runs when the device is started in a running game OnBegin<override>()<suspends>:void= # Get the players in the current race and create a player_stat_table # for each of them. Players := GetPlayspace().GetPlayers() InitializeAllPlayerStats(Players)UpdateStatsBillboards()를 호출하고Players및Leaderboards배열을 전달하여 레벨 내 게시판을 각 플레이어의 현재 데이터로 업데이트합니다. 그런 다음UpdatePlayerReferences()를 호출하여 레벨 내 레퍼런스가 플레이어와 일치하도록 업데이트합니다. 마지막으로for표현식에서 각 플레이어의WaitForPlayerToFinishRace()함수를 생성합니다. 완성된OnBegin()함수는 다음과 같습니다.Verse# Runs when the device is started in a running game OnBegin<override>()<suspends>:void= # Get the players in the current race and create a player_stat_table # for each of them. Players := GetPlayspace().GetPlayers() InitializeAllPlayerStats(Players) UpdateStatsBillboards(Players, Leaderboards) UpdatePlayerReferences(Players, PlayerReferences) # Wait for all players to finish the race.코드를 저장하고 컴파일합니다.
player_leaderboards_example 장치를 레벨로 드래그합니다. 플레이어 레퍼런스를 PlayerReferences 배열에 할당하여 순서를 기록합니다. 첫 번째 인덱스의 장치는 1위 플레이어의 플레이어 레퍼런스에 해당하고, 두 번째 인덱스는 2위 플레이어에 해당하는 식이어야 합니다. 순위표에도 동일한 작업을 수행하여 플레이어 레퍼런스 장치와 정렬된 상태를 유지해야 합니다. 경주 관리 장치도 할당해야 합니다!
퍼시스턴스 순위표 테스트하기
편집 세션에서 퍼시스턴스 데이터를 테스트할 수 있지만, 이 데이터는 세션을 종료하고 재시작하면 리셋됩니다. 데이터가 여러 세션에 걸쳐 유지되도록 하려면 플레이테스트 세션을 시작하고 섬 설정에서 특정 설정을 변경해야 합니다. 편집 세션과 플레이테스트 세션 둘 모두에서 퍼시스턴스 데이터를 테스트하도록 섬을 구성하려면 퍼시스턴스 데이터로 테스트하기를 참고하여 섬 설정에서 특정 설정을 변경하세요. 편집 세션과 플레이테스트 세션 둘 모두에서 퍼시스턴스 데이터를 테스트하도록 섬을 구성하는 방법은 퍼시스턴스 데이터로 테스트하기를 참고하세요.
세션을 구성한 후 레벨을 플레이테스트할 때 완주한 플레이어에게 등수에 따른 포인트가 지급되어야 합니다. 플레이어의 등수가 충분히 높은 경우 승리를 부여해야 하며, 이러한 통계는 여러 플레이 세션에 걸쳐 유지되어야 합니다. 플레이어 및 플레이어 통계는 가장 많은 포인트를 보유한 플레이어가 첫 번째에 표시되도록 정렬해야 합니다.
직접 해보기
이 가이드를 완료함으로써 레벨에 퍼시스턴스 플레이어 통계를 표시하기 위한 순위표를 제작하는 방법을 배웠습니다. 또한 최상위 플레이어가 누구인지 모두가 알 수 있도록 이러한 순위표를 정렬 및 업데이트하는 방법도 배웠습니다. 이 튜토리얼을 나만의 경험에 적용하여 누가 최고 중의 최고인지 보여주세요!
완성된 코드
player_stats_table.verse
# This file defines a player_stats_table, a collection of persistable player statistics.
# It also contains functions to compare stats tables by each of the stats to order players
# when sorting.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }
# Structure for passing a player and their stats as arguments.
player_and_stats<public> := struct:
player_leaderboards.verse
# This file contains the code that updates the billboards, player references, and UI on the island
# to display a player's stats from their player stats table. It also handles adding wins and points to a
# player's stats table.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation}
# The message to display on the stats billboard.
StatsMessage<localizes>(CurrentPlayer:message, Points:message, Wins:message):message=
"{CurrentPlayer}:\n{Points}\n{Wins}"
player_stats_manager.verse
# This file handles the code for initializing, updating, and returning player_stats_tables
# for each player. It also defines an abstract stat_type class to use for updating stats, and the
# StatType module to use when displaying stats.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }
# Return the player_stats_table for the provided Agent.
GetPlayerStats<public>(Agent:agent)<decides><transacts>:player_stats_table=
player_leaderboards_example.verse
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }
using { PlayerLeaderboard }
# See https://dev.epicgames.com/documentation/en-us/uefn/create-your-own-device-in-verse for how to create a verse device.
# A Verse-authored creative device that can be placed in a level
player_leaderboards_example := class(creative_device):
# Visual representations of each player.