Mover Entities
Como mover, rotacionar e escalar uma entity gradualmente ao longo do tempo, com alterações incrementais.
Para mover, rodar ou redimensionar uma entity na tua scene ao longo de um período de tempo, usa o Tween component. O engine executa a transformação desejada de forma suave, mostrando atualizações em cada frame até terminar a duração especificada. Além disso, os valores do Transform component da entity afetada são atualizados em tempo real, caso seja necessário fazer verificações de proximidade no código da scene.
O component Tween tem as seguintes funções:
setMove: Move entre dois pontossetRotate: Rodar entre duas direçõessetScale: Redimensionar entre dois tamanhossetMoveRotateScale: Faz a transição simultaneamente nos três parâmetrossetMoveContinuous: Move constantemente na mesma direçãosetRotateContinuous: Rodar constantemente na mesma direçãosetTextureMove: Desloca a textura de um Material entre duas posiçõessetTextureMoveContinuous: Desloca continuamente a textura de um Material na mesma direção
Move entre dois pontos
Para mover uma entity entre dois pontos, cria um Tween component com a setMove function.
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
)O tween de movimento recebe as seguintes informações:
entity: A entity a moverstart: Um Vector3 para a posição inicialend: Um Vector3 para a posição finalduration: Quantos milissegundos demora a mover entre as duas posições
Este outro parâmetro opcional também está disponível:
easingFunction: Que easing function usar. Vê Tweens não lineares
Rodar entre duas direções
Para rodar uma entity entre dois pontos, cria um Tween component com a setRotate function.
O tween de rotação recebe as seguintes informações:
start: Um Quaternion para a rotação inicialend: Um Quaternion para a rotação finalduration: Quantos milissegundos demora a mover entre as duas posições
Este outro parâmetro opcional também está disponível:
easingFunction: Que easing function usar. Vê Tweens não lineares
Rodar com um ponto de pivô
Ao rodar uma entity, a rotação é sempre feita em referência à coordenada central da entity. Para rodar uma entity usando outro conjunto de coordenadas como ponto de pivô, cria uma segunda entity (invisível) com o ponto de pivô como posição e torna-a parent da entity que queres rodar.
Ao rodar a entity pai, as suas children serão todas rodadas usando a posição do pai como ponto de pivô. Nota que a position da child entity faz referência à da parent entity.
Nota que, neste exemplo, o system está a rodar a pivotEntity entity, que é parent da childEntity entity.
Redimensionar entre dois tamanhos
Para alterar a escala de uma entity entre dois tamanhos, cria um Tween component com a setScale function.
O tween de scale recebe as seguintes informações:
start: Um Vector3 para o tamanho inicialend: Um Vector3 para o tamanho finalduration: Quantos milissegundos demora a mover entre as duas posições
Este outro parâmetro opcional também está disponível:
easingFunction: Que easing function usar. Vê Tweens não lineares
Mover a partir da posição atual
Enquanto um tween está ativo, o engine atualiza os valores do Transform component da entity em tempo real. Isto significa que podes ler a posição atual da entity a partir do seu Transform component a qualquer momento, e usar esse valor como o start de um novo tween. A entity então move-se de onde quer que esteja atualmente até ao alvo, independentemente de como lá chegou.
📔 Nota: Passa sempre um start valor explícito. Se o start parâmetro for deixado por definir, é tratado como (0, 0, 0), por isso a entity teleporta-se para a origem da scene antes de se mover. Da mesma forma, se passares um start que não corresponda à posição atual da entity, a entity teleporta-se visivelmente para essa posição antes de se mover. Lê a posição atual a partir do Transform component, como nos exemplos desta secção, sempre que quiseres que o movimento comece de onde a entity está atualmente.
Redirecionar durante o trajeto
Ao chamar setMove (ou qualquer uma das outras funções tween) numa entity que já tem um tween em execução, substitui o tween em execução pelo novo. Como o start é lido a partir da posição em tempo real da entity, isto redireciona a entity de forma suave a meio do trajeto: muda de direção a partir de onde quer que esteja nesse momento, sem quaisquer saltos.
O exemplo abaixo move uma entity para o pad em que o player clicar. Se o player clicar noutro pad enquanto a entity ainda estiver em trajeto, a entity muda de direção suavemente em direção ao novo alvo.
Para executar lógica quando a entity chega ao destino, vê Ao terminar o tween.
📔 Nota: Redireciona desta forma apenas em resposta a eventos ocasionais, como um click ou ao alcançar um waypoint. Se o alvo mudar constantemente, por exemplo uma entity que segue o player, não cries um novo tween em cada frame: a entity vai tremer visivelmente. Vê Seguir um alvo em movimento.
Tweens não lineares
Tweens podem seguir diferentes Easing Functions que afetam a taxa de alteração ao longo do tempo. Uma linear function significa que a velocidade da alteração é constante do início ao fim. Há muitas opções para escolher, que desenham curvas com formatos diferentes dependendo de se o início e/ou o fim começam devagar, e em que medida. Uma easeinexpo curve começa devagar e termina rápido, aumentando a velocidade exponencialmente; pelo contrário, uma easeoutexpo curve começa rápido e termina devagar.
O opcional easingFunction parâmetro obtém o seu valor a partir da EasingFunction enum, que oferece as seguintes opções:
EF_EASEBACKEF_EASEBOUNCEEF_EASECIRCEF_EASECUBICEF_EASEELASTICEF_EASEEXPOEF_EASEINBACKEF_EASEINBOUNCEEF_EASEINCIRCEF_EASEINCUBICEF_EASEINELASTICEF_EASEINEXPOEF_EASEINQUADEF_EASEINQUARTEF_EASEINQUINTEF_EASEINSINEEF_EASEOUTBACKEF_EASEOUTBOUNCEEF_EASEOUTCIRCEF_EASEOUTCUBICEF_EASEOUTELASTICEF_EASEOUTEXPOEF_EASEOUTQUADEF_EASEOUTQUARTEF_EASEOUTQUINTEF_EASEOUTSINEEF_EASEQUADEF_EASEQUARTEF_EASEQUINTEF_EASESINEEF_LINEAR
Rotação constante
Para fazer uma entity rodar constantemente, usa o Tween component com a setRotateContinuous function.
O tween de rotação contínua recebe as seguintes informações:
entity: A entity a rodardirection: Um Quaternion que determina o eixo em torno do qual rodar. Apenas o eixo desta rotação importa, o tamanho do seu ângulo é ignorado. Por exemplo,Quaternion.fromEulerDegrees(0, -1, 0)eQuaternion.fromEulerDegrees(0, -90, 0)comportam-se da mesma forma, ambos rodando em torno do y eixo numa direção negativa.speed: Quantos graus por segundo a entity irá rodar. Um valor negativo roda na direção oposta.
Este outro parâmetro opcional também está disponível:
duration: Quantos milissegundos manter a rotação. Após esse tempo, a rotação para.
Movimento constante
Para fazer uma entity mover-se constantemente na mesma direção, usa o Tween component com a setMoveContinuous function.
O tween de movimento contínuo recebe as seguintes informações:
entity: A entity a moverdirection: Um Vector3 para o movimentospeed: Quantos metros por segundo a entity irá mover-se
Este outro parâmetro opcional também está disponível:
duration: Quantos milissegundos manter o movimento. Após esse tempo, o movimento para.
O tween de movimento contínuo recebe as seguintes informações:
Seguir um alvo em movimento
setMoveContinuous também é a ferramenta certa quando o destino continua a mudar, por exemplo uma entity que segue o player. É tentador, em vez disso, criar um novo setMove tween em cada frame, apontado para a posição mais recente do player, mas isso produz um tremor visível.
A razão é que a posição que lês a partir do Transform component de uma entity com tween é a posição que o engine comunicou pela última vez à scene, por isso fica atrasada alguns frames em relação ao local onde a entity realmente está. Quando passas esse valor como o start de um novo tween, o engine aplica-o imediatamente, e a entity salta para trás para onde estava há alguns frames. Uma dessas correções é impercetível, mas repeti-la muitas vezes por segundo não é.
setMoveContinuous evita o problema por completo, porque lhe dás uma direção e uma velocidade em vez de um ponto inicial. O engine continua a usar a posição real da entity, por isso substituir o tween para mudar de direção nunca faz a entity saltar.
📔 Nota: Um tween contínuo nunca termina por si só, por isso a entity continua a mover-se até removeres o Tween component com Tween.deleteFrom(), ou até o opcional duration se esgote. Nota também que reorientar em cada frame envia uma atualização para o engine em cada frame. Para evitar isso, chama apenas setMoveContinuous novamente quando a direção tiver mudado o suficiente para importar.
Sequências de Tween
Para fazer uma entity reproduzir uma série de tweens em sequência, usa o TweenSequence component. Este component requer dois campos:
sequence: Um array com várias definições de tween, que serão executadas sequencialmente. O array pode estar vazio, caso em que apenas reproduz o tween atual.loop(opcional): Se não for fornecido, a sequência é reproduzida apenas uma vez. Se o campo estiver presente, o valor tem de ser um valor doTweenLoopenum. Os valores aceites são:TL_RESTART: Quando a sequência termina, recomeça. Se o último estado não corresponder ao primeiro, a entity salta instantaneamente de um para o outro.TL_YOYO: Quando a sequência termina, ela recua, fazendo todos os tweens ao contrário até voltar a atingir o início. Depois começa mais uma vez.
Mover para trás e para a frente
Para fazer uma platform mover-se constantemente para trás e para a frente entre duas posições, deixa o sequence array vazio, e define loop para TweenLoop.TL_YOYO
A entity mover-se-á para trás e para a frente entre o ponto inicial e o ponto final, com a mesma duration e a mesma easing function em ambas as direções.
Seguir um caminho
Para fazer uma entity seguir um caminho mais complexo com vários pontos, fornece uma lista de definições de tween no sequence de um TweenSequence component.
Nota que, ao definir um tween dentro de um TweenSequence, tens de usar o formato mais detalhado de Tween.Mode.Move, ou Tween.Mode.Rotate, ou Tween.Mode.Scale para definir o tween. Neste formato mais detalhado, tens de especificar:
duration: Quantos milissegundos demora a mover entre as duas posiçõeseasingFunction: Que easing function usar. Vê Tweens não lineares. Neste formato, o valor é obrigatório.mode: O modo do tween, que pode serTween.Mode.Move,Tween.Mode.Rotate, ouTween.Mode.Scale.
E dentro do mode campo, tens de especificar:
start: O valor inicial do tweenend: O valor final do tween
Ao terminar o tween
Usa tweenSystem.tweenCompleted para detetar quando um tween terminou. Isto pode ser útil para executar ações quando um tween acaba, por exemplo para abrir a porta de um elevador.
Tweens simultâneos
Para mover, rodar e redimensionar uma entity entre um estado inicial e um estado final, cria um Tween component com a setMoveRotateScale function. Esta function também pode ser usada em qualquer combinação destes três parâmetros.
O tween de movimento recebe as seguintes informações:
entity: A entity a moverparams: Um objeto com os seguintes parâmetrosposition: (opcional) Um objeto com umstarteendvalor, tanto comoVector3.rotation: (opcional) Um objeto com umstarteendvalor, tanto comoQuaternion.scale: (opcional) Um objeto com umstarteendvalor, tanto comoVector3. Pelo menos um dosposition,rotationouscaletem de ser fornecido.duration: (obrigatório) Quantos milissegundos demora a transição entre os dois conjuntos de valoreseasingFunction: (opcional) Que easing function usar. Vê Tweens não lineares
Uma Entity só pode ter um Tween component, e cada componente tween só pode executar uma transformação por vez. Através do setMoveRotateScale tipo de tween, você pode fazer uma Entity mover-se lateralmente e também rotacionar ao mesmo tempo, mas esses dois movimentos seguirão a mesma timeline. Se você precisar que as transições sejam independentes entre si, como alternativa, você pode usar entities com parent. Por exemplo, você pode ter uma Entity parent invisível que se move lateralmente, com um child visível que rotaciona.
No snippet a seguir, uma Entity parent rotaciona enquanto um child aumenta de escala.
Pausar um tween
Para pausar um tween, altere a playing propriedade para false. Para retomá-lo, altere-a de volta para true.
Para encerrar um tween que não precise ser continuado, delete o Tween component da Entity. Se a entitiy também estivesse usando um TweenSequence component, delete-o também.
Tweens baseados em um System
Em vez de usar o componente Tween e deixar o engine lidar com a transformação, você pode preferir fazer essa transição de forma incremental, frame a frame, por meio de um System na sua scene. Ao mover a Entity uma pequena quantidade cada vez que a função é executada.
Por um lado, isso lhe dá mais controle para recalcular os movimentos a cada frame. Por outro lado, o código fica mais complicado, e jogadores com máquinas menos performáticas podem experimentar o tween como lento, percebendo cada incremento.
Mover via System
A maneira mais fácil de mover uma Entity é modificar gradualmente o position valor armazenado no Transform component.
Neste exemplo, estamos movendo uma Entity em 0,05 metros por tick do game loop.
Vector3.Forward() retorna um vetor que aponta para frente e mede 1 metro de comprimento. Neste exemplo, então reduzimos esse vetor para 1/20 do seu comprimento com Vector3.scale(). Se a nossa scene tiver 30 frames por segundo, a Entity está se movendo a uma velocidade de 1,5 metros por segundo.

