Mover Entities

Como mover, rodar e dimensionar uma entity gradualmente ao longo do tempo, com alterações incrementais.

Para mover, rodar ou redimensionar uma entidade na sua cena ao longo de um período de tempo, use o Tween componente. O engine realiza a transformação desejada de forma suave, atualizando a cada frame até que a duração especificada termine. Também os Transform valores do componente da entidade afetada são atualizados em tempo real caso seja necessário fazer verificações de proximidade no código da cena.

circle-info

💡 Dica: No Scene Editor in Creator Hubarrow-up-right, você pode mover entidades de forma no-code via Actions, veja Make any item smartarrow-up-right.

O componente Tween possui as seguintes funções:

  • setMove: Mover entre dois pontos

  • setRotate: Rodar entre duas direções

  • setScale: Escalar entre dois tamanhos

  • setMoveRotateScale: Transicionar simultaneamente em todos os três parâmetros

  • setMoveContinuous: Mover constantemente na mesma direção

  • setRotateContinuous: Rodar constantemente na mesma direção

  • setTextureMove: Deslocar a textura de um material entre duas posições

  • setTextureMoveContinuous: Deslocar a textura de um material constantemente na mesma direção

Mover entre dois pontos

Para mover uma entidade entre dois pontos, crie um Tween componente com a setMove função.

const myEntity = engine.addEntity()
Transform.create(myEntity, {
	position: Vector3.create(4, 1, 4),
})
MeshRenderer.setBox(myEntity)

Tween.setMove(myEntity, 
	Vector3.create(1, 1, 1), 
	Vector3.create(8, 1, 8), 
	2000
)

A tween de movimento recebe as seguintes informações:

  • entity: A entidade a mover

  • start: Um Vector3 para a posição inicial

  • end: Um Vector3 para a posição final

  • duration: Quantos milissegundos leva para mover entre as duas posições

Estes outros parâmetros opcionais também estão disponíveis:

  • faceDirection: Se true, a entidade é rotacionada para olhar na direção do movimento.

  • easingFunction: Qual função de easing usar. Veja Non-linear tweens

Rodar entre duas direções

Para rodar uma entidade entre duas posições, crie um Tween componente com a setRotate função.

A tween de rotação recebe as seguintes informações:

  • start: Um Quaternion para a rotação inicial

  • end: Um Quaternion para a rotação final

  • duration: Quantos milissegundos leva para mover entre as duas posições

Este outro parâmetro opcional também está disponível:

Rodar com um ponto de pivô

Ao rodar uma entidade, a rotação é sempre em referência à coordenada central da entidade. Para rodar uma entidade usando outro conjunto de coordenadas como ponto de pivô, crie uma segunda entidade (invisível) com o ponto de pivô como sua posição e torne-a pai da entidade que você deseja rotacionar.

Ao rodar a entidade pai, seus filhos serão todos rotacionados usando a posição do pai como ponto de pivô. Note que a position da entidade filha está em referência à da entidade pai.

Note que neste exemplo, o sistema está rotacionando a pivotEntity entidade, que é pai da childEntity entidade.

Escalar entre dois tamanhos

Para alterar a escala de uma entidade entre dois tamanhos, crie um Tween componente com seu modo definido como Tween.Mode.Scale.

A tween de escala recebe as seguintes informações:

  • start: Um Vector3 para o tamanho inicial

  • end: Um Vector3 para o tamanho final

  • duration: Quantos milissegundos leva para mover entre as duas posições

Este outro parâmetro opcional também está disponível:

Non-linear tweens

Tweens podem seguir diferentes Easing Functions que afetam a taxa de mudança ao longo do tempo. Uma linear função significa que a velocidade da mudança é constante do início ao fim. Existem muitas opções para escolher, que desenham curvas de formas diferentes dependendo se o começo e/ou o fim iniciam devagar, e o quanto. Uma easeinexpo curva começa devagar e termina rápida, aumentando a velocidade exponencialmente, ao contrário de uma easeoutexpo curva que começa rápida e termina devagar.

