Paramédicos são um arquétipo de personagem comum em muitos jogos. A função de um paramédico é curar personagens próximos e ajudar os companheiros a se recuperarem após receber dano. Paramédicos desempenham funções diferentes dependendo do jogo, por exemplo, aqueles que atendem pacientes em um hospital; combatentes que, além de curarem, ajudam suas equipes a lutar; ou estações neutras que curam qualquer personagem.
O personagem paramédico que você criará neste exemplo segue um conjunto de regras lógicas.
- Ocioso:
- Iniciar cura de agentes
- Loop de cura
- Navegar até agente
O paramédico começa ocioso e patrulha até que um agente entre na área de cura. Esse agente é então adicionado à fila de cura do paramédico. O paramédico precisa rastrear o agente que precisa ser curado em seguida, e uma fila oferece uma estrutura de dados útil para essa finalidade, pois funciona ao estilo de o primeiro a entrar é o primeiro a sair. Isso significa que o personagem que entrar primeiro na área de cura será o primeiro a ser curado.
Assim que o paramédico receber o próximo agente que precisa ser curado, ele primeiro verifica se a vida desse agente está abaixo do limite de cura. Nesse caso, ele começa a curá-lo a uma taxa específica até que a vida do agente atinja o limite ou o agente saia da área de cura. Durante a cura, o médico tentará ficar perto do agente, dirigindo-se continuamente até ele. Assim que a vida do agente voltar ao limite, o paramédico receberá o próximo agente que precisa de cura, e o processo recomeça. Se não houver agentes para curar, o paramédico voltará a ficar ocioso.
Você pode visualizar a lógica do PNJ paramédico usando a máquina de estado finito abaixo. Para obter mais informações sobre máquinas de estado finito, consulte Compreendendo comportamentos de PNJs.
Ao completar este guia, você aprenderá a criar um personagem paramédico personalizado usando o script de comportamento de PNJ, que cura outros personagens próximos quando a vida deles está abaixo de um determinado limite. O script completo está incluído no final deste guia para referência.
Como criar um novo script de comportamento de PNJ
Para começar a criar seu próprio PNJ paramédico, crie um novo script de comportamento de PNJ chamado medic_example. Para obter mais informações sobre como criar seu próprio script de comportamento de PNJ, consulte Como criar seu próprio comportamento de PNJ. Abra o arquivo Verse no Visual Studio Code.
Siga estas etapas para criar um script de comportamento de PNJ no UEFN que gera um personagem paramédico capaz de curar jogadores próximos.
Como implementar a fila de cura
O script de comportamento de PNJ começa com vários valores usados para movimentação de personagens e visualização de depuração. Você não precisará de todos eles nesse script, então removerá o código desnecessário agora.
-
No topo da definição da classe
medic_example, remova os valores antes deOnBegin(). O personagem paramédico não esperará para ir até os personagens e, em vez disso, os seguirá durante a cura. Você não precisa dos valores de depuração para este exemplo e usará outros objetos para visualizar quando o paramédico curar os personagens. -
Em
OnBegin(), depois de obter as interfaces do personagem na primeira instruçãoif, remova o código dentro da instruçãothen. O personagem paramédico não precisa fazer o loop entre os pontos após o surgimento e, em vez disso, patrulhará no ponto de surgimento, esperando que os personagens se curem. -
Remova as funções
DrawDebugLocation()eDrawDebugLookAt(). Como você não usará os valores de depuração neste exemplo, também não precisará das funções associadas que os utilizam.
Depois de remover o código desnecessário, você poderá começar a criar seu personagem paramédico.
-
No topo da definição da classe
medic_example, adicione os seguintes valores:-
O float editável
HealingThreshold. Este é o limite de vida que os personagens devem atingir para receberem cura.# O limite de PV que um personagem deve atingir antes de ser curado. @editable HealingThreshold:float = 50.0 -
Adicione um float editável
HealingDelay. Esse é o tempo de espera entre cada instância de cura durante a cura dos personagens. Mude este valor caso deseje que seu médico cure mais devagar ou mais rápido.~~~(verse) # O limite de PV que um personagem deve atingir antes de ser curado. @editable HealingThreshold:float = 50.0
# O tempo de espera antes de curar personagens @editable HealingDelay:float = 1.5 ~~~
-
Um float editável
HealingAmount. É a quantidade de vida para curar personagens por instância de cura. Quando seu PNJ paramédico curar um personagem, ele o curará emHealingAmounta cadaHealingDelaysegundos.~~~(verse) # O tempo de espera antes de curar personagens @editable HealingDelay:float = 1.5
# Quanto curar de personagens por instância de cura @editable HealingAmount:float = 5.0
~~~ -
Uma área mutante editável
HealVolume. É o volume em que os personagens entram para receber cura. Você usará uma área mutante neste exemplo porque ela tem umAgentEntersEvent, no qual seu paramédico pode se registrar e verificar se há personagens que possam precisar de cura.~~~(verse) # Quanto curar de personagens por instância de cura @editable HealingAmount:float = 5.0
# Os personagens de volume entram para receber cura. @editable HealVolume:mutator_zone_device = mutator_zone_device{} ~~~
-
Um gerador de efeitos visuais editável
VFXSpawner. Como é importante ter feedback visual para saber se o código está funcionando, você usará um gerador de efeitos visuais para fazer surgir efeitos quando um personagem estiver sendo curado.~~~(verse) # Os personagens de volume entram para receber cura. @editable HealVolume:mutator_zone_device = mutator_zone_device{}
# O gerador de efeitos visuais para reproduzir efeitos visuais enquanto personagens estão sendo curados. @editable VFXSpawner:vfx_spawner_device = vfx_spawner_device {} ~~~
-
Uma variável opcional
agentchamadaAgentToFollow. Ela armazena uma referência ao personagem que o paramédico deve seguir enquanto o cura.~~~(verse) # O gerador de efeitos visuais para reproduzir efeitos visuais enquanto personagens estão sendo curados. @editable VFXSpawner:vfx_spawner_device = vfx_spawner_device {}
#O agente a seguir enquanto ele está sendo curado var AgentToFollow:?agent = false ~~~
-
Uma fila variável de agentes chamada
AgentsToHeal. Se vários personagens precisarem de cura, o paramédico irá curá-los com base na ordem em que entraram emHealVolume. Você configurará o código da fila na próxima etapa. Para obter mais informações sobre a estrutura de dados da fila, consulte Pilhas e filas no Verse.~~~(verse) #O agente a seguir enquanto ele está sendo curado var AgentToFollow:?agent = false
# A fila de agentes para curar no caso de vários agentes entrarem no volume de cura. var AgentsToHeal
:queue(agent) = queue(agent){} ~~~ -
Um float variável
UpdateRateSeconds. É o tempo de espera entre a atualização da posição deHealVolumeeVFXSpawner.~~~(verse) # A fila de agentes para curar no caso de vários agentes entrarem no volume de cura. var AgentsToHeal
:queue(agent) = queue(agent){} # Usada para especificar com que rapidez atualizar a posição de HealVolume e VFXSpawner UpdateRateSeconds
:float = 0.1 ~~~
-
-
Para implementar a fila
AgentsToHeal, você usará o código fornecido no final dessa etapa.- De volta ao Explorador Verse, clique com o botão direito no nome do projeto e escolha Add new Verse file to project (Adicionar arquivo Verse ao projeto) para abrir a janela Criar script Verse.
-
Na janela Criar Script Verse, clique em Classe Verse para selecioná-lo como seu script.
-
Defina um nome para a classe Verse alterando o texto no campo Nome da classe para
queue. -
Clique em Criar para criar o arquivo Verse.
-
No Explorador do Verse, clique duas vezes no nome do arquivo Verse para abri-lo no Visual Studio Code.
-
Substitua o código no arquivo
queuepelo código a seguir. Esse código implementa uma fila genérica do tipotypeusando uma estrutura de dados em lista. Este é um exemplo de tipo paramétrico, pois a implementação da fila funcionará independentemente do tipo a partir do qual você a criou. No seu exemplo, você usará uma fila de personagens, então sua definição de fila emmedic_exampleseráqueue(agent).~~~(verse) list(t:type) := class: Data:t Next:?list(t)
queue
(t:type) := class : Elements :?list(t) = false Size :int = 0 Enqueue
(NewElement:t):queue(t) = queue(t): Elements := option: list(t): Data := NewElement Next := Elements Size := Size + 1 Dequeue
() :tuple(queue(t), t) = List := Elements? (queue(t){Elements := List.Next, Size := Size - 1}, List.Data) Front
() :t = Elements?.Data CreateQueue
-
Dividir seus scripts Verse em pastas distintas pode ajudar na organização, bem como fornecer maneiras de referenciar facilmente arquivos comumente usados. Como exemplo disso, você criará uma pasta para armazenar os comportamentos do PNJ nesse projeto. No Visual Studio Code, clique no botão Nova pasta para criar uma nova pasta no projeto UEFN. Dê a pasta o nome de
npc_behaviors. Em seguida, arraste o arquivo Versemedic_examplepara a nova pasta.
Seu código em medic_example agora deverá ser compilado corretamente.
Como curar personagens dentro de um volume
Quando um personagem ferido entra em HealVolume, seu personagem paramédico deve começar a curá-lo se a vida saúde for inferior a HealingThreshold. Quando a vida do personagem estiver acima de HealingThreshold, seu paramédico deverá parar de curar esse personagem e passar para o personagem que precisa de cura. No caso de vários personagens, seu paramédico deve curar os personagens na ordem em que entraram em HealVolume. Siga estas etapas para curar personagens quando entrarem em HealVolume.
-
De volta ao arquivo
medic_example, emOnBegin()após a instruçãothen, inicie umloop. Dentro doloop, obtenha o resultado da funçãoDequeue()da filaAgentsToHeale salve-o em uma variávelDequeueResult.~~~(verse) then: loop: # Faça com que o próximo agente da fila seja curado. Se houver um agente para curar, cure-o chamando AgentToHeal. # Se não houver agentes para curar, espere até que um agente entre em HealVolume if: DequeueResult := AgentsToHeal.Dequeue[] ~~~
-
A variável
DequeueResulté umatupleque retorna uma cópia da filaAgentsToHealcom o primeiro elemento removido e o agente no início da fila. AtualizeAgentsToHealdefinindo-o como o primeiro valor na tupla e salve o segundo valor comoAgentToHeal.~~~(verse) if: DequeueResult := AgentsToHeal.Dequeue[] set AgentsToHeal = DequeueResult(0) AgentToHeal := DequeueResult(1) ~~~
-
Depois de curar o agente, você precisa começar a curá-lo enquanto ele está em
HealVolume. Você definirá uma nova função chamadaHealCharacter()para lidar com isso. Adicione uma nova função chamadaHealCharacter()à definição da classemedic_example. Essa função usaAgentToHeale as interfacesNavigatableeFocusabledos personagens médicos como argumentos de função. Adicione o modificador<suspends>a essa função, pois ela precisa realizar diversas tarefas assíncronas ao curar um personagem.~~~(verse) # Cure o personagem e espere um período de tempo HealingDelayAmount. #Termina quando a vida do personagem atingir HealingThreshold # ou o personagem sai de HealVolume. HealCharacter(AgentToHeal:agent, Navigatable:navigatable, Focusable:focus_interface)
:void= ~~~ -
Em
HealCharacter, verifique seAgentToHealestá no volume chamandoIsInVolume[]e transmitindoAgentToHealcomo argumento. Se o agente estiver no volume, você poderá começar a curá-lo. Todos os agentes curáveis implementam a interfacehealthful, que faz parte dofort_characterdo agente. Obtenha ofort_characterdo agente e salve-o em um valorCharacterToHeal.~~~(verse) HealCharacter(AgentToHeal:agent, Navigatable:navigatable, Focusable:focus_interface)
:void= # Apenas cure o personagem se ele estiver dentro de HealVolume if: HealVolume.IsInVolume[AgentToHeal] CharacterToHeal := AgentToHeal.GetFortCharacter[] ~~~ -
Com o personagem pronto para ser curado, você precisa garantir que seu paramédico permaneça próximo ao personagem que está sendo curado. Crie um
navigation_targetdeAgentToHealusandoMakeNavigationTargete salve-o em uma variávelNavigationTarget. Então, em uma instruçãobranch, chame a funçãoNavigateTo()usando a interfacenavigatabledo PNJ para que seu paramédico navegue atéAgentToHeal. Também na funçãobranch, chame a funçãoMaintainFocus()para garantir que seu paramédico se concentre emAgentToHeal. Usar uma instruçãobranchnesse contexto permite que você executeNavigateTo()eMaintainFocus()de maneira assíncrona ao mesmo tempo e permite que execute qualquer código apósbranchimediatamente. Para obter mais informações sobre expressões branch, consulte a página sobre branch em Verse.~~~(verse) # Apenas cure o personagem se ele estiver dentro de HealVolume if: HealVolume.IsInVolume[AgentToHeal] CharacterToHeal := AgentToHeal.GetFortCharacter[] then:
Print("O personagem está no volume, iniciando a cura") NavigationTarget := MakeNavigationTarget(AgentToHeal) branch: Navigatable.NavigateTo(NavigationTarget) Focusable.MaintainFocus(AgentToHeal) ~~~ -
Habilite o
VFXSpawnerpara reproduzir efeitos visuais enquanto seu médico cura um personagem. Então, em uma expressãodefer, desabiliteVFXSpawner. Como o código para desabilitarVFXSpawnerestá em uma expressãodefer, ele não será executado até que o escopo atual seja encerrado. Nessa situação, significa que o código será executado apenas quando a função for encerrada, assim, garantimos que será a última ação que acontecerá na função. Para obter mais informações sobre expressões "defer", consulte a página sobre defer.~~~(verse) branch: Navigatable.NavigateTo(NavigationTarget) Focusable.MaintainFocus(AgentToHeal)
VFXSpawner.Enable()
defer: VFXSpawner.Disable() ~~~
-
Ao curar
CharacterToHeal, a cura deve parar quando uma das duas condições acontecer. A vida do personagem é curada além deHealingThreshold, ou o personagem sai deHealVolume. Para isso, você usará uma expressãorace. Configure uma expressãoraceentreloopeAwait()emHealVolume.AgentExitsEvent.~~~(verse) branch: Navigatable.NavigateTo(NavigationTarget) Focusable.MaintainFocus(AgentToHeal) VFXSpawner.Enable() defer: VFXSpawner.Disable() race: loop: HealVolume.AgentExitsEvent.Await() ~~~
-
Dentro do
loop, obtenha a vida atual do personagem usandoGetHealth()e salve-a em um valorCurrentHealth. Então, em uma instruçãoif, verifique seCurrentHealthmaisHealingAmounté maior queHealingThreshold. Nesse caso, seu médico deve parar de curar e sair do loop combreak. Porém, se a vida atual do personagem estiver abaixo do limite de cura, é uma boa ideia curá-lo até o limite de cura. Adicione uma segunda instruçãoifdentro da primeira que verifica seCurrentHealthé menor queHealingThreshold. Nesse caso, defina a vida do personagem comoHealingThreshold.~~~(verse) race: loop: CurrentHealth := CharacterToHeal.GetHealth() if(CurrentHealth + HealingAmount > HealingThreshold): if (CurrentHealth < HealingThreshold): CharacterToHeal.SetHealth(HealingThreshold) PrintNPCB("O personagem atingiu HealingThreshold, interrompendo a cura") break HealVolume.AgentExitsEvent.Await() ~~~
-
Caso contrário, se
CurrentHealthmaisHealingAmountnão for maior queHealingThreshold, defina a vida do personagem comoCurrent HealthmaisHealingAmount.~~~(verse) if(CurrentHealth + HealingAmount > HealingThreshold): if (CurrentHealth < HealingThreshold): CharacterToHeal.SetHealth(HealingThreshold) PrintNPCB("O personagem atingiu HealingThreshold, interrompendo a cura") break else: CharacterToHeal.SetHealth(CurrentHealth + HealingAmount) ~~~
-
No final do
loop, suspenda por um período de tempo igual aHealingDelay. Sem essa suspensão, os personagens serão curados a cada atualização da simulação, entãoHealingDelayimpedirá que eles sejam curados instantaneamente. O códigoHealCharacter()concluído deve ter a seguinte aparência.~~~(verse) # Cure o personagem e espere um período de tempo HealingDelayAmount. #Termina quando a vida do personagem atingir HealingThreshold # ou o personagem sai de HealVolume. HealCharacter(AgentToHeal:agent, Navigatable:navigatable, Focusable:focus_interface)
:void= # Apenas cure o personagem se ele estiver dentro de HealVolume if: HealVolume.IsInVolume[AgentToHeal] CharacterToHeal := AgentToHeal.GetFortCharacter[] then: Print("O personagem está no volume, iniciando a cura") NavigationTarget := MakeNavigationTarget(AgentToHeal) branch: Navigatable.NavigateTo(NavigationTarget) Focusable.MaintainFocus(AgentToHeal) VFXSpawner.Enable() defer: VFXSpawner.Disable() race: loop: CurrentHealth := CharacterToHeal.GetHealth() if(CurrentHealth + HealingAmount > HealingThreshold): if (CurrentHealth < HealingThreshold): CharacterToHeal.SetHealth(HealingThreshold) PrintNPCB("O personagem atingiu HealingThreshold, interrompendo a cura") break else: CharacterToHeal.SetHealth(CurrentHealth + HealingAmount) Sleep(HealingDelay) HealVolume.AgentExitsEvent.Await() ~~~ -
De volta a
OnBegin(), na expressãothendentro doloop, chameHealCharacter()passandoAgentToHeal, a interfaceNavigatablee a interfaceFocusable.~~~(verse) if: DequeueResult := AgentsToHeal.Dequeue[] set AgentsToHeal = DequeueResult(0) AgentToHeal := DequeueResult(1) then: Print("O próximo agente a ser curado saiu da fila") HealCharacter(AgentToHeal, Navigatable, Focusable) ~~~
-
Seu paramédico nem sempre terá um personagem para curar perto dele, e a função
Dequeue[]falhará se não houver agentes na filaAgentsToHeal. Para lidar com isso, adicione uma instruçãoelseao final deloop. Dentro dessa instruçãoif, chameSleep()por um período de tempo igual aHealingDelaye, em seguida, aguarde comAwait()atéHealVolume.AgentEntersEvent. Dessa forma, o personagem paramédico não chamaráDequeue[]indefinidamente na filaAgentsToHeale, em vez disso, aguardará até que um novo personagem entre emHealVolumeantes de reiniciar o loop. O loop concluído deve ter a seguinte aparência.~~~(verse) loop: # Faça com que o próximo agente da fila seja curado. Se houver um agente para curar, cure-o chamando AgentToHeal. # Se não houver agentes para curar, espere até que um agente entre em HealVolume if: DequeueResult := AgentsToHeal.Dequeue[] set AgentsToHeal = DequeueResult(0) AgentToHeal := DequeueResult(1) then: Print("O próximo agente a ser curado saiu da fila") HealCharacter(AgentToHeal, Navigatable, Focusable) else: Print("AgentsToHeal está vazio!") Sleep(HealingDelay) HealVolume.AgentEntersEvent.Await() ~~~
Rastreie quando os personagens estão no volume de cura
Para saber quando os personagens entram em HealVolume ou saem dele, você assinará AgentEntersEvent e AgentExitsEvent de HealVolume para novas funções.
-
Adicione uma nova função chamada
OnAgentEnters()à definição da classemedic_example. Essa função usa o agente que acabou de entrar emHealVolumee o coloca na filaAgentsToHeal.~~~(verse) OnAgentEnters(EnteredAgent:agent):void= Print("O agente entrou no volume de cura") ~~~
-
Em
OnAgentEnters(), verifique se o agente no volume não é o personagem paramédico. Nesse caso, defina a filaAgentsToHealcomo o resultado da chamada deEnqueue[]comEnteredAgent. A funçãoOnAgentEnters()concluída deve ter a seguinte aparência:~~~(verse) OnAgentEnters(EnteredAgent:agent):void= Print("O agente entrou no volume de cura") if (EnteredAgent <> GetAgent[]): set AgentsToHeal = AgentsToHeal.Enqueue(EnteredAgent) ~~~
-
Quando um agente sai de
HealVolume, você não precisa removê-lo da filaAgentsToHeal. Isso ocorre porque o loop emOnBegin()já chamaDequeue[]em um loop. No entanto, pode ser necessário executar o código quando um agente sai do volume nos seus exemplos. Nesse caso, você configurará uma função para isso agora. Adicione uma nova função chamadaOnAgentExits()à definição da classemedic_example.~~~(verse) OnAgentExits(ExitAgent:agent):void= Print("O agente saiu do volume de cura") ~~~
-
Em
OnBegin(), assineAgentEntersEventeAgentExitsEventdeHealVolumeemOnAgentEnterseOnAgentExits, respectivamente. Como o processo deve começar desabilitado, este é um bom lugar para chamarDisable()no gerador de personagem.~~~(verse) OnBegin
() :void= Print("Olá, IA!") VFXSpawner.Disable() HealVolume.AgentEntersEvent.Subscribe(OnAgentEnters) HealVolume.AgentExitsEvent.Subscribe(OnAgentExits) ~~~
Mova o volume de cura com o paramédico
Quando o personagem paramédico se move, HealVolume precisa se mover com ele para corresponder à sua posição atual. O mesmo se aplica a VFXSpawner. Para fazer isso, você usará uma nova função DeviceFollowCharacter().
-
Adicione uma nova função chamada
DeviceFollowCharacter()à definição da classemedic_example. Como essa função precisa ser executada de forma assíncrona para atualizar continuamente as posições dos dispositivos, adicione o modificador<suspends>a ela.~~~(verse) DeviceFollowCharacter()
:void= ~~~ -
Dentro da função
DeviceFollowCharacter(), obtenha ofort_characterdo médico, obtendo primeiro o agente com o uso deGetAgent[]e depois chamandoGetFortCharater[].~~~(verse) DeviceFollowCharacter()
:void= if: # Obtenha o agente (personagem IA) ao qual este comportamento está associado. Agent := GetAgent[] # Obtenha a interface "fort_character" do agente para acessar comportamentos, eventos, funções e interfaces específicos do personagem do Fortnite. Character := Agent.GetFortCharacter[] ~~~ -
Agora, você precisa mover
HealVolumeeVFXSpawnercontinuamente para a posição deCharacter. Para isso, faça o loop deMoveTo()em ambos os dispositivos. Inicie umloop, obtenha a transformação deCharactere salve-a em uma variávelCharacterTransform.~~~(verse) if: # Obtenha o agente (personagem IA) ao qual este comportamento está associado. Agent := GetAgent[] # Obtenha a interface "fort_character" do agente para acessar comportamentos, eventos, funções e interfaces específicos do personagem do Fortnite. Character := Agent.GetFortCharacter[] then: loop: CharacterTransform := Character.GetTransform() ~~~
-
Chame
MoveTo()emVFXSpawnereHealVolume, movendo-os atéCharacterTransform.TranslationeCharacterTransform.Rotation. Defina a duração comoUpdateRateSecondssegundos. Por último, chameSleep()por um período de tempo deUpdateRateSecondspara evitar que os dispositivos atualizem suas posições a cada atualização da simulação. Atualizar a posição do dispositivo a cada atualização de simulação pode causar movimentos instáveis nos seus dispositivos. Seu códigoDeviceFollowCharacter()concluído deve ter a seguinte a aparência.~~~(verse) DeviceFollowCharacter()
:void= if: # Obtenha o agente (personagem IA) ao qual este comportamento está associado. Agent := GetAgent[] # Obtenha a interface "fort_character" do agente para acessar comportamentos, eventos, funções e interfaces específicos do personagem do Fortnite. Character := Agent.GetFortCharacter[] then: loop: CharacterTransform := Character.GetTransform() VFXSpawner.MoveTo(CharacterTransform.Translation, CharacterTransform.Rotation, UpdateRateSeconds) HealVolume.MoveTo(CharacterTransform.Translation, CharacterTransform.Rotation, UpdateRateSeconds) Sleep(UpdateRateSeconds) ~~~ -
Em
OnBegin(), após a instruçãoifem que você salva suas interfaces de personagem, mas antes do loop, gere uma instância deDeviceFollowCharacter().
Como adicionar seu personagem ao nível
-
Crie uma nova definição de personagem PNJ chamada Médico. Clique na sua nova definição de personagem PNJ para abrir a tela Definição de personagem PNJ.
-
Na tela Definição de Personagem PNJ, modifique as seguintes propriedades:
-
Em Tipo de Personagem PNJ, defina Tipo como Guarda. A interface de guarda permite acessar funcionalidades específicas do personagem, como eventos para quando o guarda entra em estado de alerta ou suspeita e permite que você contrate guardas como aliados. Guardas também podem equipar armas, enquanto os personagens do tipo personalizado e animais selvagens não. Você também pode alterar o nome do personagem na aba Nome.
-
Em Comportamento do Personagem PNJ, defina Comportamento como Comportamento de Verse. Em seguida, defina o script de comportamento de PNJ como
medic_example. Seu personagem ainda terá acesso à funcionalidade da interface de guarda, mas usará seu script Verse para decidir o que fazer duranteOnBegineOnEnd. -
Na aba Modificadores, em Modificador de geração de guarda, clique na aba Cosmético para alterar a aparência cosmética do seu personagem. Você pode escolher um elemento cosmético preexistente ou habilitar o Character Cosmetic Retargeting (Redirecionamento cosmético de personagem) para usar um modelo personalizado. Observe que apenas guardas e personagens do tipo personalizado podem usar o redirecionamento cosmético de personagem, mas o tipo animais selvagens não. Para obter mais informações sobre modificadores de personagens e quais deles se aplicam a diferentes tipos de personagens, consulte a página Definição de Personagem.
-
-
Salve a definição de personagem PNJ. No Navegador de Conteúdo, arraste a definição de personagem PNJ até o nível. Isso criará automaticamente um novo gerador de personagem e atribuirá a ele sua definição de personagem PNJ.
-
Arraste uma área mutante e um gerador de efeitos visuais até o nível.
-
Selecione o gerador de personagens. No Organizador, em Opções do usuário:
-
Defina Substituição do script AIBehavior como seu script
medic_example. Substituir o scriptAIBehaviorno Organizador permite que você faça referência a dispositivos no nível, e você precisará dessa funcionalidade para atribuir HealVolume e VFXSpawner. -
Defina HealVolume como a área mutante e VFXSpawner como o gerador de efeitos visuais que você colocou no nível.
-
-
Selecione a área mutante. No Organizador, em Opções do usuário, defina Área Visível Durante o Jogo como Verdadeiro. Isso ajudará você a visualizar onde está
HealVolumee como ele se move com o personagem médico. -
Selecione o Gerador de Efeitos Visuais. No Organizador, em Opções do usuário, defina Efeito Visual como um efeito de sua escolha. Este exemplo usa o efeito Bolhas para transmitir cura, mas você pode querer usar algo diferente, como fogos de artifício ou faíscas. Altere o efeito visual para atender às necessidades do seu personagem.
-
Clique em Iniciar sessão na barra de ferramentas do UEFN para testar o nível. Durante o teste do jogo, seu personagem deve curar personagens feridos que entram na área mutante. Ao curar um personagem, o efeito visual deve ser reproduzido, e o médico deve acompanhar e focar no personagem que está sendo curado.
O script completo
Veja a seguir um script completo para um PNJ que cura personagens cujo PV está abaixo de um determinado limite.
medic_example.verse
~~~(verse) using { /Fortnite.com/AI } using { /Fortnite.com/Characters } using { /Fortnite.com/Devices } using { /Verse.org/Colors } using { /Verse.org/Random } using { /Verse.org/Simulation } using { /UnrealEngine.com/Temporary/Diagnostics } using { /UnrealEngine.com/Temporary/SpatialMath }
Um comportamento de PNJ criado com Verse que pode ser usado em uma definição de PNJ ou na substituição de script de comportamento de um Gerador de Personagens.
medic_example
# O tempo de espera antes de curar personagens @editable HealingDelay:float = 1.5
# Quanto curar de personagens por instância de cura @editable HealingAmount:float = 5.0
# Os personagens de volume entram para receber cura. @editable HealVolume:mutator_zone_device = mutator_zone_device{}
# O gerador de efeitos visuais para reproduzir efeitos visuais enquanto personagens estão sendo curados. @editable VFXSpawner:vfx_spawner_device = vfx_spawner_device {}
#O agente a seguir enquanto ele está sendo curado var AgentToFollow:?agent = false
# A fila de agentes para curar no caso de vários agentes entrarem no volume de cura.
var AgentsToHeal
# Usada para especificar com que rapidez atualizar a posição de HealVolume e VFXSpawner
UpdateRateSeconds
OnBegin
if:
# Obtenha o agente (personagem IA) ao qual este comportamento está associado. Agent := GetAgent[]
# Obtenha a interface "fort_character" do agente para acessar comportamentos, eventos, funções e interfaces específicos do personagem do Fortnite. Character := Agent.GetFortCharacter[]
# Obtenha a interface navegável do personagem para definir alvos específicos até os quais esse personagem deve se mover. Navigatable := Character.GetNavigatable[]
# Obtenha "focus_interface" do personagem para definir alvos específicos nos quais ele deverá focar depois de se mover até eles. Focusable := Character.GetFocusInterface[]
then: # Defina HealVolume e VFXSpawner para seguir continuamente o PNJ spawn{DeviceFollowCharacter()} loop: # Faça com que o próximo agente da fila seja curado. Se houver um agente para curar, cure-o chamando AgentToHeal. # Se não houver agentes para curar, espere até que um agente entre em HealVolume if: DequeueResult := AgentsToHeal.Dequeue[] set AgentsToHeal = DequeueResult(0) AgentToHeal := DequeueResult(1) then: PrintNPCB("O próximo agente a ser curado saiu da fila") HealCharacter(AgentToHeal, Navigatable, Focusable) else: PrintNPCB("AgentsToHeal está vazio!") Sleep(HealingDelay) HealVolume.AgentEntersEvent.Await() else: # Se o código falhar aqui, significa que algo falhou ao reunir o agente e suas interfaces PrintNPCB( "Erro no script de comportamento de PNJ na configuração do PNJ", ?Duration := 6.0, ?TextColor := NamedColors.Red )
# Cure o personagem e espere um período de tempo HealingDelayAmount.
#Termina quando a vida do personagem atingir HealingThreshold
# ou o personagem sai de HealVolume.
HealCharacter(AgentToHeal:agent, Navigatable:navigatable, Focusable:focus_interface)
# Apenas cure o personagem se ele estiver dentro de HealVolume if: HealVolume.IsInVolume[AgentToHeal] CharacterToHeal := AgentToHeal.GetFortCharacter[] then: PrintNPCB("O personagem está no volume, iniciando cura") NavigationTarget := MakeNavigationTarget(AgentToHeal) branch: Navigatable.NavigateTo(NavigationTarget) Focusable.MaintainFocus(AgentToHeal) VFXSpawner.Enable() defer: VFXSpawner.Disable() race: loop: CurrentHealth := CharacterToHeal.GetHealth() if(CurrentHealth + HealingAmount > HealingThreshold): if (CurrentHealth < HealingThreshold): CharacterToHeal.SetHealth(HealingThreshold) PrintNPCB("O personagem atingiu HealingThreshold, interrompendo a cura") break else: CharacterToHeal.SetHealth(CurrentHealth + HealingAmount) Sleep(HealingDelay) HealVolume.AgentExitsEvent.Await()
# Define HealVolume e VFXSpawner para acompanhar continuamente o personagem por meio de loops
# Use MoveTo para a posição do personagem.
DeviceFollowCharacter()
# Obtenha a interface "fort_character" do agente para acessar comportamentos, eventos, funções e interfaces específicos do personagem do Fortnite. Character := Agent.GetFortCharacter[] then: # Faça loop de MoveTo em HealVolume e VFXSpawner para corresponder sua posição com o # PNJ loop: CharacterTransform := Character.GetTransform() VFXSpawner.MoveTo(CharacterTransform.Translation, CharacterTransform.Rotation, UpdateRateSeconds) HealVolume.MoveTo(CharacterTransform.Translation, CharacterTransform.Rotation, UpdateRateSeconds) Sleep(UpdateRateSeconds)
# Quando um agente entrar em HealVolume, adicione-o à # fila AgentsToHeal se ele não for o PNJ. OnAgentEnters(EnteredAgent:agent):void= PrintNPCB("O agente entrou no volume de cura") if (EnteredAgent <> GetAgent[]): set AgentsToHeal = AgentsToHeal.Enqueue(EnteredAgent)
# Quando um agente sai de HealVolume, use PrintNPCB no log OnAgentExits(ExitAgent:agent):void= PrintNPCB("O agente saiu do volume de cura")
# O wrapper personalizado que fornece duração e cor padrão. PrintNPCB(Msg:string,?Duration:float = 3.0, ?TextColor:color = NamedColors.Green):void = Print("[new_npc_behavior] {Msg}", ?Color := TextColor, ?Duration := Duration)
# Essa função é executada quando o PNJ desaparece ou é eliminado do mundo.
OnEnd
### queue.verse
~~~(verse)
list(t:type) := class:
Data:t
Next:?list(t)
queue<public>(t:type) := class<internal>:
Elements<internal>:?list(t) = false
Size<public>:int = 0
Enqueue<public>(NewElement:t):queue(t) =
queue(t):
Elements := option:
list(t):
Data := NewElement
Next := Elements
Size := Size + 1
Dequeue<public>()<decides><transacts>:tuple(queue(t), t) =
List := Elements?
(queue(t){Elements := List.Next, Size := Size - 1}, List.Data)
Front<public>()<decides><transacts>:t = Elements?.Data
CreateQueue<public><constructor>(InData:t where t:type) := queue(t):
Elements := option:
list(t):
Data := InData
Next := false
Size := 1
Por conta própria
Ao concluir este guia, você aprendeu a criar um personagem paramédico que cura personagens automaticamente abaixo de um determinado limite. Usando o que aprendeu, tente criar seu próprio personagem paramédico com comportamentos especiais.
-
Você pode criar um paramédico que alterna entre volumes de dano e cura com base na presença de um inimigo no volume.
-
Que tal um paramédico que usa um recurso esgotável para curar personagens? Como o paramédico restauraria esse recurso? Ele poderia restaurá-lo com o passar do tempo ou restaurá-lo atacando inimigos?