Movement with Irrlicht's animators

When we think of animation we usually think of a model moving it's arms or swinging it's weapon. This is accomplished in Irrlicht through the SetFrameLoop or AnimateJoints functions of an animated/rigged model. However, animators in Irrlicht serve the more general purpose of modifying a scene node in some way, be it a camera, light, model or a custom scene node. In this tutorial we will be modifying the Skybox/Skydome tutorial. The following topics are covered in this tutorial:

  1. Creating a project
  2. Model and camera changes to Skybox tutorial
  3. Frame rate independent manual movement
  4. Adding an animator
  5. List of animators

The tutorial's code files and media files are installed along with Ginjo-Builder and can be accessed from the 'Project' window that is shown when the editor starts. This tutorial is called '09_Movement' in the 'Tutorials' tab.

1. Creating a project

First we create a project and compiler options XML file. (See Render loop for a more detailed description of creating a project.)

  1. Create a new project through the Project menu.
  2. Right click on project's top level tree node named "New GBP(Unsaved)" and select Rename folder. Rename the folder to "Animators".
  3. Save the project as "Movement.gbp" from the Project menu.
  4. Add a new file to the project tree and save it as "testAnimators.gbc"
  5. Add a new file to the project tree and save it as "Animators.xml". (The XML file must have the same name as the top level tree node.)

Open "Animators.xml" and just like in Render loop add the <exe> and <startup> elements. We will also import the GB namespace so we don't have to type it out every time. (For the full list of XML tags see Compiler options.)

<?xml version="1.0" encoding="utf-8"?>
<root>
   <exe path=".\game.exe" />
   <startup name="testAnimators.main" />
   
   <ImportSymbols>
      <namespace name="GB"  />
   </ImportSymbols>
</root>

2. Model and camera changes to Skybox tutorial

In our XML file we specified the startup function as "testAnimators.main". Double-click on "testAnimators.gbc" in the project tree to open it, and copy over the "main" function from the Skybox/Skydome tutorial. Delete the FPS camera scene node code and instead add in the drone model from the Cameras tutorial. We will also add in a camera that has the drone as the parent node. Thus the camera will maintain its position relative to the drone (at Vector3Df(400,300,-300)), even when the drone moves. The code for the drone and camera should look as follows:

//load model from relative path ..\media\GlobalHawk.obj 
var:scene.Mesh drone = smgr.GetMesh('..\media\GlobalHawk.obj')
//add model to scene 
var:Scene.MeshSceneNode droneNode = smgr.AddMeshSceneNode(drone)
if(!isNull(droneNode)){
   droneNode.Position=new gb.core.Vector3Df(2700 * 2, 255 * 5, 300)
   droneNode.Scale=new gb.core.Vector3Df(0.2, 0.2, 0.2)
   droneNode.SetMaterialFlag(gb.video.MaterialFlag.Lighting, false)
}
var:scene.CameraSceneNode camera= smgr.AddCameraSceneNode(droneNode, new core.Vector3Df(400,300,-300), droneNode.Position)
camera.FarValue = 42000

Note that the droneNode is passed in as the camera's parent. Thus the position vector Vector3Df(400,300,-300) is relative to the drone. When you run the program using the skydome you should see a stationary drone:

3. Frame rate independent manual movement

Different computers render the scene at different speeds. In order to produce consistent movement we need to measure the elapsed time since the previous iteration of the render loop, and update our drone models position accordingly. We called our IrrlichtDevice variable engine, so we can use either engine.Timer.RealTime to retrieve the systems current time in milliseconds, or we can use engine.Timer.Time to retrieve Irrlicht engine's virtual time. The benefit of the virtual timer is that it can be stopped and started, as well as its speed modified. Modify the render loop as shown below to include the virtual timer and change the drones position based on the elapsed time:

