침투자는 투명 상태이기 때문에 방어자의 목표물을 획득했을 때도 흥미로운 문제가 발생합니다. 방어자는 목표물을 가지고 자신의 기지로 전력질주하여 도망치는 투명 플레이어를 어떻게 찾아야 할까요? 이 문제를 해결하려면 시각적 도움, 이 경우에는 사물의 도움을 받아 침투자의 위치를 방어자에게 보여주면 됩니다.
목표물을 가진 플레이어의 머리 위에 오브젝트를 띄우는 방법을 살펴보려면 다음 단계를 따릅니다.
아이템 회수 관리 장치 생성하기
- Verse 익스플로러를 사용하여 item_capture_manager 라는 새 Verse 장치를 생성하여 레벨에 드래그합니다.
item_capture_manager파일의 상단에서 다음 작업을 수행합니다.using { /UnrealEngine.com/Temporary/SpatialMath }를 추가하여vector3구조체에 액세스합니다. 이것을 사용하면 플레이어 머리 위에 떠 있는 표시를 어디로 순간이동시킬지 알 수 있습니다.using { /Fortnite.com/Characters }도 추가하여 플레이어의fort_character에 액세스합니다.using { /Fortnite.com/Devices } using { /Verse.org/Simulation } using { /Fortnite.com/Characters } using { /UnrealEngine.com/Temporary/Diagnostics } using { /UnrealEngine.com/Temporary/SpatialMath }
item_capture_manager클래스 정의에서 다음과 같은 필드를 추가합니다.- 회수 아이템 생성 장치
CaptureItemSpawners의 편집 가능 배열. 이 배열은 침투자를 위한 회수 아이템 생성 장치를 저장합니다.item_capture_manager := class(creative_device): Logger:log = log{Channel := triad_item_capture_log_channel} # 회수할 아이템을 생성하는 회수 아이템 생성 장치입니다. @editable CaptureItemSpawner:capture_item_spawner_device = capture_item_spawner_device{} CaptureItemIndicator로 명명된 편집 가능 포크리 사물. 이것은 침투자가 목표물을 획득했을 때 머리 위에 표시될 사물입니다.# 회수할 아이템을 생성하는 회수 아이템 생성 장치입니다. @editable CaptureItemSpawner:capture_item_spawner_device = capture_item_spawner_device{} # 플레이어가 CaptureItemSpawner에서 나온 아이템을 가지고 있을 때 # 머리 위에 표시될 사물입니다. @editable CaptureItemIndicator:creative_prop = creative_prop{}MapIndicator로 명명된 편집 가능 지도 표시 장치. 레벨의 CaptureItemSpawner 아래에 위치하며, 팀별 목표물의 위치를 지도에 표시합니다.# 플레이어가 CaptureItemSpawner에서 나온 아이템을 가지고 있을 때 # 머리 위에 표시될 사물입니다. @editable CaptureItemIndicator:creative_prop = creative_prop{} # 팀별 목표물의 위치를 지도에 표시하는 표시 장치입니다 @editable MapIndicator:map_indicator_device = map_indicator_device{}- 두 개의 편집 가능 플로트
UpdateRateSeconds및VerticalOffset. 전자는CaptureItemIndicator의 위치가 얼마나 빨리 변하는지, 후자는 플레이어의 머리 위로CaptureItemIndicator가 얼마나 높이 뜨는지를 제어합니다.# 팀별 목표물의 위치를 지도에 표시하는 표시 장치입니다 @editable MapIndicator:map_indicator_device = map_indicator_device{} # CaptureItemIndicator가 그 위치를 업데이트하는 빈도입니다. @editable UpdateRateSeconds:float = 0.15 # CaptureItemIndicator가 플레이어의 머리 위에 떠 있는 높이입니다. @editable VerticalOffset:float = 180.0 ItemGrabbedMessageDevice로 명명된 편집 가능 HUD 메시지 장치. 목표물을 픽업했을 때 각 플레이어에게 메시지를 보냅니다.# CaptureItemIndicator가 플레이어의 머리 위에 떠 있는 높이입니다. @editable VerticalOffset:float = 180.0 # 플레이어가 회수 아이템을 획득하면 메시지를 표시합니다. @editable ItemGrabbedMessageDevice:hud_message_device = hud_message_device{}ScoreManagerDevice로 명명된 편집 가능 점수 관리 장치. 플레이어가 목표물을 회수하면 팀에 점수를 획득합니다.# 플레이어가 회수 아이템을 획득하면 메시지를 표시합니다. @editable ItemGrabbedMessageDevice:hud_message_device = hud_message_device{} # 플레이어가 회수 아이템을 회수하면 점수를 획득합니다. @editable ScoreManagerDevice:score_manager_device = score_manager_device{}ReturnTime으로 명명된 편집 가능 플로트. 회수 아이템에 CaptureItemSpawner로 반환되기 전에 반환 시간이 있는 경우, 표시 장치를 언제 CaptureItemSpawner로 다시 반환할지 확인하기 위해 해당 반환 시간의 길이를 트래킹해야 합니다.
- 회수 아이템 생성 장치
- 새 메서드
FollowCharacter()를item_capture_manager클래스 정의에 추가합니다. 이 메서드는fort_character를 취해 머리 위의 표시 장치를 사용하여 추적합니다. 플레이어가 목표물 중 하나를 보유할 때마다 이 중 하나를 스폰해야 하므로 함수에<suspends>지정자를 추가합니다.# CaptureItemIndicator가 플레이어 머리 위에서 계속 따라다니게 합니다. # CaptureItemIndicator에 대한 업데이트 루프, 플레이어가 아이템을 회수했는지, 아이템을 드롭했는지, 아이템이 제거되었는지 여부 # 사이의 레이스입니다. FollowCharacter(FortCharacter:fort_character)<suspends>:void= Logger.Print("Spawned FollowCharacter function")
목표물을 갖고 달리기
플레이어가 목표물을 획득했을 때 어떤 일이 벌어지는지가 중요합니다. 플레이어는 다음과 같은 행동을 할 수 있습니다.
- 주변 이동. 이 경우 플레이어의 위치를 지속적으로 업데이트해야 하므로 CaptureItem과 지도 표시 장치가 필요합니다. 이것은 루프로 작업할 수 있습니다.
- 목표물 회수. 이 경우 플레이어가 회수 아이템을 갖고 있지 않다면, 표시 장치도 보이면 안 되므로, 표시 장치를 시야에 보이지 않는 어딘가에 있는 CaptureItemSpawner로 반환해야 합니다.
- 목표물 드롭 또는 제거. 이 경우 표시 장치는 아이템이 드롭된 곳에 머물러야 하며, 회수 아이템이 반환되면 CaptureItemSpawner로 반환됩니다.
이 목표를 달성하려면 race 표현식을 구성해야 합니다. 위 세 가지 조건 사이에 race 를 사용하면 플레이어가 목표물을 드롭하거나 완전히 회수할 때까지 기다리는 동안 표시 장치의 위치를 계속 업데이트할 수 있습니다.
race표현식을FollowCharacter()에 추가합니다. 이때,CaptureItemSpawner의ItemCapturedEvent에 대한Await(),CaptureItemSpawner’의ItemCapturedDroppedEvent에 대한Await(), 그리고FortCharacter의EliminatedEvent()를loop하도록 레이스를 구성합니다.FollowCharacter(FortCharacter:fort_character)<suspends>:void= Logger.Print("Spawned FollowCharacter function") race: loop: CaptureItemSpawner.ItemCapturedEvent.Await() CaptureItemSpawner.ItemDroppedEvent.Await() FortCharacter.EliminatedEvent().Await()loop에서FortCharacter의 위치를 구하여Transform변수에 저장합니다.loop: Transform := FortCharacter.GetTransform()- 이제
MoveTo()를 생성하여CaptureItemIndicator및MapIndicator를Transform의 이동 및 회전, 그리고 앞에서 구성한VerticalOffset에UpdateRateSeconds동안 이동합니다.CaptureItemIndicator및MapIndicator가 서로의 표현식이 완료될 때까지 기다리는 것이 아니라 정확히 동시에 이동해야 하므로, 두MoveTo()함수 모두Spawn{}하려고 합니다. 이동은X,Y및Z좌표로 이루어진vector3이므로 새vector3내부에VerticalOffset를 둬야 합니다.VerticalOffset은 플레이어 머리 위의 수직 거리이므로vector3의Z값으로 설정합니다.loop: Transform := FortCharacter.GetTransform() spawn{CaptureItemIndicator.MoveTo(Transform.Translation + vector3{Z := VerticalOffset}, Transform.Rotation, UpdateRateSeconds)} spawn{MapIndicator.MoveTo(Transform.Translation + vector3{Z := VerticalOffset}, Transform.Rotation, UpdateRateSeconds)} - 마지막으로
0.0동안 슬립합니다. 루프가 시뮬레이션 업데이트 당 1번만 실행되도록 하고,MoveTo()함수를 생성하는 컨트롤 범위에서 벗어나지 않습니다. 이제FollowCharacter()코드는 다음과 같게 됩니다.# CaptureItemIndicator가 플레이어 머리 위에서 계속 따라다니게 합니다. # CaptureItemIndicator에 대한 업데이트 루프, 플레이어가 아이템을 회수했는지, 아이템을 드롭했는지, 아이템이 제거되었는지 여부 # 사이의 레이스입니다. FollowCharacter(FortCharacter:fort_character)<suspends>:void= Logger.Print("Spawned FollowCharacter function") race: loop: Transform := FortCharacter.GetTransform() spawn{CaptureItemIndicator.MoveTo(Transform.Translation + vector3{Z := VerticalOffset}, Transform.Rotation, UpdateRateSeconds)} spawn{MapIndicator.MoveTo(Transform.Translation + vector3{Z := VerticalOffset}, Transform.Rotation, UpdateRateSeconds)} # 이 루프는 시뮬레이션 업데이트당 한 번만 실행되어야 하므로, 게임 틱 한 번 동안 슬립합니다. Sleep(0.0) CaptureItemSpawner.ItemCapturedEvent.Await() CaptureItemSpawner.ItemDroppedEvent.Await() FortCharacter.EliminatedEvent().Await() Logger.Print("Objective dropped or captured")표시 장치 초기화하기
- 회수 아이템이 회수되거나 반환되면, 시야에 보이지 않는 어딘가에 있는
CaptureItemSpawner로 표시 장치를 반환해야 합니다. 여기서는CaptureItemSpawner위로 순간이동시키겠습니다. 이렇게 하기 위해,ReturnIndicators()로 명명된 함수를item_capture_manager클래스 정의에 추가합니다.# 지도와 회수 아이템 표시 장치를 처음에 있던 생성 장치 위로 되돌립니다. ReturnIndicators(InAgent:agent):void= CaptureItemSpawner의 트랜스폼을 구하여SpawnerTransform변수에 저장합니다. 그런 다음,CaptureItemIndicator및MapIndicator에 대한MoveTo()를CaptureItemSpawner의 트랜스폼 및 회전에 생성하고,loop에서CaptuerItemSpawnwer위에 두었던 것과 같은 방식으로VerticalOffset를 추가합니다. 사물을 눈에 띄지 않는 곳까지 멀리 두려면VerticalOffset에 큰 숫자를 곱하면 됩니다. 이 경우에는 10을 곱합니다. 완성된ReturnIndicators()메서드는 다음과 같아야 합니다.# 지도와 회수 아이템 표시 장치를 처음에 있던 생성 장치 위로 되돌립니다. ReturnIndicators():void= SpawnerTransform := CaptureItemSpawner.GetTransform() # 생성 장치로 다시 순간이동하여 CaptureItemIndicator와 MapIndicator를 지도에서 안 보이는 곳 위에 숨깁니다. spawn{CaptureItemIndicator.MoveTo(SpawnerTransform.Translation + vector3{Z := VerticalOffset * 10.0}, SpawnerTransform.Rotation, UpdateRateSeconds)} spawn{MapIndicator.MoveTo(SpawnerTransform.Translation + vector3{Z := VerticalOffset * 10.0}, SpawnerTransform.Rotation, UpdateRateSeconds)} Logger.Print("Returned Indicators to capture spawner")
목표물을 획득, 드롭, 회수한 플레이어 처리하기
- 새 메서드
OnItemPickedUp()를item_capture_manager클래스 정의에 추가합니다. 이 메서드는agent를 취하고, 해당 캐릭터에 대한FollowCharacter()의 인스턴스를 스폰합니다.# 플레이어가 목표물을 획득하면 각 플레이어에게 신호합니다 OnItemPickedUp(InAgent:agent):void= Logger.Print("Objective Grabbed") InAgent에 대한FortCharacter를 구하고, 이FortCharacter를 사용하여FollowCharacter()함수를 스폰합니다. 완성된OnItemPickedUp()메서드는 다음과 같아야 합니다.# 플레이어가 목표물을 획득하면 각 플레이어에게 신호합니다 OnItemPickedUp(InAgent:agent):void= Logger.Print("Objective Grabbed") if(FortCharacter := InAgent.GetFortCharacter[]): ItemGrabbedMessageDevice.Show() spawn{FollowCharacter(FortCharacter)}- 새 메서드
OnItemCaptured()를item_capture_manager클래스 정의에 추가합니다. 이 메서드는 목표물을 회수한agent를 취합니다.# 아이템이 회수되었을 때, 회수 팀이 점수를 획득하고 표시 장치를 반환합니다. OnItemCaptured(CapturingAgent:agent):void= Logger.Print("Objective Captured") OnItemCaptured()에서ScoreManagerDevice를 활성화하여 플레이어의 팀에 점수를 부여하고ReturnIndicators()를 호출하여 표시 장치를 반환합니다.# 아이템이 회수되었을 때, 회수 팀이 점수를 획득하고 표시 장치를 반환합니다. OnItemCaptured(CapturingAgent:agent):void= Logger.Print("Objective Captured") ScoreManagerDevice.Activate() ReturnIndicators()- 새 메서드
OnItemDropped()를item_capture_manager클래스 정의에 추가합니다. 이 메서드는 아이템을 드롭한agent를 취합니다.# 플레이어가 아이템을 드롭했을 때 ReturnTime이 0보다 클 경우 # WaitForReturn() 함수를 스폰합니다. OnItemDropped(InAgent:agent):void= Logger.Print("Objective Dropped") - 목표물이 드롭되면, 표시 장치는 목표물이 픽업되거나
CaptureItemSpawner로 반환될 때까지 목표물 가까이에 있어야 합니다. 표시 장치가 언제 반환되는지 알기 위해서는 앞에서 구성한ReturnTime변수를 사용합니다.ReturnTime이0.0보다 크거나 같으면, 그동안 기다린 다음 표시 장치를 반환합니다.ReturnTime이 음수이면, 목표물에 반환 시간이 없으므로 표시 장치를 이동할 필요가 없습니다. 다시 표시 장치를 이동하려면, 다음 단계에서 정의할WaitForReturn()으로 명명된 새로운 헬퍼 함수를 스폰합니다.# 플레이어가 아이템을 드롭했을 때 ReturnTime이 0보다 클 경우 # WaitForReturn() 함수를 스폰합니다. OnItemDropped(InAgent:agent):void= Logger.Print("Objective Dropped") if(ReturnTime >= 0.0): spawn{WaitForReturn()} else: Logger.Print("The dropped objective does not return") - 새 메서드
WaitForReturn()을item_capture_manager클래스 정의에 추가합니다. 이 함수는ReturnTime동안 기다린 다음 목표물이 대기 시간이 완료되기 전에 픽업되지 않으면 반환합니다. 이 메서드에<suspends>모디파이어를 추가하여Sleep()을 허용합니다.# ReturnTime 동안 기다린 후 표시 장치를 반환합니다. WaitForReturn()<suspends>:void= Logger.Print("Waiting to return the indicators...") - 표시 장치를 반환해야 할지 여부는 목표물이
ReturnTime이 종료되기 전에 픽업됐는지 여부에 따라 달라집니다. 만약 그런 경우, 표시 장치가 즉시 플레이어에게 돌아가 이상하게 보이는 현상이 야기될 수 있으므로 표시 장치를 반환되지 않게 합니다. 이를 해결하기 위해 값이 레이스 결과와 같은 로직 변수를 사용합니다.# ReturnTime 동안 기다린 후 표시 장치를 반환합니다. WaitForReturn()<suspends>:void= Logger.Print("Waiting to return the indicators...") # 시간이 만료되기 전에 회수 아이템이 픽업되지 않으면 # CaptureItem과 지도 표시 장치를 반환합니다. ShouldReturn:logic := race: WaitForReturn()함수는 두 가지 조건 사이에서 레이스를 해야 합니다.ReturnTime이 소진되고, 목표물이CaptureItemSpawner로 반환됩니다. 이 경우 표시 장치를 반환해야 하고,ShouldReturn이true여야 합니다. 또는ReturnTime이 만료되기 전에 목표물이 픽업됩니다. 이 경우ShouldReturn은false여야 합니다. 이러한 각 조건은 값을 반환하므로 별도의block두 개를 사용하여 레이스를 실행합니다.ShouldReturn:logic := race: block: block:- 첫 번째 블록에서는
ReturnTime동안Sleep()을 호출한 다음true를 반환합니다. 두 번째 블록에서는CaptureItemSpawner.ItemPickedUpEvent를Await()하고 false를 반환합니다. 이제ShouldReturn변수는 둘 중 먼저 완료되는 것으로 초기화됩니다.ShouldReturn:logic := race: block: Sleep(ReturnTime) True block: CaptureItemSpawner.ItemPickedUpEvent.Await() False ShouldReturn이 true라면, 표시 장치를 반환해야 합니다.ShouldReturn이true로 평가되면ReturnIndicators()를 호출합니다. 이제 완료된WaitForReturn()코드는 다음과 같게 됩니다.# ReturnTime 동안 기다린 후 표시 장치를 반환합니다. WaitForReturn()<suspends>:void= Logger.Print("Waiting to return the indicators...") # 시간이 만료되기 전에 회수 아이템이 픽업되지 않으면 # CaptureItem과 지도 표시 장치를 반환합니다. ShouldReturn:logic := race: block: Sleep(ReturnTime) True block: CaptureItemSpawner.ItemPickedUpEvent.Await() False if(ShouldReturn?): ReturnIndicators()- 이제
OnBegin()에서CaptureItemSpawner의ItemPickedUpEvent를OnItemPickedUp()에,ItemCapturedEvent를OnItemCaptured()에,ItemDroppedEvent를OnItemDropped()에 등록합니다.OnBegin<override>()<suspends>:void= CaptureItemSpawner.ItemPickedUpEvent.Subscribe(OnItemPickedUp) CaptureItemSpawner.ItemCapturedEvent.Subscribe(OnItemCaptured) CaptureItemSpawner.ItemDroppedEvent.Subscribe(OnItemDropped) SpawnerTransform := CaptureItemSpawner.GetTransform() - 마지막으로,
OnBegin()의CaptureItemIndicator및MapIndicator에서MoveTo()를 호출하여 스크립트가 실행되면 표시 장치를 시작 위치에 둡니다. 이제OnBegin()코드는 다음과 같게 됩니다.OnBegin<override>()<suspends>:void= CaptureItemSpawner.ItemPickedUpEvent.Subscribe(OnItemPickedUp) CaptureItemSpawner.ItemCapturedEvent.Subscribe(OnItemCaptured) CaptureItemSpawner.ItemDroppedEvent.Subscribe(OnItemDropped) SpawnerTransform := CaptureItemSpawner.GetTransform() # 생성 장치로 다시 순간이동하여 CaptureItemIndicator를 지도에서 안 보이는 곳 아래에 숨깁니다. CaptureItemIndicator.MoveTo(SpawnerTransform.Translation + vector3{Z := VerticalOffset * 10.0}, SpawnerTransform.Rotation, UpdateRateSeconds) MapIndicator.MoveTo(SpawnerTransform.Translation + vector3{Z := VerticalOffset * 10.0}, SpawnerTransform.Rotation, UpdateRateSeconds) -
다시 에디터에서 스크립트를 저장하고 빌드하여 장치를 레벨에 드래그합니다. 레벨에서
CaptureItemIndicator로 적절히 사용할 만한 사물을 고릅니다. 충분히 눈에 띄기만 하면 무엇이든 상관없습니다. 이 예시에서는 다이아몬드를 사용하겠습니다. '디테일(Details)' 패널에서 CaptureItemSpawner를 InfiltratorCaptureSpawner에, CaptureItemIndicator를 선택한 사물에 할당합니다. 또한 MapIndicator 를 침투자의 지도 표시 장치에, ItemGrabbedMessageDevice 를 침투자의 HUD 메시지 장치에, ScoreManagerDevice 를 침투자의 점수 관리 장치에 할당합니다. 침투자의 회수 아이템은 반환하지 않으므로, ReturnTime 을 음수로 설정합니다.또한 공격자를 위해
item_capture_manager의 인스턴스도 구성해야 합니다. 팀 멤버들이 시각적으로 혼동이 되지 않도록 CaptureItemIndicator 를 침투자 사물과는 다른 사물로 변경하고 다른 모든 장치를 할당해야 합니다. 침투자의 회수 아이템은 설정 시간 후에 반환되므로 ReturnTime 을 양수로 설정합니다. - UEFN 툴바에서 세션 시작(Launch Session) 을 클릭하여 레벨을 플레이테스트합니다. 레벨을 플레이테스트할 때는 플레이어가 목표물을 획득했을 때 머리 위로 사물이 표시되어야 합니다. 사물은 플레이어를 따라 움직여야 하며, 플레이어가 목표물을 드롭하거나 회수에 성공했을 경우 사물은 회수 아이템 생성 장치로 다시 순간이동되어야 합니다.

다음 단계
이 튜토리얼의 다음 단계에서는 플레이어에게 게임에서 수행해야 할 일을 빠르게 알려주는 방법과 플레이어 경험 향상 시 집중해야 할 사항을 살펴봅니다.