circle-info

💡 Dica: Experimente diferentes curvas de movimento. As diferenças são muitas vezes sutis, mas nós subconscientemente interpretamos informações de como as coisas se movem, como peso, atrito ou até personalidade.

O parâmetro opcional easingFunction toma seu valor do EasingFunction enum, que oferece as seguintes opções:

  • EF_EASEBACK

  • EF_EASEBOUNCE

  • EF_EASECIRC

  • EF_EASECUBIC

  • EF_EASEELASTIC

  • EF_EASEEXPO

  • EF_EASEINBACK

  • EF_EASEINBOUNCE

  • EF_EASEINCIRC

  • EF_EASEINCUBIC

  • EF_EASEINELASTIC

  • EF_EASEINEXPO

  • EF_EASEINQUAD

  • EF_EASEINQUART

  • EF_EASEINQUINT

  • EF_EASEINSINE

  • EF_EASEOUTBACK

  • EF_EASEOUTBOUNCE

  • EF_EASEOUTCIRC

  • EF_EASEOUTCUBIC

  • EF_EASEOUTELASTIC

  • EF_EASEOUTEXPO

  • EF_EASEOUTQUAD

  • EF_EASEOUTQUART

  • EF_EASEOUTQUINT

  • EF_EASEOUTSINE

  • EF_EASEQUAD

  • EF_EASEQUART

  • EF_EASEQUINT

  • EF_EASESINE

  • EF_LINEAR

Rotação constante

Para fazer uma entidade girar constantemente, use o Tween componente com a setRotateContinuous função.

A tween de rotação contínua recebe as seguintes informações:

  • entity: A entidade a rotacionar

  • direction: Um Quaternion para a rotação

  • speed: Quantos graus por segundo a entidade irá girar

Este outro parâmetro opcional também está disponível:

  • duration: Quantos milissegundos sustentar a rotação. Após esse tempo, a rotação irá parar.

Movimento constante

Para fazer uma entidade mover-se constantemente na mesma direção, use o Tween componente com a setMoveContinuous função.

A tween de movimento contínuo recebe as seguintes informações:

  • entity: A entidade a mover

  • direction: Um Vector3 para o movimento

  • speed: Quantos metros por segundo a entidade irá mover-se

Este outro parâmetro opcional também está disponível:

  • duration: Quantos milissegundos sustentar o movimento. Após esse tempo, o movimento irá parar.

A tween de movimento contínuo recebe as seguintes informações:

Sequências de Tween

Para fazer uma entidade executar uma série de tweens em sequência, use o TweenSequence componente. Este componente requer dois campos:

  • sequence: Um array com múltiplas definições de tween, que serão realizadas sequencialmente. O array pode estar vazio, caso em que apenas toca o tween atual.

  • loop (opcional): Se não fornecido, a sequência é tocada apenas uma vez. Se o campo estiver presente, o valor deve ser um valor do TweenLoop enum. Valores aceitos são:

    • TL_RESTART: Quando a sequência terminar, ela reinicia. Se o estado final não corresponder ao estado inicial, a entidade salta instantaneamente de um para o outro.

    • TL_YOYO: Quando a sequência terminar, ela volta para trás, executando todos os tweens em reverso até alcançar o início novamente. Então começa mais uma vez.

Mover para frente e para trás

Para fazer uma plataforma mover-se constantemente para frente e para trás entre duas posições, deixe o sequence array vazio, e defina loop para TweenLoop.TL_YOYO

A entidade moverá-se para frente e para trás entre o ponto inicial e o ponto final, com a mesma duração e a mesma função de easing em ambas as direções.

Seguir um caminho

Para fazer uma entidade seguir um caminho mais complexo com múltiplos pontos, forneça uma lista de definições de tween no sequence de um TweenSequence componente.