Rotacionar via System
A maneira mais fácil de rotacionar uma Entity é alterar gradualmente os valores no componente Transform de forma incremental e executar isso como parte da função de um System.
Observe que, para combinar a rotação atual com cada incremento, estamos usando Quaternion.multiply. Na matemática de quaternions, você combina duas rotações multiplicando-as, e NÃO somando-as. A rotação resultante de multiplicar um quaternion por outro será a rotação final equivalente após primeiro realizar uma rotação e depois a outra.
Neste exemplo, estamos rotacionando a Entity em 1 grau na direção para cima em cada tick do game loop.

Rotacionar via System sobre um ponto pivô
Ao rodar uma entity, a rotação é sempre feita em referência à coordenada central da entity. Para rodar uma entity usando outro conjunto de coordenadas como ponto de pivô, cria uma segunda entity (invisível) com o ponto de pivô como posição e torna-a parent da entity que queres rodar.
Ao rodar a entity pai, as suas children serão todas rodadas usando a posição do pai como ponto de pivô. Nota que a position da child entity faz referência à da parent entity.
Nota que, neste exemplo, o system está a rodar a pivotEntity entity, que é parent da childEntity entity.

Ajustar o movimento ao tempo delta
Suponha que o jogador que visita sua scene esteja com dificuldade de acompanhar o ritmo da taxa de frames. Isso pode fazer com que o movimento pareça aos solavancos, já que nem todos os frames têm o mesmo tempo, mas cada um move a Entity pela mesma quantidade.
Você pode compensar esse tempo irregular usando o dt parâmetro para ajustar a escala do movimento.
O exemplo acima mantém o movimento aproximadamente na mesma velocidade do 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 Entity se mova suavemente entre dois pontos, use o lerp (interpolação linear) algoritmo. Esse 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 de destino
A quantidade, um valor de 0 a 1 que representa que fração da translação deve ser feita.
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 de destino for (10, 0, 10):
Usar uma quantidade de 0 retornaria (0, 0, 0)
Usar uma quantidade de 0,3 retornaria (3, 0, 3)
Usar uma quantidade de 1 retornaria (10, 0, 10)
Para implementar isso lerp() na sua scene, recomendamos criar um component customizado para armazenar as informações necessárias. Você também precisa definir um System que implemente o movimento gradual em cada frame.

