コアとなるゲームプレイが完成したので、プレイヤーがアクションを実行するときに、次のように視覚的なフィードバックを提供する必要があります。
プレイヤーにどこへ行くべきかを示す目標マーカーを示す。
プレイヤーが得点を得たとき、カウントダウンにさらに時間を付与する。
プレイヤーが乗り物に乗ったときのみにゲームを開始する。
プレイヤーが新しいアイテムを拾ったときに、そのプレイヤーから余分なピザを削除して、プレイヤーがマップ上にピザをドロップしないようにする。
「タイムトライアル:ピザ配送」チュートリアルのこのステップを完了すると、ゲームの質を高める方法を習得できます。
プレイヤーに次の選択されたピックアップ ゾーンを表示する
次の手順に従って、どこへ行くべきかをプレイヤーに示す目標マーカーを追加します。 「game_coordinator_device.verse」ファイルを次のように更新します。
PickupMarkerという名前の、public指定子付きの編集可能なobjective_markerをgame_coordinator_deviceクラスに追加します。@editable PickupMarker<public> : objective_marker = objective_marker{}PickupDeliveryLoop()関数の先頭で、PickupMarkerオブジェクトに関連付けられているマップ インジケータの仕掛けを有効にし、関数の終了時にこの仕掛けを非アクティブ化および無効にするためのdeferを設定します。PickupDeliveryLoop<private>()<suspends> : void = PickupZonesTags : []pickup_zone_tag = array{pickup_zone_level_1_tag{}, pickup_zone_level_2_tag{}, pickup_zone_level_3_tag{}} MaxPickupLevel := PickupZonesTags.Length - 1 FirstPickupZoneCompletedEvent := event(){} <# PickupDeliveryLoop の終了時に必ずマーカーが無効になるように、MapIndicator の無効化を遅らせます。 PickupDeliveryLoop がキャンセルされた場合にも遅延が実行されます。 #> defer: if (ValidPlayer := MaybePlayer?): PickupMarker.MapIndicator.DeactivateObjectivePulse(ValidPlayer) PickupMarker.MapIndicator.Disable() PickupMarker.MapIndicator.Enable()次のピックアップ ゾーンが選択されたら、選択されたピックアップ ゾーンにピックアップ マーカーを動かし、
PickupMarker.MapIndicator.ActivateObjectivePulse()を呼び出してプレイヤーをそこに誘導します。Verserace: loop: if (PickupZone : base_zone = PickupZoneSelectors[PickupLevel].SelectNext[]): PickupZone.ActivateZone() Sleep(0.0) PickupMarker.MoveMarker(PickupZone.GetTransform(), ?OverTime := 0.0) if (ValidPlayer := MaybePlayer?): PickupMarker.MapIndicator.ActivateObjectivePulse(ValidPlayer) <# This is the only defer we need for any PickupZone we activate. It will either deactivate the first PickupZone at the end of each outer loop,
プレイヤーがスコアを獲得した際に、カウントダウンにさらに時間を追加する
プレイヤーがアイテムを配達するたびに追加の時間を与えることで、プレイヤーに対してより頻繁にアイテムを配達するように促すことができます。
カウントダウンにさらに時間を追加するには、次の手順に従います。
「score_manager.verse」ファイル内で、
AddPendingScoreToTotalScore()関数の戻り値の型をintに変更し、総スコアに追加されたポイントを使用してカウントダウンを更新できるようにreturn PendingScoreを追加します。AddPendingScoreToTotalScore<public>() : int = set TotalGameScore += PendingScore defer: set PendingScore = 0 UpdateUI() return PendingScore「game_coordinator_device.verse」ファイル内で、
public指定子付きの編集可能なDeliveryBonusSecondsという名前のfloatをgame_coordinator_deviceクラス定義に追加します。これは、配送にコミットされているそれぞれのポイントに対してカウントダウン タイマーに追加する秒数を表します。# ピックアップしたアイテムを配送したときにカウントダウン タイマーに追加する秒数。 @editable DeliveryBonusSeconds<public> : float = 20.0ボーナス時間を計算し、カウントダウン タイマーの残り時間を更新するように、配送の
block式を更新します。block: FirstPickupZoneCompletedEvent.Await() if (DeliveryZone := DeliveryZoneSelector.SelectNext[]): DeliveryZone.ActivateZone() # PickupDeliveryLoop がキャンセルされた場合にもアクティブな配送ゾーンが非アクティブ化されるように、ゾーンの非アクティブ化を遅らせます。 defer: Logger.Print("Deactivating delivery zone.",?Level := log_level.Normal) DeliveryZone.DeactivateZone() DeliveryZone.ZoneCompletedEvent.Await() Logger.Print("Delivered", ?Level:=log_level.Normal) PointsCommitted := ScoreManager.AddPendingScoreToTotalScore() BonusTime : float = DeliveryBonusSeconds * PointsCommitted CountdownTimer.AddRemainingTime(BonusTime) else: Logger.Print("Can't find next DeliveryZone to select.",?Level := log_level.Error) return # Error out of the PickupDeliveryLoopプレイテスト時には、ピザをピックアップして配送ゾーンに行くと、カウントダウンに時間が追加されます。
プレイヤーが乗り物に乗り込んだときにゲームを開始する
プレイヤーが乗り物 (ビークル、車両) に乗り込んだときにゲームを開始したり、ビークルを降りたときの処理を設定したりするには、次の手順に従います。
乗り物スポナーの仕掛けへの編集可能な参照を、
public指定子付きで作成します。@editable VehicleSpawner<public> : vehicle_spawner_atk_device = vehicle_spawner_atk_device{}private指定子とsuspends指定子を持つStartGameOnPlayerEntersVehicle()という名前の関数を作成します。 この関数では、プレイヤーが乗り物に乗り込むのを待ってからStartGame()を呼び出し、乗り物に乗り込んだプレイヤー参照でMaybePlayer変数を更新する必要があります。StartGame()ではなくOnBegin()を更新して、この関数を呼び出します。OnBegin<override>()<suspends> : void = FindPlayer() SetupZones() # プレイヤーがこの乗り物に初めて乗り込んで、ゲームが開始されたときにのみ通知されるようにします。 # StartGameOnPlayerEntersVehicle はそのイベントを待ってから、ゲームプレイ ループを開始します。 StartGameOnPlayerEntersVehicle() StartGameOnPlayerEntersVehicle<private>()<suspends> : void = VehiclePlayer := VehicleSpawner.AgentEntersVehicleEvent.Await() Logger.Print("Player entered the vehicle") set MaybePlayer = option{player[VehiclePlayer]} StartGame()プレイヤーが乗り物から降りたときのイベント ハンドラを設定します。
private指定子のある「HandlePlayerExitsVehicle()」という名前の関数を作成します。OnBegin<override>()<suspends> : void = FindPlayer() SetupZones() # 乗り物に乗り込んだ後に、プレイヤーはいつでもその乗り物から降りることができますが、 # 降りるたびにそれを検知して、プレイヤーを乗り物に戻すようにします。 VehicleSpawner.AgentExitsVehicleEvent.Subscribe(HandlePlayerExitsVehicle) # プレイヤーがこの乗り物に初めて乗り込んで、ゲームが開始されたときにのみ通知されるようにします。 # StartGameOnPlayerEntersVehicle はそのイベントを待ってから、ゲームプレイ ループを開始します。 StartGameOnPlayerEntersVehicle() HandlePlayerExitsVehicle<private>(VehiclePlayer : agent) : void = Logger.Print("Player exited the vehicle. Reassigning player to vehicle") VehicleSpawner.AssignDriver(VehiclePlayer)
余分なピザを削除する
プレイヤーが新しいアイテムを拾ったときに余分なピザをプレイヤーから削除して、プレイヤーがマップ上にピザをドロップしないようにするには、次の手順に従います。
プレイヤーのインベントリからピザを削除するアイテム リムーバーの仕掛けへの編集可能な参照を追加します。
@editable PizzaRemover<public> : item_remover_device = item_remover_device{}PickupDeliveryLoop()関数内で、プレイヤーがアイテムをピックアップした直後に、プレイヤーからピザを取り除きます。Verseloop: if (PickupZone : base_zone = PickupZones[PickupLevel].SelectNext[]): PickupZone.ActivateZone() Sleep(0.0) PickupMarker.MoveMarker(PickupZone.GetTransform(), ?OverTime := 0.0) if (ValidPlayer := MaybePlayer?): PickupMarker.MapIndicator.ActivateObjectivePulse(ValidPlayer) <# This is the only defer we need for any PickupZone we activate. It will either deactivate the first PickupZone at the end of each outer loop, or it'll deactivate any later PickupZone. That's because the expression is evaluated at the end, when the PickupZone variable has been bound to a newer zone. #>