ANIMAÇÃO
De agora em diante conheceremos como a Ogre trabalha com movimentação de malhas, isso vai depender principalmente dos movimentos que o personagem, por exemplo, poderá fazer. Essas animações são criadas durante o processo de modelagem, e são todas exportadas juntamente com a malha, e estão no arquivo .mesh.
Um programa que pode ser utilizado para se conhecer as animações da malha chama-se Mesh Viewer, uma busca pelo fórum da Ogre mostrará outros programas semelhantes a ele. Deve se observar o nome da animação, pois é mais fácil e mais organizado chamar uma animação pelo nome.
Inicialmente vamos para o arquivo "AplicationListener.h" e adicionamos a seguinte variável, do tipo AnimationState(Estado da animação), para controlar a animação do robô.
AnimationState *animationState;
Agora indo até o construtor da nossa classe AplicationListener, ou seja, o método AplicationListener no arquivo "AplicationListener.cpp", incluimos as linhas abaixo.
animationState = scene_mgr->getEntity("robo")->getAnimationState("Idle");
animationState->setLoop(true);
animationState->setEnabled(true);
Com o método "getAnimationState()" definimos a animação que a váriavel animationState irá cuidar. A animação chamada foi "Idle" que é a do robô parado. Já que ela deve sempre se repetir, usa-se a função "setLoop()" com o parâmetro true. Se a animação fosse do robô morrendo por exemplo, ela seria executada somente uma vez, então o parãmetro para essa função seria false. A animação será habilitada com "setEnabled()".
animationState->addTime(evt.timeSinceLastFrame);
A animação do robô precisa ser atualizada durante a execução do programa, dessa forma usamos a função "addTime()", ela deve ser atualizada frequentemente. Então coloque a linha de código acima no método "frameStarted()", que é o loop principal do jogo. O parâmetro é exatamente o tempo passado desde o último frame o que atualizará a animação corretamente. Execute o projeto e o robô estará na sua animação de parado.
Para exemplificar um pouco mais sobre animação, vamos criar uma situação em que o robô irá andar.
No projeto base para estes tutoriais, existem algumas variáveis que foram criadas e seram usadas
nessa parte da explicação. Elas estão declaradas no arquivo "AplicationListener.h".
Real distancia - guarda o valor da distãncia a qual o robô irá andar.
Vector3 destino - posição no ambiente 3D para onde o robô irá.
Vector3 direcao - direção do movimento do robô.
Real walkSpeed - velocidade a qual o robô irá andar.
Real move - distância a qual o robô andou desde o último frame renderizado.
distancia = 0; walkSpeed = 100; destino = Vector3::ZERO;
Agora no construtor da classe AplicationListener inicializamos o valor da variável "distancia" com 0, pois o robô irá começar a andar quando pressionarmos a tecla "r", isso será adicionado ao código ainda. Definimos também o valor de walkSpeed com 100 e do vetor destino.
//move-> recebe o valor "andado" pelo char no ultimo frame move = walkSpeed * evt.timeSinceLastFrame; distancia -= move;
O trecho de código acima deve estar no método "frameStarted()", com ele iremos obter o valor andado pelo robô desde o último frame, e colocaremos na variável "move". Depois decrementaremos a distância a qual o robô ainda terá que se mover.
case OIS::KC_R:
animationState = scene_mgr->getEntity("robo")->getAnimationState("Walk");
animationState->setLoop(true);
animationState->setEnabled(true);
destino = Vector3(100,0,-300);
direcao = destino - scene_mgr->getSceneNode("roboNode")->getPosition();
distancia = direcao.normalise();
/*essa parte do codigo serve para girar a "frente" do char para a direção que
ele irá andar */
src = scene_mgr->getSceneNode("roboNode")->getOrientation() * Vector3::UNIT_X;
if ((src.dotProduct(direcao)) < 0.0001f)
{
scene_mgr->getSceneNode("roboNode")->yaw(Degree(180));
}
else
{
quat = src.getRotationTo(direcao);
scene_mgr->getSceneNode("roboNode")->rotate(quat, Node::TS_WORLD);
}
break;
O robô começará a andar quando a tecla "r" for pressionada, então no método "keyReleased()" adicionamos o código acima. A variável "animationState" é atualizada para a animação do robô andando.
Definimos a posição para onde o robô se movimentará, depois obtemos a direção a partir da subtração do vetor destino e do vetor que guarda a posição atual do robô. Então define-se o valor da distancia a ser percorrida normalizando o vetor direção.
A segunda parte(abaixo do comentário) serve para colocar a "frente" do robô na direção da movimentação. Observe na primeira linha dessa parte, o trecho "Vector3::UNIT_X", nesse vetor deve-se dizer qual a direção da "frente" da malha quando foi modelada. Por exemplo o robô quando foi modelado a sua "frente" está na direção positiva do eixo X. Já o ninja, um outro modelo que vem juntamente com a Ogre, a sua frente está para o eixo positivo de Z. Atente para esse detalhe no Mesh Viewer, ou seu personagem poderá andar de lado ou de costas.
if (distancia <= 0.0f)
{
direcao = Vector3::ZERO;
//chama a animação do robô parado
animationState = scene_mgr->getEntity("robo")->getAnimationState("Idle");
animationState->setLoop(true);
animationState->setEnabled(true);
}
else
{
//movimenta o robô na direção correta
scene_mgr->getSceneNode("roboNode")->translate(direcao * move);
}
Voltando para o método "frameStarted()" insirta as linhas acima, com elas verificamos se o robô já percorreu toda a distância a qual definimos. Se a distância for menor ou igual a zero, então o robô andou tudo e deverá parar, dessa forma o valor do vetor "direcao" ficará como zero, pois é esse vetor que estamos utilizando para mudar a posição do personagem. Também devemos chamar a movimentação do robô parado(Idle).
Caso ele ainda não tenha percorrido toda a distância então simplesmente movimentamos o robô usando a função "translate()", onde o parâmetro é um vetor resultado da multiplicação do vetor "direcao" e da quantidade andada pelo personagem desde o último frame(move).
Italo Mendes
italo.ribeiro@gmail.com