Rotacionar entre dois ângulos via System
Para rotacionar suavemente entre dois ângulos, use o slerp (spherical linear interpolation) algorithm. Esse algoritmo é muito semelhante a um lerp, mas ele lida com rotações de quaternion.
A slerp() função recebe três parâmetros:
A quaternion ângulo para a rotação de origem
A quaternion ângulo para a rotação de destino
A quantidade, um valor de 0 a 1 que representa que fração da translação deve ser feita.
Para implementar isso na sua scene, recomendamos armazenar os dados que entram na Slerp() função em um component customizado. Você também precisa definir um System que implemente a rotação gradual em cada frame.
📔 Nota: Você poderia, em vez disso, representar a rotação com ângulos euler como Vector3 valores e usar uma Lerp() função, mas isso implicaria uma conversão de Vector3 para Quaternion em cada frame. Os valores de rotação são armazenados internamente como quaternions no Transform component, portanto é mais eficiente para a scene trabalhar com quaternions.

Uma abordagem mais simples, porém menos eficiente, para isso aproveita a Quaternion.rotateTowards função e evita usar quaisquer component customizados.
No exemplo acima Quaternion.rotateTowards recebe três argumentos: a rotação inicial, a rotação final desejada e o incremento máximo por frame. Nesse caso, como o incremento máximo é de dt * 10 graus, a rotação será realizada ao longo de um período de cerca de 9 segundos.
Observe que o System também verifica se a rotação está concluída e, se estiver, remove o System do engine. Caso contrário, o System continuaria fazendo cálculos em cada frame, mesmo depois de a rotação estar concluída.
Alterar a escala entre dois tamanhos via System
Se você quiser que uma Entity 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 de destino, e então use o 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 de destino
A quantidade, um valor de 0 a 1 que representa que fração da escala deve ser aplicada.
Para implementar este lerp na sua scene, recomendamos criar um component customizado para armazenar as informações necessárias. Você também precisa definir um System que implemente a escala gradual em cada frame.