Note que ao definir um tween dentro de um TweenSequence, você precisa usar o formato mais verboso de Tween.Mode.Move, ou Tween.Mode.Rotate, ou Tween.Mode.Scale para definir o tween. Neste formato mais verboso, você precisa especificar:

  • duration: Quantos milissegundos leva para mover entre as duas posições

  • easingFunction: Qual função de easing usar. Veja Non-linear tweens. Neste formato o valor é obrigatório.

  • mode: O modo do tween, que pode ser Tween.Mode.Move, Tween.Mode.Rotate, ou Tween.Mode.Scale.

E dentro do campo mode você precisa especificar:

  • start: O valor inicial do tween

  • end: O valor final do tween

Ao término do tween

Use tweenSystem.tweenCompleted para detectar quando um tween terminou. Isso pode ser útil para executar ações quando um tween terminar, por exemplo para abrir a porta de um elevador.

Tweens simultâneos

Para mover, rodar e escalar uma entidade entre um estado inicial e um estado final, crie uma Tween componente com a setMoveRotateScale função. Esta função também pode ser usada em qualquer combinação desses três parâmetros.

A tween de movimento recebe as seguintes informações:

  • entity: A entidade a mover

  • params: Um objeto com vários parâmetros opcionais

    • position: Um objeto com um start e end value, ambos como Vector3.

    • rotation: Um objeto com um start e end value, ambos como Quaternion.

    • scale: Um objeto com um start e end value, ambos como Vector3.

    • duration: Quantos milissegundos leva para transicionar entre os dois conjuntos de valores

    • easingFunction: Qual função de easing usar. Veja Non-linear tweens

Uma entidade só pode ter um Tween componente, e cada componente tween só pode executar uma transformação de cada vez. Através do setMoveRotateScale tween type, você pode fazer uma entidade mover-se lateralmente e também rotacionar ao mesmo tempo, mas ambos os movimentos seguirão a mesma linha do tempo. Se você precisar que as transições sejam independentes entre si, como solução alternativa, você pode usar entidades com hierarquia de pai/filho. Por exemplo, você pode ter uma entidade pai invisível que se move lateralmente, com um filho visível que rotaciona.

No snippet a seguir, uma entidade pai rotaciona enquanto uma filha aumenta de escala.

Pausar um tween

Para pausar um tween, altere a propriedade playing para false. Para retomá-lo, altere de volta para true.

Para encerrar um tween que não precisa continuar, apague o Tween componente da entidade. Se a entidade também estava usando um TweenSequence componente, apague esse também.

Tweens baseados em um sistema

Ao invés de usar o componente Tween e deixar o engine tratar da transformação, você pode preferir fazer essa transição incrementalmente, frame a frame, via um systemarrow-up-right na sua cena. Movendo a entidade uma pequena quantidade cada vez que a função roda.

Por um lado, isso lhe dá mais controle para recalcular movimentos em cada frame. Por outro lado, o código fica mais complicado, e jogadores com máquinas menos performáticas podem experimentar o tween como travado, notando cada incremento.

Mover via system

A maneira mais fácil de mover uma entidade é modificar gradualmente o valor position armazenado no Transform componente.

Neste exemplo estamos movendo uma entidade 0.1 metros por tick do loop do jogo.

Vector3.Forward() retorna um vetor que aponta para frente e mede 1 metro de comprimento. Neste exemplo estamos então escalando este vetor para 1/10 de seu comprimento com Vector3.scale(). Se nossa cena tiver 30 frames por segundo, a entidade está movendo-se a 3 metros por segundo de velocidade.



Rodar via system

A maneira mais fácil de rodar uma entidade é alterar gradualmente os valores no componente Transform incrementalmente, e executar isso como parte da função de um system.

Note que para combinar a rotação atual com cada incremento, estamos usando Quaternion.multiply. Em matemática de quaternions, você combina duas rotações multiplicando-as, NÃO somando-as. A rotação resultante de multiplicar um quaternion por outro será a rotação final equivalente após primeiro executar uma rotação e depois a outra.

