プレイヤーがアイドル状態であるかどうかを特定する
このセクションでは、プレイヤーが前回のシミュレーションの更新以降に一定の距離を移動したかどうかを確認する方法について説明します。移動していた場合は、プレイヤーの現在位置が保存され、再度確認されます。移動していない場合は、ループを抜け、メソッドが完了します。このメソッドでは、GetFortCharacter[]、GetTransform()、Translation を使用してプレイヤーの位置を取得します。これらの詳細については、それぞれの「API リファレンス」のページを参照してください。
このページには、このゲームプレイで必要なゲームプレイ メカニクスの実行方法を示す Verse のスニペットが含まれています。以下の手順を実行してから、このチュートリアルの ステップ 6 にある完全なスクリプトをコピーしてください。
以下の手順を実行すると、プレイヤーがアイドル状態であるかどうかを特定できます。
-
AwaitStopMoving()という名前のエージェント クラスの拡張メソッドを作成します。つまり、定義済みのクラスにカスタム メソッドを追加します。(PropAgent:agent).AwaitStopMoving(MinimumDistance:float)<suspends>:void= Logger.Print("エージェントの移動が最小移動距離未満であることを確認しています。") -
プレイヤーの初期位置を取得します。
(PropAgent:agent).AwaitStopMoving(MinimumDistance:float)<suspends>:void= Logger.Print("Checking if the agent has moved less than the minimum distance.") # シーン内のエージェントのキャラクターからエージェントの初期位置を取得します。 if (Tracked := PropAgent.GetFortCharacter[]): var StartPosition:vector3 = Tracked.GetTransform().Translation -
次回のシミュレーションの更新で、プレイヤーの次の位置を取得します。
(PropAgent:agent).AwaitStopMoving(MinimumDistance:float)<suspends>:void= Logger.Print("Checking if the agent has moved less than the minimum distance.") # シーン内のエージェントのキャラクターからエージェントの初期位置を取得します。 if (Tracked := PropAgent.GetFortCharacter[]): var StartPosition:vector3 = Tracked.GetTransform().Translation Sleep(0.0) # 次のゲーム ティックでのエージェントの位置を取得します。 NewPosition := Tracked.GetTransform().Translation - 初期位置と最新の位置の間の距離が、
MinimumDistanceパラメータとして関数に渡された、受け入れ可能なしきい値内であるかどうかを確認します。(PropAgent:agent).AwaitStopMoving(MinimumDistance:float)<suspends>:void= Logger.Print("Checking if the agent has moved less than the minimum distance.") # シーン内のエージェントのキャラクターからエージェントの初期位置を取得します。 if (Tracked := PropAgent.GetFortCharacter[]): var StartPosition:vector3 = Tracked.GetTransform().Translation Sleep(0.0) # 次のゲーム ティックでのエージェントの位置を取得します。 NewPosition := Tracked.GetTransform().Translation # 開始位置からの新しい位置の距離が MinimumDistance 未満である場合は、エージェントは移動していないため、ループを抜けます。 if (Distance(StartPosition, NewPosition) < MinimumDistance): Logger.Print("Agent has moved less than the minimum distance.") # その他の場合は、StartPosition をリセットして、プレイヤーの新しい位置からの移動を確認します。 else: set StartPosition = NewPosition -
次に、初期位置と最新の位置の間のチェックをループし、これらの位置の間の距離が
MinimumDistanceのしきい値を上回ったらループを抜ける必要があります。# エージェントの移動が MinimumDistance 未満になるまでループします。 (PropAgent:agent).AwaitStopMoving(MinimumDistance:float)<suspends>:void= Logger.Print("Checking if the agent has moved less than the minimum distance.") # シーン内のエージェントのキャラクターからエージェントの初期位置を取得します。 if (Tracked := PropAgent.GetFortCharacter[]): var StartPosition:vector3 = Tracked.GetTransform().Translation loop: Sleep(0.0) # 次のゲーム ティックでのエージェントの位置を取得します。 NewPosition := Tracked.GetTransform().Translation # 開始位置からの新しい位置の距離が MinimumDistance 未満である場合は、エージェントは移動していないため、ループを抜けます。 if (Distance(StartPosition, NewPosition) < MinimumDistance): Logger.Print("Agent has moved less than the minimum distance.") break # その他の場合は、StartPosition をリセットして、プレイヤーの新しい位置からの移動を確認します。 else: set StartPosition = NewPosition
ハートビートまでのカウントダウン
以下の手順を実行すると、カウントダウン時間が時間切れになるまで警告とカウントダウン タイマーを表示して、警告とカウントダウン テキストをクリアするまでに、HeartBeat.MoveTime - HeartBeat.WarningTime に相当する時間を待機します。
- CountdownTimer() という名前の関数を作成します。
# HeartBeatWarningTime が開始するまで遅延します。その後、HeartBeatWarningTime でカウントダウンし、カウントダウン テキストを設定します。遅延時は、テキストをクリアします。 CountdownTimer(PropAgent:agent)<suspends>:void = Logger.Print("Starting heartbeat countdown.") -
まず、heartbeat.verse で設定したマップから、関連付けられているプレイヤーの
heartbeat_warning_uiの取得を試行する必要があります。取得できたら、プレイヤーが停止してからカウントダウン タイマーが表示されるまでの遅延を開始する必要があります。# HeartBeatWarningTime が開始するまで遅延します。その後、HeartBeatWarningTime でカウントダウンし、カウントダウン テキストを設定します。遅延時は、テキストをクリアします。 CountdownTimer(PropAgent:agent)<suspends>:void= Logger.Print("Starting heart beat countdown.") if (UIData := HeartBeat.WarningUI[PropAgent]): Sleep(HeartBeat.MoveTime - HeartBeat.WarningTime) # 警告が表示されるまでの期間スリープします。 Logger.Print("Starting heartbeat warning.") else: Logger.Print("UIData not found.") -
次に、画面に表示され、1 秒ごとに 1 ずつ減っていく変数を作成します。変数に「
WarningTimeRemaining」という名前を付けます。これを heartbeat.verse のWarningTimeに設定します。WarningTimeRemainingがintであり、WarningTimeがfloatであるため、Ceil[]関数を使用してintを作成する必要があります。# HeartBeatWarningTime が開始するまで遅延します。その後、HeartBeatWarningTime でカウントダウンし、カウントダウン テキストを設定します。遅延時は、テキストをクリアします。 CountdownTimer(PropAgent:agent)<suspends>:void= Logger.Print("Starting heart beat countdown.") if (UIData := HeartBeat.WarningUI[PropAgent]): Sleep(HeartBeat.MoveTime - HeartBeat.WarningTime) # Sleep for the amount of time before the warning appears. Logger.Print("Starting heartbeat warning.") var WarningTimeRemaining:int = 0 if (set WarningTimeRemaining = Ceil[HeartBeat.WarningTime]) {} else: Logger.Print("UIData not found.") -
カウントダウン ループを開始する前に、
defer式を使用して、CountdownTimer()関数が完了するたびにプレイヤーの UI からカウントダウン タイマーをクリアします。この関数は、タイマーが時間切れになるか、プレイヤーが再び移動を開始した場合にのみ完了します。詳細は、「Defer」をご覧ください。# HeartBeatWarningTime が開始するまで遅延します。その後、HeartBeatWarningTime でカウントダウンし、カウントダウン テキストを設定します。遅延時は、テキストをクリアします。 CountdownTimer(PropAgent:agent)<suspends>:void= Logger.Print("Starting heart beat countdown.") if (UIData := HeartBeat.WarningUI[PropAgent]): Sleep(HeartBeat.MoveTime - HeartBeat.WarningTime) # 警告が表示されるまでの期間スリープします。 Logger.Print("Starting heart beat warning.") var WarningTimeRemaining:int = 0 if (set WarningTimeRemaining = Ceil[HeartBeat.WarningTime]) {} # defer は、関数が完了したときや、レースに負けた場合など、関数がキャンセルされたときに実行されます。 # そのため、この場合、カウントダウンが終了するか、カウントダウンが終了する前に小道具エージェントが移動すると、警告テキストはクリアされます。 defer: UIData.Text.SetText(HeartBeatWarningClear) # 警告テキストを残り時間に設定し、1 秒待機してから残り時間を減らします。カウントダウンが完了したら、ループを抜けます。 UIData.Text.SetText(HeartBeatWarningMessage(WarningTimeRemaining)) else: Logger.Print("UIData not found.") -
最後に、カウントダウン タイマーを減らすループを作成します。
SetText()関数を使用して、WarningTimeRemainingでHeartBeatWarningMessageを表示します。次に、残り時間を減らす前にSleep()で 1 秒待機します。WarningTimeRemainingが 0 以下の場合は、カウントダウンが完了しているため、ループを抜けることができます。# HeartBeatWarningTime が開始するまで遅延します。その後、HeartBeatWarningTime でカウントダウンし、カウントダウン テキストを設定します。遅延時は、テキストをクリアします。 CountdownTimer(PropAgent:agent)<suspends>:void= Logger.Print("Starting heart beat countdown.") if (UIData := HeartBeat.WarningUI[PropAgent]): Sleep(HeartBeat.MoveTime - HeartBeat.WarningTime) # Sleep for the amount of time before the warning appears. Logger.Print("Starting heart beat warning.") var WarningTimeRemaining:int = 0 if (set WarningTimeRemaining = Ceil[HeartBeat.WarningTime]) {} # defer は、関数が完了したときや、レースに負けた場合など、関数がキャンセルされたときに実行されます。 # そのため、この場合、カウントダウンが終了するか、カウントダウンが終了する前に小道具エージェントが移動すると、警告テキストはクリアされます。 defer: UIData.Text.SetText(HeartBeatWarningClear) # 警告テキストを残り時間に設定し、1 秒待機してから残り時間を減らします。カウントダウンが完了したら、ループを抜けます。 loop: Logger.Print("Heart beat in {WarningTimeRemaining} seconds.") UIData.Text.SetText(HeartBeatWarningMessage(WarningTimeRemaining)) Sleep(1.0) set WarningTimeRemaining -= 1 if (WarningTimeRemaining <= 0): break else: Logger.Print("UIData not found.")
アイドル状態のプレイヤーでエフェクトを再生する
AwaitStopMoving() が完了したら、そのプレイヤーのカウントダウン タイマーを開始して、その後 ハートビート エフェクトをスタートさせます。ただし、プレイヤーが再び動き始めるとすぐに、タイマーまたはハートビートのどちらか現在実行中のものをキャンセルする必要があります。これを行うには、race 式が必要です。2 つのレース式は次のとおりです。
-
PropAgent.AwaitStartMoving(MinimumMoveDistance) -
blockハートビートのエフェクトが再生されるまでカウントダウンが行われます。
AwaitStartMoving() は、レースで勝利し、カウントダウン タイマーまたはハートビート エフェクトを停止するために必要です。
ブロック式は、その中の 2 つの関数、CountdownTimer() および StartHeartbeart() が順次実行され、互いにレースしないようにするために使用されます。カウントダウン タイマーは、タイマーが完了した 後に ハートビートのエフェクトが開始されることを小道具プレイヤーに知らせることを意図しているため、タイマーとハートビートの両方を同時に開始しても意味がありません。
プレイヤーが長い間動いていないときにエフェクトを再生するには、次の手順を実行します。
AwaitStartMoving()という名前の拡張メソッドを作成します。実装は以下の点を除いて同じです。
-
このメソッドは、前回のシミュレーションの更新以降、プレイヤーが
MinimumDistance以上移動したかどうかを確認します。AwaitStopMoving()のように、MinimumDistance未満ではありません。 -
このメソッドは、ループが終わるたびに
StartPositionをリセットしません。ループが終わるたびにStartPositionがリセットされると、シミュレーションの更新にかかる時間の間に、プレイヤーがMinimumDistance以上移動する必要があり、これは、不可能である可能性があります。# エージェントが MinimumDistance を上回る距離を移動するまでループします。 (PropAgent:agent).AwaitStartMoving(MinimumDistance:float)<suspends>:void= Logger.Print("Checking if the agent moves further than the minimum distance.") # シーン内のエージェントのキャラクターからエージェントの初期位置を取得します。 if (Tracked := PropAgent.GetFortCharacter[]): StartPosition:vector3 = Tracked.GetTransform().Translation loop: Sleep(0.0) # Get the position of the agent in the next game tick. NewPosition := Tracked.GetTransform().Translation # 開始位置からの新しい位置の距離が MinimumDistance 以上である場合、エージェントは移動しているため、ループを抜けます。 if (Distance(StartPosition, NewPosition) >= MinimumDistance): Logger.Print("Agent has moved more than or equal to the minimum distance.") break
-
RunPropGameLoop()という名前の関数を作成します。この関数は、プレイヤーがきわめて長い間アイドル状態である場合に、ハートビート エフェクトを再生するように管理します。# 小道具エージェントが移動を停止した場合、小道具エージェントが MinimumMoveDistance を超えて移動するか、ハートビートタイマーが完了するか、小道具エージェントが撃破されるかの、いずれが先に起こるかを確認します。 RunPropGameLoop(PropAgent:agent)<suspends>:void = Logger.Print("Starting prop agent game loop.") -
小道具エージェントの移動距離が最小移動距離を下回るまで待機してから、先に進みます。
# 小道具エージェントが移動を停止した場合、小道具エージェントが MinimumMoveDistance を超えて移動するか、ハートビートタイマーが完了するか、小道具エージェントが撃破されるかの、いずれが先に起こるかを確認します。 RunPropGameLoop(PropAgent:agent)<suspends>:void = Logger.Print("Starting prop agent game loop.") # 小道具エージェントが撃破されるか、プレイヤーがセッションを退出するまで、小道具の動作を永続的にループします。 loop: # 小道具エージェントの移動距離が最小移動距離を下回るまで待機してから、先に進みます。 PropAgent.AwaitStopMoving(MinimumMoveDistance) Sleep(0.0) -
race式を追加して、AwaitStartMoving()の完了 (プレイヤーが移動を開始したことを意味する) と、CountdownTimer()とその後のStartHeartbeat()の実行を伴うblock式の間でレースを行います。# 小道具エージェントが移動を停止した場合、小道具エージェントが MinimumMoveDistance を超えて移動するか、ハートビートタイマーが完了するか、小道具エージェントが撃破されるかの、いずれが先に起こるかを確認します。 RunPropGameLoop(PropAgent:agent)<suspends>:void = Logger.Print("Starting prop agent game loop.") # 小道具エージェントが撃破されるか、プレイヤーがセッションを退出するまで、小道具の動作を永続的にループします。 loop: # 小道具エージェントの移動距離が最小移動距離を下回るまで待機してから、先に進みます。 PropAgent.AwaitStopMoving(MinimumMoveDistance) # 小道具エージェントの移動距離が最小移動距離を超えるまで、ハートビートまでのカウントダウンを実行してから、ハートビートを無期限に再生します。 race: PropAgent.AwaitStartMoving(MinimumMoveDistance) block: CountdownTimer(PropAgent) PropAgent.StartHeartbeat() Sleep(0.0) # レースが完了したら (小道具エージェントが移動したら)、再びループを開始します。