이제 코어 게임플레이를 만들었으니 플레이어가 액션을 수행할 때 다음과 같은 시각적 피드백을 제공해야 합니다.
플레이어에게 어디로 갈지 보여주는 목표 마커.
플레이어 득점 시 카운트다운에 시간 추가.
플레이어가 탈것에 들어갈 때만 게임 시작.
플레이어가 피자를 맵에 떨어뜨리지 않도록 새 아이템을 픽업할 때 여분의 피자 제거.
타임 트라이얼: 피자 배달 게임 튜토리얼의 이 단계를 완료하면 게임의 완성도를 높이는 방법을 배우게 됩니다.
플레이어에게 다음으로 선택된 픽업 구역 표시하기
다음 단계에 따라 플레이어에게 다음 목적지를 보여주는 목표 마커를 추가합니다. 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(){} <# MapIndicator 비활성화를 defer로 지연시켜 PickupDeliveryLoop를 종료하면 항상 마커가 비활성화되게 합니다. defer는 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 PendingScoregame_coordinator_device.verse 파일에서 이름이
DeliveryBonusSeconds이고public지정자가 있는 편집 가능float를game_coordinator_device클래스 정의에 추가하여 배달로 얻은 점수마다 카운트다운 타이머에 몇 초를 추가할지 나타냅니다.# 픽업한 피자가 배달되었을 때 카운트다운 타이머에 추가할 시간(초)입니다. @editable DeliveryBonusSeconds<public> : float = 20.0보너스 시간을 계산하고 카운트다운 타이머의 남은 시간을 업데이트하도록 배달
block표현식을 업데이트합니다.block: FirstPickupZoneCompletedEvent.Await() if (DeliveryZone := DeliveryZoneSelector.SelectNext[]): DeliveryZone.ActivateZone() # 구역 비활성화를 defer로 지연시켜 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 # 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. #>