Neste exemplo, estamos rotacionando a entidade em 1 grau na direção para cima em cada tick do loop do jogo.

circle-info

💡 Dica: Para fazer uma entidade sempre rotacionar para olhar o jogador, você pode adicionar um Billboard componentearrow-up-right.



Rodar via system sobre um ponto de pivô

Ao rodar uma entidade, a rotação é sempre em referência à coordenada central da entidade. Para rodar uma entidade usando outro conjunto de coordenadas como ponto de pivô, crie uma segunda entidade (invisível) com o ponto de pivô como sua posição e torne-a pai da entidade que você deseja rotacionar.

Ao rodar a entidade pai, seus filhos serão todos rotacionados usando a posição do pai como ponto de pivô. Note que a position da entidade filha está em referência à da entidade pai.

Note que neste exemplo, o sistema está rotacionando a pivotEntity entidade, que é pai da childEntity entidade.



Ajustar movimento para tempo de atraso

Suponha que o jogador visitando sua cena esteja lutando para acompanhar o ritmo da taxa de frames. Isso poderia resultar no movimento parecendo irregular, pois nem todos os frames são cronometrados igualmente mas cada um move a entidade pela mesma quantidade.

Você pode compensar esse tempo desigual usando o dt parâmetro para ajustar a escala do movimento.

O exemplo acima mantém o movimento aproximadamente na mesma velocidade que o exemplo de movimento acima, mesmo se a taxa de frames cair. Ao rodar a 30 frames por segundo, o valor de dt é 1/30.

Você também pode suavizar rotações da mesma forma multiplicando a quantidade de rotação por dt.

Mover entre dois pontos via system

Se você quiser que uma entidade se mova suavemente entre dois pontos, use o lerp (interpolação linear) algoritmo. Este algoritmo é muito conhecido no desenvolvimento de jogos, pois é realmente útil.

A lerp() função recebe três parâmetros:

  • O vetor para a posição de origem

  • O vetor para a posição alvo

  • A quantidade, um valor de 0 a 1 que representa que fração da translação fazer.

O algoritmo de interpolação linear encontra um ponto intermediário no caminho entre ambos os vetores que corresponde à quantidade fornecida.

Por exemplo, se o vetor de origem for (0, 0, 0) e o vetor alvo for (10, 0, 10):

  • Usando uma quantidade de 0 retornaria (0, 0, 0)

  • Usando uma quantidade de 0.3 retornaria (3, 0, 3)

  • Usando uma quantidade de 1 retornaria (10, 0, 10)

Para implementar isto lerp() na sua cena, recomendamos criar um componente customizadoarrow-up-right para armazenar a informação necessária. Você também precisa definir um system que implemente o movimento gradual em cada frame.



Rodar entre dois ângulos via system

Para rodar suavemente entre dois ângulos, use o slerp (esférica interpolação linear) algoritmo. Este algoritmo é muito similar a um lerp, mas ele lida com rotações em quaternion.

A slerp() função recebe três parâmetros:

circle-info

💡 Dica: Você pode passar valores de rotação em eulerarrow-up-right graus (de 0 a 360) usando Quaternion.fromEulerDegrees().

Para implementar isto na sua cena, recomendamos armazenar os dados que entram na função Slerp() em um componente customizadoarrow-up-rightcomponente. Você também precisa definir um system que implemente a rotação gradual em cada frame.

circle-exclamation


Uma abordagem mais simples mas menos eficiente para isto aproveita a Quaternion.rotateTowards função, e evita usar quaisquer componentes personalizados.

No exemplo acima Quaternion.rotateTowards leva três argumentos: a rotação inicial, a rotação final desejada e o incremento máximo por quadro. Neste caso, como o incremento máximo é de dt * 10 graus, a rotação será realizada ao longo de um período de alguns 9 segundos.

Note que o sistema também verifica se a rotação está completa e, se estiver, remove o sistema do engine. Caso contrário, o sistema continuaria fazendo cálculos em cada quadro, mesmo depois que a rotação estivesse completa.