Mover a velocidades irregulares entre dois pontos via System
Ao usar o método lerp, você pode fazer a velocidade do movimento ser não linear. No exemplo anterior, incrementamos a quantidade de lerp em um valor dado a cada frame, mas também poderíamos usar uma função matemática para aumentar o número exponencialmente ou por outras medidas que lhe deem um ritmo de movimento diferente.
Você também poderia usar uma função que gere resultados recorrentes, como uma função seno, para descrever um movimento que vai e volta.
Muitas vezes, essas transições não lineares podem dar muita vida a uma scene. Um movimento que acelera ao longo de uma curva ou desacelera gradualmente pode dizer muito sobre a natureza de um objeto ou personagem. Você poderia até aproveitar funções matemáticas que adicionam efeitos de quique.
O exemplo acima é exatamente como o exemplo linear de lerp que mostramos antes, mas o fraction campo fraction é 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 na rotação ou na escala da mesma forma mostrada acima, mapeando uma transição linear para uma curva.

Seguir um caminho via System
Você pode fazer com que uma Entity percorra em loop um array de vetores, realizando um movimento de lerp entre cada um para seguir um caminho mais complexo.
O exemplo acima define um caminho 3D composto por quatro vetores 3D. O component customizado contém os mesmos dados usados pelo component customizado no exemplo acima, mas adiciona um array path com todos os pontos do nosso caminho e um campo pathTargetIndex para acompanhar qual segmento do caminho está atualmente em uso. PathTransportData O System é muito semelhante ao System no exemplo acima, mas, quando uma ação de lerp é concluída, ele define os campos target lerp origin com novos valores. Se alcançarmos o fim do caminho, retornamos ao primeiro valor do caminho. array, com todos os pontos do nosso caminho, e um pathTargetIndex campo para acompanhar qual segmento do caminho está atualmente em uso.
O System é muito semelhante ao System 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 fim do caminho, retornamos ao primeiro valor do caminho.

Tweens de Texture
Para fazer uma Texture deslizar suavemente, use o Tween component com a setTextureMove function.
O tween de Texture recebe as seguintes informações:
entity: A Entity da qual a Texture será movidastart: Um Vector2 para a posição inicialend: Um Vector2 para a posição finalduration: Quantos milissegundos demora a 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 tiling. Por padrão, usa offset.easingFunction: Que easing function usar. Vê Tweens não lineares.
Movimento contínuo de Texture
Para fazer uma Texture deslizar continuamente, use o Tween component com a setTextureMoveContinuous function.
O tween contínuo de Texture recebe as seguintes informações:
entity: A Entity da qual a Texture será movidadirection: Um Vector2 para o movimentospeed: Quantas unidades por segundo a Entity se moverá
Este outro parâmetro opcional também está disponível:
movementType: define se o movimento será no campo offset ou tiling. Por padrão, usa offset.duration: Quantos milissegundos manter o movimento. Após esse tempo, o movimento para.
Leia mais sobre tweens de Texture na Tweens de Texture seção.
Atualizado