Time for action — combining user control and animation

And, as always, we will use the previous code as a starting point:

  1. Firstly, we need two new variables in the FrameListener for controlling the movement speed and saving our rotation:
    float _WalkingSpeed;
    float _rotation;
    
  2. In the constructor, we init the new values; we want to move at 50 units per second and start with no rotation:
    _WalkingSpeed = 50.0f;
    _rotation = 0.0f;
    
  3. Then we need to change our animation states to prevent them from looping. This time, we are going to control when a new animation has to start and not Ogre 3D:
    _aniState = _ent->getAnimationState("RunBase");
    _aniState->setLoop(false);
    _aniStateTop = _ent->getAnimationState("RunTop");
    _aniStateTop->setLoop(false);
    
  4. In the frameStarted() method, we need two new local variables, one to indicate if we have moved our model for this frame and a second one to store the direction in which we have moved our model.
    bool walked = false;
    Ogre::Vector3 SinbadTranslate(0,0,0);
    
  5. Also in the frameStarted() method, we add some new code to control the movement of our model. We will use the arrow keys for movement. When a key is pressed, we need to change the translation variable to save the direction in which we want to move the model and we need to set the rotation variable to rotate the model in such a way that it looks in the direction it moves:
    if(_key->isKeyDown(OIS::KC_UP))
    {
    SinbadTranslate += Ogre::Vector3(0,0,-1);
    _rotation = 3.14f;
    walked = true;
    }
    
  6. We need the same for the other three arrow keys:
    if(_key->isKeyDown(OIS::KC_DOWN))
    {
    SinbadTranslate += Ogre::Vector3(0,0,1);
    _rotation = 0.0f;
    walked = true;
    }
    if(_key->isKeyDown(OIS::KC_LEFT))
    {
    SinbadTranslate += Ogre::Vector3(-1,0,0);
    _rotation = -1.57f;
    walked = true;
    }
    if(_key->isKeyDown(OIS::KC_RIGHT))
    {
    SinbadTranslate += Ogre::Vector3(1,0,0);
    _rotation = 1.57f;
    walked = true;
    }
    
  7. Then, after the key handling, we need to check if we walked this frame. If this is the case, we need to check if the animation has ended. When this is true, we restart the animation:
    if(walked)
    {
    _aniState->setEnabled(true);
    _aniStateTop->setEnabled(true);
    if(_aniState->hasEnded())
    {
    _aniState->setTimePosition(0.0f);
    }
    if(_aniStateTop->hasEnded())
    {
    _aniStateTop->setTimePosition(0.0f);
    }
    }
    
  8. If we didn't walk this frame, we need to set both animation states to zero. Otherwise, our model would be frozen in an animation half way done and this doesn't look exactly good. So if we don't walk this frame, we set the two animations back to the starting position. Also, we disable both animations since we aren't moving the model of this frame and because we don't need animations:
    else
    {
    _aniState->setTimePosition(0.0f);
    _aniState->setEnabled(false);
    _aniStateTop->setTimePosition(0.0f);
    _aniStateTop->setEnabled(false);
    }
    
  9. The last thing we need to do is to apply translation and rotation to our model's scene node:
    _node->translate(SinbadTranslate * evt.timeSinceLastFrame * _WalkingSpeed);
    _node->resetOrientation();
    _node->yaw(Ogre::Radian(_rotation));
    
  10. Now we compile and run the application. With the mouse and WASD, we can move the camera. With the arrow keys, we can move Sinbad and the right animation gets played each time we move him.
    Time for action — combining user control and animation

What just happened?

We created our first application with user input and animations combined. This could be called the first real interactive application we created up until now. In steps 1 and 2, we created and inited some variables we needed later. In step 3, we changed how we handle our animations; previously, we always enabled an animation directly and let it loop. Now we don't want to enable it directly because we want the animation only to be played when our model moves, everything else just looks stupid. For the same reason, we disabled looping of animations. We only want to react to user input so that there is no need for animation looping. If needed, we will start the animation ourselves.

Most of the changes we did were inside the frameStarted() method. In step 4, we created a couple of local variables we needed later, namely, a Boolean value that was used as an indicator if the model moves this frame and the other was a vector representing the movement direction. Steps 5 and 6 queried the key state of the arrow keys. When a key is down, we change the direction vector and the rotation accordingly and set the flag for movement to true. We used this flag in step 7, if the flag is true, meaning our model moves this frame, we enabled the animation and checked if the animations had reached their end. If the animations have reached their end, we reset them to their starting position so that they can be played again. Because we don't want animations to be played when the model isn't moving, we set them to their starting position and disable them in step 8. In step 9, we applied the translation. Then we reset the orientation, and after this, applied the new rotation. This is necessary because yaw adds the rotation to the already done rotations, which in our case would be wrong because we have absolute rotation, and we need absolute and not relative rotations. Therefore, we reset the orientation first and then apply our rotation to the now zeroed rotation.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.135.206.254