Alterar escala entre dois tamanhos via system

Se você quer que uma entidade mude de tamanho suavemente e sem alterar suas proporções, use o lerp (interpolação linear) algoritmo do Scalar objeto.

Caso contrário, se você quiser alterar os eixos em proporções diferentes, use Vector3 para representar a escala de origem e a escala alvo, e então use a lerp função do Vector3.

A lerp() função do Scalar objeto recebe três parâmetros:

  • Um número para a escala de origem

  • Um número para a escala alvo

  • A quantidade, um valor de 0 a 1 que representa qual fração da escala aplicar.

Para implementar este lerp na sua cena, recomendamos criar um componente personalizado para armazenar a informação necessária. Você também precisa definir um system que implemente o escalonamento gradual em cada quadro.



Mover em velocidades irregulares entre dois pontos via system

Ao usar o método lerp, você pode tornar a velocidade de movimento não linear. No exemplo anterior incrementamos a quantidade do lerp por um valor dado a cada quadro, mas também poderíamos usar uma função matemática para aumentar o número exponencialmente ou em outras medidas que deem um ritmo de movimento diferente.

Você também poderia usar uma função que dê resultados recorrentes, como uma função seno, para descrever um movimento que vai e volta.

Frequentemente essas transições não lineares podem trazer muita vida a uma cena. Um movimento que acelera seguindo uma curva ou que desacelera gradualmente pode dizer muito sobre a natureza de um objeto ou personagem. Você pode até aproveitar funções matemáticas que adicionam efeitos de quique.

O exemplo acima é igual ao exemplo linear de lerp que mostramos antes, mas o fraction campo mapeado para um valor não linear a cada tick. Esse valor não linear é usado para calcular a lerp função, resultando em um movimento que segue uma curva exponencial.

Você também pode mapear uma transição em rotação ou em escala da mesma forma que mostrado acima, mapeando uma transição linear para uma curva.



Seguir um caminho via system

Você pode fazer uma entidade percorrer um array de vetores, realizando um movimento lerp entre cada um para seguir um caminho mais complexo.

O exemplo acima define um caminho 3D composto por quatro vetores 3D. O PathTransportData componente personalizado contém os mesmos dados usados pelo componente personalizado no lerp exemplo acima, mas adiciona um path array, com todos os pontos do nosso caminho, e um pathTargetIndex campo para acompanhar qual segmento do caminho está sendo usado atualmente.

O sistema é muito similar ao sistema no lerp exemplo, mas quando uma ação de lerp é concluída, ele define os target e origin campos para novos valores. Se alcançarmos o final do caminho, retornamos ao primeiro valor do caminho.



Texture tweens

Para fazer uma textura deslizar suavemente, use o Tween componente com a setTextureMove função.

O texture tween recebe as seguintes informações:

  • entity: A entidade cuja textura será movida

  • start: Um Vector2 para a posição inicial

  • end: Um Vector2 para a posição final

  • duration: Quantos milissegundos leva para mover entre as duas posições

Este outro parâmetro opcional também está disponível:

  • movementType: (opcional), define se o movimento será no campo offset ou no campo tiling. Por padrão usa offset.

  • easingFunction: Qual função de easing usar. Veja Non-linear tweens. Nota: Este parâmetro é usado apenas se uma duração for fornecida.

Movimento constante de textura

Para fazer uma textura deslizar constantemente, use o Tween componente com a setTextureMoveContinuous função.

O texture continuous tween recebe as seguintes informações:

  • entity: A entidade cuja textura será movida

  • direction: Um Vector2 para o movimento

  • speed: Quantas unidades por segundo a entidade irá mover

Este outro parâmetro opcional também está disponível:

  • movementType: define se o movimento será no campo offset ou no campo tiling. Por padrão usa offset.

  • duration: Quantos milissegundos sustentar o movimento. Após esse tempo, o movimento irá parar.

Leia mais sobre texture tweens em Texture Tweensarrow-up-right seção.

Atualizado