Você pode criar seus próprios componentes usando Verse para adicionar às suas entidades. Com componentes do Verse personalizados, você pode gerar e remover entidades da cena, adicionar ou remover componentes de entidades, criar seus próprios comportamentos, como o desaparecimento de uma entidade em loop ou o que você puder imaginar!
Como criar um novo componente Verse
Você pode criar um novo componente Verse usando o arquivo de modelo Verse.
Para criar um componente Verse:
No painel Detalhes da sua entidade, escolha Adicionar componente, Novo componente Verse.
Você também pode criar um novo componente Verse adicionando um novo arquivo Verse com o Explorador do Verse.
Na lista de modelos de código Verse, escolha Componente do Scene Graph.
Defina o nome do componente como o nome do seu componente criado em Verse. Neste exemplo, o nome do componente é
my_verse_component.Clique em Criar para criar o arquivo do componente Verse. Seu componente criado em Verse agora aparece na lista de componentes ao escolher adicionar um componente à sua entidade.
Você só pode adicionar um de uma determinada classe ou subclasse de componente. Por exemplo, você só pode ter um mesh_component em uma entidade. Isso se estende a subclasses de componentes, ou seja, se você adicionar um capsule_light_component à sua entidade, não poderá adicionar também um rect_light_component, pois ambos são subclasses de light_component. Essa limitação também se aplica aos seus componentes personalizados criados em Verse.
Duração do componente
À medida que são adicionados à cena, entidades e começam a ser executados na simulação, os componentes são movidos ao longo de uma série de funções de tempo de vida. Seus componentes criados em verse devem substituir esses métodos para a configuração e execução da simulação.
Ao ser desativado, o componente será movido ao longo da versão de desativação das funções, o que dá chance de limpar qualquer estado mantido no componente antes de sua remoção.
Confira a seguir os estados de tempo de vida do componente:
Inicializado
AddedToScene
BeginSimulation
EndSimulation
RemovingFromScene
Cancelando inicialização
As funções de tempo de vida de componentes são diferentes do tempo de vida de dispositivos. A lógica do componente é executada tanto no modo de edição quanto no de jogo. Qualquer comportamento adicionado será executado imediatamente ao inicializar a sessão. Se você quiser que seu componente de lógica seja executado apenas na inicialização do jogo, pode gerar estruturas pré-fabricadas na função OnBegin() de um dispositivo Verse.
Como consultar entidades e componentes com Verse
Há várias maneiras de encontrar entidades e componentes no seu código Verse. A maneira como você estrutura suas entidades e componentes afeta como consultar e desenvolver funcionalidades no seu código Verse.
Consultando por entidades e componentes no Verse, você precisa começar com uma entidade e retornar entidades aninhadas acima ou abaixo dela na hierarquia. Você pode consultar o pai ou os filhos diretos de uma entidade, bem como todas as suas entidades pais e descendentes.
Obtenha entidades com o tipo de componente
Você pode encontrar todas as entidades que possuem um componente de tipo específico ao chamar a entidade que deseja consultar. Se a entidade consultada é a entidade de simulação, todas as entidades que possuem componentes desse tipo serão buscadas na cena.
No exemplo a seguir, o componente Verse busca todas as entidades que possuem o componente light_component anexado. Para cada uma das entidades encontradas, ele gera um particle_sytem_component e o anexa a ela. Aqui, BlowingParticles é um emissor do Niagara referenciado no arquivo Assets.digest.Verse.
O light_component é uma superclasse para todos os diferentes botões de componente de luz que você pode adicionar à sua entidade. Na consulta abaixo, LightComponent é usado para encontrar entidades com qualquer tipo de componente de luz neles.
# Runs when the component should start simulating in a running game.
OnBeginSimulation<override>():void =
# Run OnBeginSimulation from the parent class before
# running this component's OnBeginSimulation logic
(super:)OnBeginSimulation()
for:
LightComponent : Entity.GetSimulationEntity[].FindDescendantEntitiesWithComponent(light_component)
do:
# Create a particle system component and add it to the entity.
O próximo exemplo mostra como fazer consultas para todas as entidades que têm sistemas de partículas aninhados sob a entidade à qual o componente Verse está anexado usando a função FindDescendantEntitiesWithComponent(). Da mesma forma, você também pode obter todas as entidades ancestrais com um componente específico usando FindAncestorEntitiesWithComponent().
# Runs when the component should start simulating in a running game.
# Can be suspended throughout the lifetime of the component. Suspensions
# will be automatically canceled when the component is disposed or the
# game ends.
OnSimulate<override>()<suspends>:void=
# Get all entities that have particle system components nested under the entity this component is attached to.
ParticleSystemEntities := Entity.FindDescendantEntitiesWithComponent(particle_system_component)
# Get all entities with particle system components that are ancestors of this entity.
Se você precisar consultar entidades em toda a sua cena, poderá fazer isso obtendo a entidade de simulação e executando suas consultas nela. Isso iniciará a consulta no topo da estrutura da entidade e encontrará todas as entidades aninhadas que corresponderem à consulta. Para acessar a entidade de simulação, chame a função falível GetSimulationEntity[] na entidade à qual o componente Verse está anexado.
# Runs when the component should start simulating in a running game.
# Can be suspended throughout the lifetime of the component. Suspensions
# will be automatically canceled when the component is disposed or the
# game ends.
OnSimulate<override>()<suspends>:void=
# Get the simulation entity.
if:
SimulationEntity := Entity.GetSimulationEntity[]
then:
Ter seu componente Verse vasculhando a árvore da entidade constantemente pode demandar muito processamento. Se seu comportamento depender de uma estrutura de entidade específica, qualquer alteração sutil na estrutura da sua entidade pode causar alterações indesejadas ou interrupção total no comportamento.
Por outro lado, isso também significa que a configuração do componente pode ser mais simples, porque tudo o que você precisa fazer é adicionar seu componente Verse e ter a estrutura correta de entidade. Lembre-se desses prós e contras ao criar suas entidades e desenvolver a lógica do seu componente Verse.
Explore o módulo SceneGraph para descobrir todas as formas de trabalhar com entidades e componentes em Verse. O texto a seguir descreve algumas maneiras comuns de consultar entidades e componentes no seu código.
Obtenha componentes de uma entidade
Você pode usar código Verse para obter um componente de um tipo específico em uma entidade chamando GetComponent[]. Isso é útil na criação de lógica personalizada que depende de outro comportamento de componente. Por exemplo, usar o sound_component para reproduzir áudio dependendo da cor de uma luz, ou obter um particle_system_component para aplicar efeitos dependendo da chance de a entidade estar dentro de uma área específica.
No exemplo a seguir, o componente do Verse faz uma plataforma aparecer e desaparecer repetidamente em um loop. Isso é feito buscando-se o componente de malha da entidade, desabilitando-o e, em seguida, reativando-o após uma duração definida.
using { /Verse.org }
using { /Verse.org/Native }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/SceneGraph }
# A Verse-authored component that can be added to entities.
# This component will make the entity appear and disappear on loop.
disappear_on_loop_component := class<final_super>(component):
# How long in seconds the entity should be hidden.
@editable
Em outro exemplo, o componente do Verse busca o light_component na entidade e altera sua cor para laranja-escuro. O light_component é uma superclasse para todos os tipos de luz que você pode adicionar a entidades, ou seja, este exemplo encontra qualquer componente que seja subclasse dele.
# Runs when the component should start simulating in a running game.
# Can be suspended throughout the lifetime of the component. Suspensions
# will be automatically canceled when the component is disposed or the
# game ends.
OnSimulate<override>()<suspends>:void=
# Find any component on this entity that subclasses from light_component.
if:
LightComponent := Entity.GetComponent[light_component]
then:
Obtendo todos os componentes
Você pode usar a função GetComponents() para retornar todos os componentes na entidade. Como seu código não sabe que tipo de componente são esses, você pode usar a conversão para realizar diferentes operações com base no tipo de cada componente. O exemplo a seguir obtém uma matriz de todos os componentes em uma entidade e tenta convertê-los para o tipo enableable. Se a conversão for bem-sucedida, o componente implementa a interface enableable. Em seguida, ele desabilita cada componente que implementa essa interface.
# Runs when the component should start simulating in a running game.
# Can be suspended throughout the lifetime of the component. Suspensions
# will be automatically canceled when the component is disposed or the
# game ends.
OnSimulate<override>()<suspends>:void=
# Get a list of all components on the entity.
ComponentList := Entity.GetComponents()
for:
Component:ComponentList
Encontre entidades por tags de jogabilidade
Você pode adicionar um componente de tag às suas entidades para encontrar entidades específicas localizadas na sua cena de forma semelhante a adicionar tags de jogabilidade aos seus atores. Serve para escolher as entidades com as quais você deseja trabalhar em vez de depender de elementos inconstantes, como os componentes que elas têm ou a posição delas na cena.
Ocorre porque, ao depender delas, seu jogo pode se comportar de forma inesperada quando você alterar ou adicionar entidades novas ao seu projeto. Você pode adicionar tags no editor adicionando uma tag_component à sua entidade e selecionando as tags no menu suspenso Tags ou no código Verse usando a função AddTag().
O exemplo a seguir consulta a entidade de simulação em busca de todos os descendentes marcados com a tag my_tag em seu tag_component.
# Runs when the component should start simulating in a running game.
# Can be suspended throughout the lifetime of the component. Suspensions
# will be automatically cancelled when the component is disposed or the
# game ends.
OnSimulate<override>()<suspends>:void =
# Get the simulation entity.
if:
SimulationEntity := Entity.GetSimulationEntity[]
then:
Encontre entidades com sobreposições
Os volumes de colisão são volumes que representam as formas de colisão das malhas. Você pode usá-las para consultar objetos sobrepostos em uma forma específica, como danificar objetos se eles chegarem perto demais de uma torre, ou detectar quando uma bola de jogo entra em um objetivo. Em Verse, você pode usar a função FindOverlapHits() para encontrar todas as entidades em uma área específica.
Essa área pode ser a própria entidade, um determinado volume de colisão, como uma esfera ou caixa, ou uma posição para simular a entidade. Ela retornará uma lista de overlap_hit. Cada overlap_hit fornece informações sobre o componente ou a sobreposição de volume pelo volume de origem, e você pode consultar esses componentes para encontrar sua entidade associada.
O exemplo a seguir cria uma esfera com um raio de 256,0 unidades centralizada na transformação da entidade. Em seguida, encontra todas as sobreposições dentro da esfera, retornando uma lista de overlap_hits. Como cada overlap_hit é um componente ou um volume, você pode consultar TargetComponent ou TargetVolume para saber qual é o tipo. Se overlap_hit for um componente, o código obterá a entidade do componente. Por fim, verifica se a entidade possui um componente de luz. Nesse caso, a cor da luz muda para azul. Com um volume grande o suficiente, você muda a cor de todas as luzes da sua ilha com apenas algumas linhas de código!
# Runs when the component should start simulating in a running game.
# Can be suspended throughout the lifetime of the component. Suspensions
# will be automatically canceled when the component is disposed or the
# game ends.
OnSimulate<override>()<suspends>:void=
# Define a volume to find entities within.
# This is a sphere whose radius is 256.
CollisionSphere:collision_sphere = collision_sphere:
Radius := 256.0
Este código simula um volume de "collision_sphere" sobreposto denotado pelo círculo com um raio de 256,0 unidades centralizado na entidade do cubo, retornando quaisquer componentes ou volumes com os quais a esfera se sobreponha. Em seguida, obtém a entidade pai do componente sobreposto e torna todos os componentes de luz azuis. Como o cubo está dentro de "collision_sphere" quando a sobreposição começa, ele será incluído na lista de "overlap_hits" e também ficará azul. Observe que a entidade de cone vermelho mais à direita está fora de "collision_sphere" e, portanto, não sobreporá e ficará azul.
Encontre entidades com varreduras
Outra maneira importante de consultar entidades é por meio de varreduras. Varrer refere-se a mover um objeto ao longo de uma distância definida ao longo de um vetor específico. Por exemplo, mover um bloco através de uma plataforma para empurrar os jogadores para um espaço ou lançar um míssil para frente para destruir uma parede.
Em Verse, você pode simular varreduras para consultar colisões entre objetos usando a função FindSweepHits(). Essa função usa um vetor de deslocamento para simular a varredura de um objeto. Você pode realizar varreduras com a entidade principal ou com um determinado volume de colisão e especificar a transformação global inicial a partir da qual começar a varrer.
A função FindSweepHits() retorna uma lista de sweep_hits. Cada sweep_hit fornece as mesmas informações que um overlap_hit, como a incidência do componente ou volume e o volume ou componente de origem que faz a varredura. Além disso, fornece informações sobre a posição de contato, normal, normal da face e a distância ao longo da varredura onde a ocorrência foi detectada.
O exemplo a seguir usa uma entidade e chamadas FindSweepHit(), passando um vetor com comprimento de 1000,0 para o valor Forward. O código simula quais colisões ocorreriam se a entidade fosse movida 1000,0 unidades na direção positiva para frente e retorna uma lista de sweep_hit.
Como cada sweep_hit é um componente ou um volume, você pode consultar TargetComponent ou TargetVolume para saber qual é o tipo. Se o acerto for um componente, o código então obterá a entidade pai do componente. Por fim, verifica se a entidade possui um componente de luz. Nesse caso, a cor da luz muda para azul.
for:
# Simulate sweeping this entity 1000 units in the positive X direction, and return any components and volumes it overlaps with.
SweepHit : Entity.FindSweepHits(vector3{Left := 0.0, Up := 0.0, Forward := 1000.0}, Entity.GetGlobalTransform(), CollisionBox)
# Check that the overlap is a component, and if so get its parent entity.
# Then if the entity has a light component, change its color filter.
TargetComponent := SweepHit.TargetComponent
TargetEntity := TargetComponent.Entity
LightComponent := TargetEntity.GetComponent[light_component]
do:
Este código simula a varredura da entidade de cubo 1000,0 unidades na direção X positiva, retornando quaisquer componentes com os quais se sobreponha. Em seguida, obtém a entidade pai do componente sobreposto e torna todos os componentes de luz azuis. Observe que a lista de acertos não inclui a entidade que faz a varredura, então o cubo propriamente dito não ficará azul. A entidade de cone vermelho mais à direita também não ficará azul, pois está fora da varredura.
O próximo exemplo é semelhante ao anterior, com a diferença de que primeiro constrói um volume de collision_box e, em seguida, o usa para varrer 1000,0 unidades na direção pra frente positiva, começando no centro da entidade de cubo. Como o cubo está dentro de collision_box quando a verificação começa, ele será incluído na lista de sweep_hits e também ficará azul.
# Define a volume to sweep over entities.
# This box is 1/4th the size of a standard 512x512 grid tile.
CollisionBox:collision_box = collision_box:
Extents := vector3:
Left := 128.0,
Up := 128.0,
Forward := 128.0
for:
# Simulate sweeping the CollisionBox 1000 units in the positive X direction, and return any components and volumes it overlaps with.
SweepHit : Entity.FindSweepHits(vector3{Left := 0.0, Up := 0.0, Forward := 1000.0}, Entity.GetGlobalTransform(), CollisionBox)
Este código simula a verificação de um volume "collision_box" denotado pelo quadrado amarelo de 1000,0 unidades na direção para frente positiva, retornando todos os componentes com os quais se sobrepõe. Em seguida, obtém a entidade pai do componente sobreposto e torna todos os componentes de luz azuis. Como o cubo está dentro de "collision_box" quando a varredura começa, ele será incluído na lista de "sweep_hits" e ficará azul. A entidade cone vermelha mais à direita não ficará azul, pois está fora da varredura.
Como gerar e remover entidades usando Verse
Você pode remover uma entidade da cena chamando RemoveFromParent() na entidade. Você pode adicionar uma entidade à cena, seja nova ou que foi removida anteriormente, chamando AddEntities() na entidade que se tornar a entidade pai.
No exemplo a seguir, o componente Verse encontra todas as entidades marcadas com a tag de jogabilidade my_tag. Ele remove cada entidade encontrada de seu pai, o que remove a entidade da cena e adiciona a mesma entidade de volta ao seu pai após cinco segundos para gerá-la novamente na cena.
# Runs when the component should start simulating in a running game.
# Can be suspended throughout the lifetime of the component. Suspensions
# will be automatically cancelled when the component is disposed or the
# game ends.
OnSimulate<override>()<suspends>:void =
# Find all entities tagged and get their parent entity.
for:
TaggedEntity : Entity.GetSimulationEntity[].FindDescendantEntitiesWithTag(my_tag{})
Parent := TaggedEntity.GetParent[]
Da mesma forma, você pode adicionar componentes a uma entidade chamando AddComponents() e passando a lista de componentes que deseja adicionar. Você também pode remover uma entidade chamando RemoveFromParent() na entidade e pode remover um componente de uma entidade chamando RemoveFromEntity() no componente. Entidades e componentes removidos podem ser readicionados de volta à cena com AddEntities() e AddComponents(), respectivamente. Observe que você não pode alterar a entidade pai dos componentes removidos que adiciona de volta à cena.
Estruturas pré-fabricadas
As estruturas pré-fabricadas que você cria no seu projeto são expostas como uma classe em Verse no arquivo Assets.digest.verse do seu projeto. As entidades e os componentes definidos na sua estrutura pré-fabricada são acessíveis em Verse por meio das chamadas GetEntities() e GetComponents() em uma estrutura pré-fabricada.
Você pode gerar instâncias das suas estruturas pré-fabricadas instanciando a classe de estrutura pré-fabricada e adicioná-las a uma entidade na cena. No exemplo a seguir, o componente Verse cria uma instância da estrutura pré-fabricada, chamada loop_disappearing_platform_prefab no editor, e a adiciona à cena.
# Runs when the component should start simulating in a running game.
# Can be suspended throughout the lifetime of the component. Suspensions
# will be automatically cancelled when the component is disposed or the
# game ends.
OnSimulate<override>()<suspends>:void =
if:
SimulationEntity := Entity.GetSimulationEntity[]
then:
# Create an instance of the disappearing on loop platform from its prefab.
DisappearingPlatform:disappearing_platform_prefab = disappearing_platform_prefab{}
Dicas e práticas recomendadas
Quando estiver criando seus próprios componentes em Verse, lembre-se das dicas e melhores práticas a seguir:
Os componentes Verse que dependem de outros componentes, de modo geral, devem estar na mesma entidade.
Os componentes expõem eventos de marcação pré-física e pós-física, que ocorrem a cada quadro. É útil para quando você precisa realizar alguma lógica antes de aplicar a física, como modificar a transformação, e depois de aplicar, como ler as posições de objetos após a física.
Se não precisar especificamente de eventos pré-física e pós-física, você deve continuar usando as expressões de concorrência Verse para controlar o fluxo de tempo de acordo com uma determinada lógica. Consulte mais detalhes em Fluxo de tempo e simultaneidade.
As funções de tempo de vida de componentes são diferentes do tempo de vida de dispositivos. A lógica do componente é executada tanto no modo de edição quanto no de jogo. Se quiser que a lógica do seu componente seja executada apenas no início do jogo, gere estruturas pré-fabricadas na função
OnBegin()de um dispositivo Verse.