多くの体験では、プレイヤー統計データを使用してプレイヤーの体験データを時間経過とともに追跡しています。 ハイスコア、勝利した総ゲーム数、合計プレイ時間、回収したアイテム数などの統計データによって、進行状況の感覚がプレイヤーに与えられ、プレイヤーがその体験に戻るように仕向けるための素晴らしい方法です。
Verse の持続機能は、Verse スクリプトに持続可能データを付加できるようにする強力なツールです。 持続可能データはプレイヤーごとで島ごとに保存され、ゲームプレイ セッション間で同じ状態が保たれます。 持続可能データを使用すると、プレイセッション間でプレイヤーの進行状況を追跡できるようになり、以前の UEFN では利用できなかったユニークで興味を引くさまざまなプレイ体験を切り開くことができます。
このチュートリアルでは、Verse でプレイヤー統計データのカスタム テーブルを作成し、その統計データが複数のプレイ体験にわたって持続するようにセットアップする方法を示します。 このチュートリアルの終了後、永続性を使用してゲーム内リーダーボードを作成する方法については、「Verse で独自のゲーム内ランキングを作成する」を確認してください。
使用する Verse 言語機能
クラス:下記の例では、単一の統計データを管理する Verse クラス、および単一のプレイヤーの統計データのグループを追跡する持続可能クラスを作成します。
コンストラクタ:コンストラクタは、関連付けられているクラスのインスタンスを作成する特別な関数です。
Weak_map:weak_map は、反復処理できない単純なマップです。 Verse の持続データは weak_map に格納する必要があります。
レベルを設定する
この例では、次の小道具と仕掛けを使用しています。
ボタンの仕掛け x 2:プレイヤーが仕掛けとインタラクトすると、プレイヤーの現在のスコアにポイントが加算されます。 ボタンの仕掛けをもう一つ使用して、ゲームの終了をシミュレートし、現在のスコアに応じてプレイヤーの勝利数と敗北数を加算します。
ビルボードの仕掛け x 1:多くの場合、持続データをプレイヤーに見せることが重要です。 これはテスト用に使用されることもあれば、プレイヤーのエンゲージメントを高めるためや進行状況を示すために使用されることもあります。 データを表示するタイミングとどのデータを表示するかの要件は体験ごとに異なりますが、下記の例では、スコア、ハイスコア、勝利数、敗北数の統計データをビルボードの仕掛けに表示します。
持続型のプレイヤー統計データを追跡する
まず、どの統計データをプレイヤーごとに追跡するかを定義することが重要です。 たとえば、プレーヤーのこれまでのスコア、現在のランク、ラップのベストタイムを追跡したい場合があります。 この例では、各プレイヤーの統計値のテーブルでスコア、勝利数、敗北数を追跡します。 そうするために、新規クラス player_stats_table を作成し、これがメインの持続可能クラスになります。
以下の手順に従って、player_stats_table クラスを作成します。
Verse Explorer を使用して、
player_stats_table.verseという新規 Verse ファイルを作成します。その新規 Verse ファイル内で、
player_stats_tableという新規クラスを作成します。<persistable>と<final>モディファイアを両方ともクラスに追加します。<persistable>モディファイアは、クラス内データを持続できるようにします。持続可能データはオーバーライドもサブクラス化もできないため、<final>モディファイアが必要です。Verseusing { /Fortnite.com/Devices } using { /Verse.org/Simulation } using { /UnrealEngine.com/Temporary/Diagnostics } # Tracks different persistable stats for each player. player_stats_table := class<final><persistable>:player_stats_tableに、「Score」、「Wins」、「Losses」の 3 つのint値を追加します。 これらはそれぞれ、各プレイヤーの存続期間中のスコア、勝利数、敗北数を追跡します。 また、player_stats_tableの現在のバージョンを追跡するために、Versionというint変数を追加します。Verse# Tracks different persistable stats for each player. player_stats_table := class<final><persistable>: # The version of the current stats table. Version<public>:int = 0 # The score of a player. Score<public>:int = 0 # The number of wins for a player. Wins<public>:int = 0player_stats_tableクラスのインスタンスを作成するには、<constructor>関数を使用します。 Verse の持続機能では、持続可能になる変数フィールドをクラスに含めることが許可されていないため、このコンストラクタが必要です。 コンストラクタを使用すると、変数である既存の持続可能統計データのコピーを作成し、そのコピーを更新してから、クラスの元のインスタンスを変更後の値で置き換えることで、持続可能クラスの値を更新できるようになります。 新しいコンストラクタ関数MakePlayerStatsTable()をファイルに追加します。 このコンストラクタは、player_stats_tableクラスの元の (前の) インスタンスを受け取り、元の指定値から新しいテーブルを作成します。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 Score := OldTable.Score Wins := OldTable.Wins Losses := OldTable.Lossesplayer_stats_tablesのすべてを追跡するために、持続可能であるplayerのweak_mapをplayer_stats_tableインスタンスに使用します。 このウイーク マップをファイルに追加します。Verse# Maps players to a table of their player stats. var PlayerStatsMap:weak_map(player, player_stats_table) = map{}完成した
player_stats_tableクラスは次のようになります。Verseusing { /Fortnite.com/Devices } using { /Verse.org/Simulation } using { /UnrealEngine.com/Temporary/Diagnostics } # Tracks different persistable stats for each player. player_stats_table := class<final><persistable>: # The version of the current stats table. Version<public>:int = 0 # The score of a player.
全プレイヤーのプレイヤー統計データを管理する
player_stats_table クラスでは、個々のプレイヤーの統計データを追跡できますが、それらを管理する手段がまだありません。 各プレイヤーがスコアを獲得するごとに、そのプレイヤーの統計データ テーブルを更新する必要があり、ゲームの設計によっては多数のプレイヤーが同時にプレイする場合があります。
それを解決するために、もう一つのクラスを使用して、全プレイヤーの統計データを管理し、プレイヤーが勝利、敗北、スコアを獲得するごとに統計データの変化を記録します。 以下の手順に従って、マネージャー クラスをセットアップします。
Verse Explorer を使用して、
player_stats_managerという新規 Verse ファイルを作成します。 その新規ファイル内で、新規クラスplayer_stats_managerを作成します。Verseusing { /Fortnite.com/Devices } using { /Verse.org/Simulation } using { /UnrealEngine.com/Temporary/Diagnostics } # Manages and updates player_stat_tables for each player. player_stats_manager := class():player_stats_managerでは、いくつかのことを行う必要があります。 プレイヤーのplayer_stats_tableを設定し、プレイヤーごとのScore、Wins、Lossesを更新して、プレイヤーのplayer_stats_tableを返します。 これらのそれぞれを別の関数で処理します。 新しい関数「InitializePlayer()」をplayer_stats_managerクラス定義に追加します。 この関数は、指定されたプレイヤーの統計データを初期化します。Verse# Initialize stats for the given player. InitializePlayer(Player:player):void=InitializePlayer()内で、指定されたプレイヤーがPlayerStatsMap内にすでに存在するかどうかをチェックします。 存在しなければ、マップにあるそのプレイヤーの値を新しいplayer_stats_tableに設定します。 完成したInitializePlayer()関数は次のようになります。Verse# Initialize stats for the given player. InitializePlayer(Player:player):void= if: not PlayerStatsMap[Player] set PlayerStatsMap[Player] = player_stats_table{} else: Print("Unable to initialize player stats")新しい関数「
InitializeAllPlayers()」をplayer_stats_managerクラス定義に追加します。 この関数は、プレイヤーの配列を受け取り、その中のすべてのプレイヤーに対してInitializePlayer()を呼び出します。 完成したInitializeAllPlayers()関数は、次のようになっています。Verse# Initialize stats for all current players. InitializeAllPlayers(Players:[]player):void = for (Player : Players): InitializePlayer(Player)特定のプレイヤーの統計データを返すには、そのプレイヤーの
player_stats_tableを返す関数が必要です。 agent を引数に取る新しい関数GetPlayerStats()をplayer_stats_managerクラス定義に追加します。 さらに<decides><transacts>モディファイアを付加して、プレイヤーの統計データ テーブルが存在しない場合に、この関数が失敗してロールバックできるようにします。GetPlayerStats()で、新しいplayer_stats_table変数PlayerStatsを作成します。Verse# Return the player_stats_table for the provided Agent. GetPlayerStats(Agent:agent)<decides><transacts>:player_stats_table= var PlayerStats:player_stats_table = player_stats_table{}`if`式内で、この関数に渡されたAgentをPlayerにキャストし、そのプレイヤーのplayer_stats_tableをPlayerStatsMapから取得します。 そして、MakePlayerStatsTable()を呼び出して、PlayerStatsをそのテーブルに設定します。 最後に、PlayerStatsを返します。 完成したGetPlayerStats()関数は、次のようになっています。Verse# Return the player_stats_table for the provided Agent. GetPlayerStats(Agent:agent)<decides><transacts>:player_stats_table= var PlayerStats:player_stats_table = player_stats_table{} if: Player := player[Agent] PlayerStatsTable := PlayerStatsMap[Player] set PlayerStats = MakePlayerStatsTable(PlayerStatsTable) PlayerStatsスコア、勝利数、敗北数の各統計データを更新するには、統計データごとに関数を作成します。
player_stats_managerファイルに、新しい関数「AddScore()」を追加します。 この関数は、スコアを付与するエージェントと、付与するint数のポイントを受け取ります。Verse# Adds to the given Agent's score and updates both their stats table # in PlayerStatsManager and the billboard in the level. AddScore<public>(Agent:agent, NewScore:int):void=データを更新するには、持続可能な
weak_mapにそのプレイヤーの有効なデータがあることを確認してから、クラスの更新済みコピーでそのデータを置き換えます。 この処理をスコアに対して行うには、プレイヤーのスコアをPlayerStatsTableから取得し、MakePlayerStatsTable()を使用して新しいplayer_stats_tableを構築した結果にPlayerStatsMap内のテーブルを設定し、現在のスコアと新しいスコアを渡します。 複数のフィールドがあるクラスを操作する場合は、クラス コンストラクタを使用して、更新を行うたびにすべてのフィールドを明示的にコピーすることなく、1 つのフィールドを簡単に更新できます。AddScore()関数は次のようになります。Verse# Adds to the given Agent's score and updates both their stats table # in PlayerStatsManager and the billboard in the level. AddScore<public>(Agent:agent, NewScore:int):void= if: Player := player[Agent] PlayerStatsTable := PlayerStatsMap[Player] CurrentScore := PlayerStatsTable.Score set PlayerStatsMap[Player] = player_stats_table: MakePlayerStatsTable<constructor>(PlayerStatsTable) Score := CurrentScore + NewScoreこの処理を勝利数と敗北数に対しても繰り返し、
MakePlayerStatsTable()の呼び出し時に、プレイヤーの勝利数または敗北数にそれぞれNewWinsとNewLossesを加算します。Verse# Adds to the given Agent's wins and updates both their stats table # in PlayerStatsManager and the billboard in the level. AddWin<public>(Agent:agent, NewWins:int):void= if: Player := player[Agent] PlayerStatsTable := PlayerStatsMap[Player] CurrentWins := PlayerStatsTable.Wins set PlayerStatsMap[Player] = player_stats_table: MakePlayerStatsTable<constructor>(PlayerStatsTable) Wins := CurrentWins + NewWins最終的な
player_stats_managerファイルは、次のようになります。Verseusing { /Fortnite.com/Devices } using { /Verse.org/Simulation } using { /UnrealEngine.com/Temporary/Diagnostics } # Manages and updates player_stat_tables for each player. player_stats_manager := class(): # Return the player_stats_table for the provided Agent. GetPlayerStats(Agent:agent)<decides><transacts>:player_stats_table= var PlayerStats:player_stats_table = player_stats_table{}
持続機能を仕掛けでテストする
ここまでで持続クラスをセットアップしたので、それらをレベルでテストします。
「player_stats_example」という新しい Verse 仕掛けを作成します。 手順については、「Verse で新しい仕掛けを作成する」を参照してください。
player_stats_exampleクラス定義の先頭に、以下のフィールドを追加します。「
ScorePointsButton」という編集可能なbutton_device。 このボタンがアクティブ化されると、プレイヤーのスコアに加算されます。Verse# Adds to the activating player's score. @editable ScorePointsButton:button_device = button_device{}「
StatsBillboard」という編集可能なbillboard_device。 これはプレイヤーの Score、HighScore、Wins、Losses を表示します。Verse# Displays the player's Score, High Score, Wins, and Losses @editable StatsBillboard:billboard_device = billboard_device{}「
CheckWinButton」という編集可能な button_device。 このボタンは、各プレイヤーのスコアを設定し直し、プレイヤーのスコアに応じてプレイヤーに勝利または敗北を与えます。Verse# Resets the player's score and award them a win or a loss # depending if their current score is greater than WinScore. @editable CheckWinButton:button_device = button_device{}「
WinScore」という編集可能なint変数。CheckWinButtonがアクティブ化された後にこのスコアに達していれば、プレイヤーに勝利が与えられます。Verse# The score players need to reach to be awarded a win after # the CheckWinButton is activated. @editable WinScore:int = 10「
AwardScore」という編集可能なint変数。 これは、ボタンを操作したときにプレイヤーに付与されるスコアです。Verse# The amount of score to award per button press. @editable AwardScore:int = 1「
PlayerStatsManager」というplayer_stats_manager。 これは全プレイヤーの統計データを管理および更新します。Verse# Manages and updates stats for each player. PlayerStatsManager:player_stats_manager = player_stats_manager{}エージェントに 4 つの整数 Score、MaxScore、Wins、Losses を受け取る、StatsMessage というメッセージ。 このメッセージを使用して、プレイヤーの統計データをビルボードに表示します。
Verse# Displays a player's stats on a billboard. StatsMessage<localizes>(Player:agent, Score:int, Wins:int, Losses:int):message = "{Player}, Stats:\n Score: {Score}\n Wins: {Wins}\n Losses: {Losses}"
コードをコンパイルし、Verseで作成した仕掛けを自分の島までドラッグします。 手順については、「Verseの仕掛けをレベルに追加する」を参照してください。
仕掛けの [Details (詳細)] パネルで、レベルにあるボタンの仕掛けを ScorePointsButton に割り当て、ビルボードの仕掛けを StatsBillboard に割り当てます。
指定されたプレイヤーの統計データを StatsBillboard に表示するために、新しい関数
UpdateStatsBillboard()をplayer_stats_exampleクラス定義に追加します。 この関数は、受け取ったエージェントの統計データを表示します。Verse# Retrieves the stats of the given player and displays their stats # on the StatsBillboard. UpdateStatsBillboard(Agent:agent):void=UpdateStatsBillboard()内で、統計データ マネージャーのGetPlayerStats[]関数を呼び出して、指定されたエージェントの現在の統計データを取得します。 次に、新しいStatsMessage()を渡して、StatsBillboard でSetText()を呼び出します。 このStatsMessage()を構築するために、エージェントの現在の統計データからエージェントの Score、Wins、Losses にアクセスして、それらの値を取得します。 完成したUpdateStatsBillboard()関数は、次のようになります。Verse# Retrieves the stats of the given player and displays their stats # on the StatsBillboard. UpdateStatsBillboard(Agent:agent):void= if: # Get the current stats of the given agent. CurrentPlayerStats := PlayerStatsManager.GetPlayerStats[Agent] then: StatsBillboard.SetText( StatsMessage( Player := Agent,新しい関数
AddScore()をplayer_stats_exampleクラス定義に追加します。 この関数はエージェントを受け取り、ScorePointsButton とインタラクトするごとに、そのエージェントのスコアを加算します。Verse# Adds to the given player's score and updates both their stats table # in PlayerStatsManager and the billboard in the level. AddScore(Agent:agent):void=AddScore()内で、指定されたエージェントの現在の統計データと現在のスコアを取得します。 次に、PlayerStatsManagerからAddScore()を呼び出し、エージェントとAwardScoreを渡して新しいスコアを付与します。 最後に、指定されたエージェントを渡してUpdateStatsBillboard()を呼び出します。 完成したAddScore()関数は、次のようになります。Verse# Adds to the given player's score and updates both their stats table # in PlayerStatsManager and the billboard in the level. AddScore(Agent:agent):void= if: CurrentPlayerStats := PlayerStatsManager.GetPlayerStats[Agent] CurrentScore := CurrentPlayerStats.Score then: Print("Current Score is: {CurrentScore}") PlayerStatsManager.AddScore(Agent, AwardScore) UpdateStatsBillboard(Agent)CheckWin がインタラクトされたときにプレイヤーに勝利または敗北を与えるために、新しい関数
CheckWin()を player_stats_manager クラス定義に追加します。Verse# Awards a player a win or a loss when they interact # with the CheckWinButton. CheckWin(Agent:agent):void=まず、エージェントの現在のスコアを追跡するための変数
CurrentScoreを定義します。 次に、AddScore()関数と同様に、プレーヤーの統計データ テーブルから現在のスコアを取得します。Verse# Awards a player a win or a loss when they interact # with the CheckWinButton. CheckWin(Agent:agent):void= var CurrentScore:int = 0 if: PlayerStats := PlayerStatsManager.GetPlayerStats[Agent] set CurrentScore = PlayerStats.Scoreエージェントの現在のスコアが
WinScoreより大きければ勝利を、そうでなければ敗北をPlayerStatsManagerに記録する必要があります。 記録する必要があります。 最後に、AddScore()を使って現在のCurrentScoreの値を負の数として渡し、エージェントのスコアをリセットしてから、統計ビルボードにエージェントのステータスを表示します。 完成したCheckWin()関数は、次のようになります。Verse# Awards a player a win or a loss when they interact # with the CheckWinButton. CheckWin(Agent:agent):void= var CurrentScore:int = 0 if: PlayerStats := PlayerStatsManager.GetPlayerStats[Agent] set CurrentScore = PlayerStats.Score then: Print("Current Score is: {CurrentScore}") if:OnBegin()で、ScorePointsButton.InteractedWithEventをAddScore()にサブスクライブし、CheckWinButton.InteractedWithEventをCheckWin()にサブスクライブします。 次に、GetPlayers()を呼び出してゲーム内の各プレイヤーの配列を取得し、統計データ マネージャーのInitializeAllPlayers()関数を使用してそれらすべてを初期化します。Verse# Runs when the device is started in a running game OnBegin<override>()<suspends>:void= # Register Button Events ScorePointsButton.InteractedWithEvent.Subscribe(AddScore) CheckWinButton.InteractedWithEvent.Subscribe(CheckWin) Players := GetPlayspace().GetPlayers() # Initialize player stats PlayerStatsManager.InitializeAllPlayers(Players)コードを保存してコンパイルします。
持続機能をレベルでテストする
持続データを編集セッションでテストできますが、そのセッションを終了して再起動すると、そのデータはリセットされます。 セッションをまたいでデータを持続させるには、プレイテスト セッションを起動し、島設定の特定の設定を変更する必要があります。 編集セッションとプレイテスト セッションの両方で持続可能データをテストできるように島を設定する方法については、持続データ ページの「持続データでテストする」を参照してください。
セッションを設定した後にレベルをプレイテストする場合、ScorePoints ボタンとインタラクトすると、プレイヤーのスコアに加算され、更新された値がビルボードに表示されるはずです。 CheckWin ボタンとインタラクトすると、プレイヤーのスコアに応じて、プレイヤーの勝利数または敗北数に加算されるはずです。 ロビーに戻ってからもう一度島に入ると、プレイヤーの統計データが持続されていて、更新されるたびに総勝利数/総敗北数と最高スコアがビルボードに表示されるはずです。
応用編
このガイドを完了したことで、Verse を使用して、ゲームプレイ セッション間で持続する、プレイヤーごとに追跡される持続可能データを作成する方法を習得できました。 次は、持続機能を応用して独自の体験をどのように高めることができるかを確かめてください。
プレイヤーが到達した最後のチェックポイントを覚えている保存ファイル システムを作成できますか?
会話したことがあるキャラクターおよびそのキャラクターとの現在の関係を覚えているシステムについてはどうですか?
複数のセッションにわたってゴールに到達までの限られた時間のみをプレイヤーに与えて、失敗したらプレイヤーの進行度をリセットするシステムについてはどうですか?
完全なコード
このセクションのチュートリアルで作成した完全なコードを以下に示します。
player_stats_table.verse
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }
# Tracks different persistable stats for each player.
player_stats_table := class<final><persistable>:
# The version of the current stats table.
Version<public>:int = 0
# The score of a player.
player_stats_manager.verse
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }
# Manages and updates player_stat_tables for each player.
player_stats_manager := class():
# Return the player_stats_table for the provided Agent.
GetPlayerStats(Agent:agent)<decides><transacts>:player_stats_table=
var PlayerStats:player_stats_table = player_stats_table{}
player_stats_example.verse
using { /Fortnite.com/Devices }
using { /Fortnite.com/Game }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }
# A Verse-authored creative device that can be placed in a level
player_stats_example := class(creative_device):
# Adds to the activating player's score.
@editable