//The render loop runs continuously and redraws the scene.
var:gb.video.Color background=new gb.video.Color(160, 160, 160)
var:uint32 oldTime
var:uint32 newTime
var:single timeDiff
var:core.Vector3Df dronePosition
while(engine.Run()){
    //Manual movement:   		
    dronePosition=droneNode.Position
    newTime=engine.Timer.Time
    timeDiff=convert.ToSingle(newTime-oldTime)/1000	//time difference in seconds
    dronePosition.Z+=timeDiff*400 //movement speed
    droneNode.Position=dronePosition
    oldTime=newTime
    camera.Target=droneNode.Position

    //Redrawing the screen requires a call to the drivers BeginScene function.
    driver.BeginScene(gb.video.ClearBufferFlag.All, background)
    //The SceneManager will handle rendering the scene graph for us.
    smgr.DrawAll()
    //When we are done, we need to call EndScene so that the driver can update the screen.
    driver.EndScene()
}

Note that the camera is attached to the drone, so it will move with it. However, the cameras target needs to be updated to keep looking at the drone. When you run the program you should see the drone moving smoothly.

4. Adding an animator

In a game with a large number of objects (including projectiles) it would be cumbersome and error prone to manually keep track of changes to the scene and the movement of all objects. Animators simplify the task by automatically making changes to a scene node based on the elapsed time. Animators can be attached to any scene node (including cameras and lights) and can change any property of the scene node, not just its position (for example animate the textures of an object). First we are going to keep the camera stationary, and add the "fly straight" animator. This animator moves a scene node from a one position to another. Comment out the code for the manual movement of the camera in the render loop and add the animator code for the drone as shown below:

var:Scene.MeshSceneNode droneNode = smgr.AddMeshSceneNode(drone)
var:scene.SceneNodeAnimator Animator
if(!isNull(droneNode)){
droneNode.Position=new core.Vector3Df(2700 * 2, 255 * 5, 300);
droneNode.Scale=new core.Vector3Df(0.2, 0.2, 0.2)
droneNode.SetMaterialFlag(video.MaterialFlag.Lighting, false)
//**Animator movement:**
var:core.Vector3Df EndPoint=droneNode.Position
endpoint.Z+=2500
Animator=smgr.CreateFlyStraightAnimator(droneNode.Position,EndPoint,50)
droneNode.AddAnimator(Animator)
}
	
var:scene.CameraSceneNode camera
camera= smgr.AddCameraSceneNode(null, droneNode.Position+new core.Vector3Df(50,25,-25),droneNode.Position)
camera.FarValue = 42000

Note that the camera no longer has the drone as the parent node, and its position is drone's position plus Vector3Df(50,25,-25). When you run the code you should see the drone smoothly fly away. Now put back the line for updating the camera's target in the render loop:

//The render loop runs continuously and redraws the scene.
var:gb.video.Color background=new gb.video.Color(160, 160, 160)
while(engine.Run()){
    camera.Target=droneNode.Position

    //Redrawing the screen requires a call to the drivers BeginScene function.
    driver.BeginScene(gb.video.ClearBufferFlag.All, background)
    //The SceneManager will handle rendering the scene graph for us.
    smgr.DrawAll()
    //When we are done, we need to call EndScene so that the driver can update the screen.
    driver.EndScene()
}

When you run the code you should see the drone smoothly fly away, with the camera adjusting to keep track of it.

This tutorial does not include a camera that follows a model with an animator attached. Animators make changes to the scene node based on time and if we changed the camera's target manually, you may find that the camera's movement is jittery/jagged (depending on the speed of your computer). To achieve that effect you would have to extend the model and update the camera's target on the model scene nodes OnAnimate event.

5. List of animators

The following animators are included in Irrlicht:

Rotation Animator
Rotates the attached scene node around itself.
Follow spline animator
The animator modifies the position of the attached scene node to make it follow a hermite spline. It uses a subset of hermite splines: either cardinal splines (tightness != 0.5) or catmull-rom-splines (tightness = 0.5).
Fly straight animator
The attached scene node flies or moves along a line between two points.
Fly circle animator
The attached scene node flies or moves around a center at a specified radius.
Delete animator
Deletes the scene node after some time automatically.
CollisionResponseSceneNodeAnimator
A special scene node animator for doing automatic collision detection and response.(See GB.Sceene.CollisionResponseSceneNodeAnimator.)