A invisibilidade do Infiltrador cria um problema interessante quando se trata de coletar o objetivo do Defensor. O que os defensores terão que fazer para encontrar um jogador invisível que pode estar correndo de volta à base com seu objetivo? Para resolver esse problema, você pode usar um auxílio visual, neste caso um adereço, para mostrar aos defensores onde está o infiltrador.
Siga as etapas abaixo para aprender a criar um objeto que flutua acima da cabeça de um jogador quando ele tem um objetivo.
Criando o gerenciador de captura de itens
- Crie um novo dispositivo Verse chamado item_capture_manager usando o Explorador do Verse e arraste-o para o nível.
- Na parte superior do arquivo
item_capture_manager:- Adicione
using { /UnrealEngine.com/Temporary/SpatialMath }para acessar a estruturavector3. Você usará essa função para saber para onde teletransportar os indicadores que flutuam sobre a cabeça de um jogador. Adicione tambémusing { /Fortnite.com/Characters }para acessar ofort_characterdo jogador. ~~~(verse) using { /Fortnite.com/Devices } using { /Verse.org/Simulation } using { /Fortnite.com/Characters } using { /UnrealEngine.com/Temporary/Diagnostics } using { /UnrealEngine.com/Temporary/SpatialMath } ~~~
- Adicione
- Na definição da classe
item_capture_manager, adicione os seguintes campos:-
Uma matriz editável de Gerador de Itens de Captura denominada
CaptureItemSpawners. Essa matriz contém o dispositivo Gerador de Itens de Captura para os Infiltradores. ~~~(verse) item_capture_manager := class(creative_device):Logger:log = log{Channel := triad_item_capture_log_channel}
# O gerador de itens de captura que gera o item a ser capturado. @editable CaptureItemSpawner:capture_item_spawner_device = capture_item_spawner_device{} ~~~
-
Um adereço editável do Modo Criativo denominado
CaptureItemIndicator. Este é o adereço que flutuará acima da cabeça de um infiltrador quando ele capturar o objetivo. ~~~(verse) # O gerador de itens de captura que gera o item a ser capturado. @editable CaptureItemSpawner:capture_item_spawner_device = capture_item_spawner_device{}# Adereço que flutua acima da cabeça dos jogadores quando estão segurando o item a partir de # CaptureItemSpawner. @editable CaptureItemIndicator:creative_prop = creative_prop{} ~~~
-
Um dispositivo indicador de mapa editável denominado
MapIndicator. Ficará abaixo de CaptureItemSpawner no nível e será exibido no mapa onde estão os objetivos de cada equipe. ~~~(verse) # Adereço que flutua acima da cabeça dos jogadores quando estão segurando o item a partir de # CaptureItemSpawner. @editable CaptureItemIndicator:creative_prop = creative_prop{}# O indicador que mostra no mapa onde estão os objetivos de cada equipe @editable MapIndicator:map_indicator_device = map_indicator_device{} ~~~
-
Dois floats editáveis
UpdateRateSecondseVerticalOffset. O primeiro controla a rapidez com que a posição deCaptureItemIndicatormuda, enquanto o segundo controla a distância da cabeça do jogador em que oCaptureItemIndicatorflutua. ~~~(verse) # O indicador que mostra no mapa onde estão os objetivos de cada equipe @editable MapIndicator:map_indicator_device = map_indicator_device{}# Com que frequência CaptureItemIndicator atualiza sua posição. @editable UpdateRateSeconds:float = 0.15
# A que altura acima da cabeça do jogador CaptureItemIndicator flutua. @editable VerticalOffset:float = 180.0 ~~~
- Um dispositivo Mensagem do HUD editável denominado
ItemGrabbedMessageDevice. Envia uma mensagem a cada jogador quando um objetivo é coletado.# A que altura acima da cabeça do jogador CaptureItemIndicator flutua. @editable VerticalOffset:float = 180.0 Mostra uma mensagem quando um jogador coleta o item de captura. @editable ItemGrabbedMessageDevice:hud_message_device = hud_message_device{} -
Um dispositivo Gerenciador de Pontuação editável denominado
ScoreManagerDevice. Atribui uma pontuação a uma equipe sempre que um jogador captura o objeto. ~~~(verse) Mostra uma mensagem quando um jogador coleta o item de captura. @editable ItemGrabbedMessageDevice:hud_message_device = hud_message_device{}# Atribui uma pontuação a uma equipe sempre que um jogador coleta o objeto. @editable ScoreManagerDevice:score_manager_device = score_manager_device{} ~~~
- Um float editável denominado
ReturnTime. Se o item de captura tiver um tempo de retorno antes de retornar a CaptureItemSpawner, você precisará controlar quanto tempo dura esse tempo de retorno para saber quando retornar os indicadores a CaptureItemSpawner.
-
- Adicione um novo método
FollowCharacter()à definição de classe deitem_capture_manager. Esse método usafort_charactere o rastreia usando os indicadores acima de sua cabeça. Adicione o especificador<suspends>a essa função, já que devemos gerar um deles para um jogador sempre que ele estiver portando um objetivo. ~~~(verse) # Faz com que CaptureItemIndicator siga continuamente um jogador acima de sua cabeça. # Percorre entre o loop de atualização de CaptureItemIndictator e se o jogador # captura ou solta o item ou é eliminado. FollowCharacter(FortCharacter:fort_character):void= Logger.Print("Função FollowCharacter gerada") ~~~
Participando de uma corrida ao portar o objetivo
É importante pensar no que acontece quando um jogador pega o objetivo. O jogador pode:
- Movimentar-se: nesse caso, você precisa que os indicadores de CaptureItem e Map sejam atualizados continuamente para a posição do jogador. Para isso, use um loop.
- Capturar o objetivo: nesse caso, você precisa que seus indicadores retornem a CaptureItemSpawner em algum lugar fora de vista, pois eles não devem estar visíveis a menos que um jogador esteja segurando o item de captura.
- Descartar o objetivo ou ser eliminado: nesse caso, os indicadores precisam ficar onde o item foi solto e depois retornar ao CaptureItemSpawner quando o item capturado retornar.
Para executar essa função, você configurará uma expressão race. Ao usar race entre as três condições acima, você pode continuar a atualizar a posição dos indicadores enquanto espera que o jogador solte ou capture o objetivo.
- Adicione uma expressão
raceaFollowCharacter(). Configure a corrida para execução entre umloop, umAwait()paraCaptureItemSpawnerItemCapturedEvent, umAwait()paraItemCapturedDroppedEventdoCaptureItemSpawnere umAwait ()paraEliminatedEvent()doFortCharacter. ~~~(verse) FollowCharacter(FortCharacter:fort_character):void= Logger.Print("Função FollowCharacter gerada") race: loop: CaptureItemSpawner.ItemCapturedEvent.Await() CaptureItemSpawner.ItemDroppedEvent.Await() FortCharacter.EliminatedEvent().Await() ~~~ - Em
loop, obtenha a posição deFortCharactere salve-a em uma variávelTransform. ~~~(verse) loop: Transform := FortCharacter.GetTransform() ~~~ - Agora, gere
MoveTo()para moverCaptureItemIndicatoreMapIndicatoraté a translação e a rotação deTransformmaisVerticalOffsetque você configurou anteriormente durante um período de tempo deUpdateRateSeconds. ApliqueSpawn{}às duas funçõesMoveTo(), poisCaptureItemIndicatoreMapIndicatorprecisam se mover exatamente ao mesmo tempo, em vez de esperar que a expressão um do outro seja concluída. Como a translação é umvetor3que consiste nas coordenadasX,YeZ, você terá que colocar oVerticalOffsetdentro de um novovetor3. Uma vez que oVerticalOffseté a distância vertical acima da cabeça de um jogador, defina-o como o valorZdovetor3. ~~~(verse) 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)} ~~~ - Por fim, suspenda por
0.0segundos. Isso garante que o loop seja executado apenas uma vez por atualização da simulação e não saia do controle que gera funçõesMoveTo(). Seu códigoFollowCharacter()agora deve ter a seguinte aparência: ~~~(verse) # Faz com que CaptureItemIndicator siga continuamente um jogador acima de sua cabeça. # Percorre entre o loop de atualização de CaptureItemIndictator e se o jogador # captura ou solta o item ou é eliminado. FollowCharacter(FortCharacter:fort_character):void= Logger.Print("Função FollowCharacter gerada") 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)} # Como queremos garantir que esse loop seja executado apenas uma vez por atualização de simulação, colocamos para em suspensão durante um marca de jogo. Sleep(0.0) CaptureItemSpawner.ItemCapturedEvent.Await() CaptureItemSpawner.ItemDroppedEvent.Await() FortCharacter.EliminatedEvent().Await() Logger.Print("Objetivo solto ou capturado") ~~~ Como redefinir os indicadores
- Quando o item de captura é capturado ou retornado, você precisa retornar os indicadores para
CaptureItemSpawnerem algum lugar fora da vista. Neste caso, você os teletransportará acima deCaptureItemSpawner. Para isso, adicione uma função chamadaReturnIndicators()à definição da classeitem_capture_manager.# Retorna os indicadores de mapa e item de captura às suas posições iniciais acima dos geradores. ReturnIndicators(InAgent:agent):void= - Obtenha a transformação de
CaptureItemSpawnere salve-a em uma variávelSpawnerTransform. Em seguida, gereMoveTo()paraCaptureItemIndicatoreMapIndicatorpara a transformação e rotação deCaptureItemSpawner, adicionandoVerticalOffsetda mesma forma que fez nolooppara colocá-los acima deCaptuerItemSpawner. Se quiser que seu adereço fique fora de vista, pode multiplicarVerticalOffsetpor um número grande, neste caso, 10. Seu métodoReturnIndicators()completo deve ter a seguinte aparência: ~~~(verse)Retorna os indicadores de mapa e item de captura às suas posições iniciais acima dos geradores.
ReturnIndicators():void= SpawnerTransform := CaptureItemSpawner.GetTransform() # Teletransportar de volta ao gerador, ocultando CaptureItemIndicator e MapIndicator acima do mapa fora do local. 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("Indicadores retornados ao gerador de captura") ~~~
Lidar com jogadores agarrando, soltando e capturando o objetivo.
- Adicione um novo método
OnItemPickedUp()à definição de classeitem_capture_manager. Esse método gera uma instância deFollowCharacter()para esse personagem com umagent.# Sinalizar cada jogador quando ele capturar o objetivo OnItemPickedUp(InAgent:agent):void= Logger.Print("Objetivo capturado") - Obtenha o
FortCharacterparaInAgente gere uma funçãoFollowCharacter()usando esseFortCharacter. Seu métodoOnItemPickedUp()completo deve ter a seguinte aparência: ~~~(verse) # Sinalizar cada jogador quando ele capturar o objetivo OnItemPickedUp(InAgent:agent):void= Logger.Print("Objetivo capturado") if(FortCharacter := InAgent.GetFortCharacter[]): ItemGrabbedMessageDevice.Show() spawn{FollowCharacter(FortCharacter)} ~~~ - Adicione um novo método
OnItemCaptured()à definição de classe deitem_capture_manager. Esse método usaagentque capturou o objetivo. ~~~(verse) # Quando o item for capturado, atribuir pontuação à equipe de captura e retornar os indicadores. OnItemCaptured(CapturingAgent:agent):void= Logger.Print("Objetivo capturado") ~~~ - Em
OnItemCaptured(), ativeScoreManagerDevicepara atribuir a pontuação da equipe do jogador capturador e chameReturnIndicators()para retornar os indicadores. ~~~(verse) # Quando o item for capturado, atribuir pontuação à equipe de captura e retornar os indicadores. OnItemCaptured(CapturingAgent:agent):void= Logger.Print("Objetivo capturado") ScoreManagerDevice.Activate() ReturnIndicators() ~~~ - Adicione um novo método
OnItemDropped()à definição da classe deitem_capture_manager. Esse método usa oagentque soltou o item. ~~~(verse) # Quando um jogador deixa um item cair, ele gerará uma função WaitForReturn() # se ReturnTime for maior que 0. OnItemDropped(InAgent:agent):void= Logger.Print("Objetivo solto") ~~~ - Quando o objetivo é descartado, os indicadores devem permanecer por perto até que ele seja coletado ou retorne a
CaptureItemSpawner. Para saber quando retornar os indicadores, você usará a variávelReturnTime, configurada anteriormente. SeReturnTimefor maior que ou igual a0.0, convém esperar esse período de tempo e então retornar os indicadores. SeReturnTimefor negativo, o objetivo não terá tempo de retorno e, portanto, não é necessário mover os indicadores. Para retornar os indicadores, gere uma nova função auxiliar chamadaWaitForReturn(), que você definirá na próxima etapa. ~~~(verse) # Quando um jogador deixa um item cair, ele gerará uma função WaitForReturn() # se ReturnTime for maior que 0. OnItemDropped(InAgent:agent):void= Logger.Print("Objetivo solto") if(ReturnTime >= 0.0): spawn{WaitForReturn()} else: Logger.Print("O objetivo solto não retorna") ~~~ - Adicione um novo método
WaitForReturn()à definição da classe deitem_capture_manager. Essa função espera um período de tempo indicado emReturnTimee, em seguida, retorna se o objetivo não tiver sido coletado antes do término da espera. Adicione o modificador<suspends>a esse método para permitir que ele entre emSleep(). ~~~(verse) # Aguardar um período de tempo ReturnTime e retornar os indicadores. WaitForReturn():void= Logger.Print("Aguardando o retorno dos indicadores...") ~~~ - A necessidade ou não de retornar os indicadores depende do fato de o objetivo ter sido coletado antes do término de
ReturnTime. Se ele foi coletado antes, não convém retornar os indicadores, pois eles voltariam imediatamente ao jogador, podendo gerar alguns elementos visuais estranhos. Para resolver isso, você usará uma variável lógica em que o valor é igual ao resultado de uma "race". ~~~(verse) # Aguardar um período de tempo ReturnTime e retornar os indicadores. WaitForReturn():void= Logger.Print("Aguardando o retorno dos indicadores...") # Retornar os indicadores CaptureItem e Map se o item de captura # não for coletado antes de o tempo expirar. ShouldReturn:logic := race: ~~~ - Sua função
WaitForReturn()precisa percorrer entre duas condições.ReturnTimese esgota e o objetivo retorna paraCaptureItemSpawner. Nesse caso, você precisa retornar os indicadores eShouldReturndeve sertrue. Ou o objetivo é coletado antes queReturnTimeexpire. Nesse caso,ShouldReturndeve serfalse. Como cada uma dessas condições retorna um valor, você executará a corrida usando doisblocks(blocos) separados. ~~~(verse) ShouldReturn:logic := race: block: block: ~~~ - No primeiro bloco, chame
Sleep()por um período de tempoReturnTimee depois retornetrue. No segundo bloco, useAwait()paraCaptureItemSpawner.ItemPickedUpEvente retornefalse. A variávelShouldReturnagora será inicializada para qualquer um deles que seja concluído primeiro. ~~~(verse) ShouldReturn:logic := race: block: Sleep(ReturnTime) true block: CaptureItemSpawner.ItemPickedUpEvent.Await() false ~~~ -
Se
ShouldReturnfor verdadeiro, você precisará retornar os indicadores. ChameReturnIndicators()seShouldReturnfor avaliado comotrue. Seu códigoWaitForReturn()concluído agora deve ser semelhante a: ~~~(verse) # Aguardar um período de tempo ReturnTime e retornar os indicadores. WaitForReturn():void= Logger.Print("Aguardando o retorno dos indicadores...") # Retornar os indicadores CaptureItem e Map se o item de captura # não for coletado antes de o tempo expirar. ShouldReturn:logic := race: block: Sleep(ReturnTime) true block: CaptureItemSpawner.ItemPickedUpEvent.Await() false if(ShouldReturn?): ReturnIndicators() ~~~
- Agora, em
OnBegin(), inscreva oItemPickedUpEventdeCaptureItemSpawneremOnItemPickedUp(), oItemCapturedEventemOnItemCaptured()e oItemDroppedEventemOnItemDropped(). ~~~(verse) OnBegin() :void= CaptureItemSpawner.ItemPickedUpEvent.Subscribe(OnItemPickedUp) CaptureItemSpawner.ItemCapturedEvent.Subscribe(OnItemCaptured) CaptureItemSpawner.ItemDroppedEvent.Subscribe(OnItemDropped) SpawnerTransform := CaptureItemSpawner.GetTransform() ~~~ -
Por fim, em OnBegin(), coloque os indicadores em suas posições iniciais quando o script for executado chamando MoveTo() em CaptureItemIndicator e MapIndicator. Seu código OnBegin() agora deve ficar assim: ~~~(verse) OnBegin
() :void= CaptureItemSpawner.ItemPickedUpEvent.Subscribe(OnItemPickedUp) CaptureItemSpawner.ItemCapturedEvent.Subscribe(OnItemCaptured) CaptureItemSpawner.ItemDroppedEvent.Subscribe(OnItemDropped) SpawnerTransform := CaptureItemSpawner.GetTransform() # Teletransportar de volta ao gerador, ocultando CaptureItemIndicator abaixo do mapa fora do local. CaptureItemIndicator.MoveTo(SpawnerTransform.Translation + vector3{Z := VerticalOffset 10.0}, SpawnerTransform.Rotation, UpdateRateSeconds) MapIndicator.MoveTo(SpawnerTransform.Translation + vector3{Z := VerticalOffset 10.0}, SpawnerTransform.Rotation, UpdateRateSeconds) ~~~
-
Voltando ao editor, salve o script, crie-o e arraste o dispositivo para o nível. Escolha um adereço apropriado para oferecer como
CaptureItemIndicatorno nível. Ele pode ser qualquer coisa, desde que seja visível o suficiente. Neste exemplo, você usará um diamante. No painel Detalhes, atribua CaptureItemSpawner a InfiltratorCaptureSpawner e CaptureItemIndicator ao adereço que você escolheu. Atribua também MapIndicator ao indicador de mapa do infiltrador, ItemGrabbedMessageDevice ao dispositivo Mensagem do HUD do infiltrador e ScoreManagerDevice ao Gerenciador de Pontuação do infiltrador. Defina ReturnTime como um número negativo, pois o item de captura do infiltrador não é retornado.Você também deve configurar uma instância de
item_capture_managerpara os atacantes. Lembre-se de alterar CaptureItemIndicator para um adereço diferente dos adereços do infiltrador, para evitar confusão visual para as equipes, e certifique-se de atribuir todos os outros dispositivos. Defina ReturnTime como um número positivo, pois o item de captura do atacante retorna após um tempo definido. - Clique em Iniciar sessão na barra de ferramentas do UEFN para testar o nível. Ao testar seu nível, o jogador deve ter um adereço acima da cabeça ao capturar um objetivo. O adereço deve se mover com o jogador e, quando ele soltar ou capturar o objetivo, o adereço deve se teletransportar de volta para o gerador de itens de captura.

Próxima etapa
Na próxima etapa deste tutorial, você aprenderá a dizer rapidamente aos jogadores o que eles devem fazer em um jogo e no que focar quando estiver melhorando a experiência dos jogadores.