SetFrameLoop animation

In this tutorial we will be expanding on the program in the Render loop tutorial. We will be controlling the Warrior model's built-in animations using the GB.Scene.AnimatedMeshSceneNode.SetFrameLoop function. The following topics are covered:

  1. Creating a project
  2. Animation speed (frames per second)
  3. SetFrameLoop function

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 '10_SetFrameLoop_Animation' 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 "FrameLoop".
  3. Save the project as "FrameAnimation.gbp" from the Project menu.
  4. Add a new file to the project tree and save it as "LoopAnimation.gbc"
  5. Add a new file to the project tree and save it as "FrameLoop.xml". (The XML file must have the same name as the top level tree node.)

Open "FrameLoop.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="LoopAnimation.main" />
   
   <ImportSymbols>
      <namespace name="GB"  />
   </ImportSymbols>
</root>

2. Animation speed (frames per second)

In our XML file we specified the startup function as "LoopAnimation.main". Double-click on "LoopAnimation.gbc" in the project tree to open it, and add the following function, called "main". (When you run your program this is the function where execution starts.) Initialize the Irrlicht 3D engine and add the Warrior model as in the Render loop tutorial. In this tutorial we do not have any lights, thus the Lighting material flag of the model must be turned to false. (Otherwise the model will be completely black.)

function main(var:string cmdArgs[]) returns Int32
{
   var:gb.IrrlichtCreationParameters options=new gb.IrrlichtCreationParameters()
   //Without anti-aliasing our model edges would be jagged 
   options.AntiAliasing=255
   //Tell Irrlicht to use OpenGL for graphics
   options.DriverType=gb.video.DriverType.OpenGL
   //Turn off logging, we won't be using it for now
   options.LoggingLevel=gb.LogLevel.None
   
   var:gb.IrrlichtDevice engine = gb.IrrlichtDevice.CreateDevice(options)
   //Also set our window's title
   engine.SetWindowCaption('Event handling')
   
   var:video.VideoDriver driver=engine.VideoDriver
   var:Scene.SceneManager smgr=engine.SceneManager

   //add camera 
   var:scene.CameraSceneNode Camera= smgr.AddCameraSceneNode()
   camera.Position=new core.Vector3Df(10,30,-100)

   //load model from relative path ..\media\warrior.x
   var:scene.AnimatedMesh WarriorMesh = smgr.GetMesh('..\media\warrior.x')
   //add model to scene
   var:Scene.AnimatedMeshSceneNode Warrior
   Warrior = smgr.AddAnimatedMeshSceneNode(WarriorMesh)

   if(!isNull(Warrior)){
      Warrior.AnimationSpeed = 20
      Warrior.Scale = new core.Vector3Df(40)
      Warrior.SetMaterialFlag(video.MaterialFlag.Lighting, false)
      camera.Target = Warrior.Position + new core.Vector3Df(0,20,0)
   }
}

Next add the render loop to the "main" function exactly as in the first tutorial. However, this time around we will also display the current animation frame of the model in the window's title bar. Note the addition of the PrevFrame and NowFrame variables before the loop. We use the Scene.AnimatedMeshSceneNode's CurrentFrame property to retrieve the model's animation frame.

var:Int32 PrevFrame
var:int32 NowFrame
var:video.Color background=new video.Color(160, 160, 160)
while (engine.Run()){
   NowFrame = convert.ToInt32(Warrior.CurrentFrame)
   if(NowFrame != PrevFrame){
      PrevFrame = NowFrame
      engine.SetWindowCaption('Frame:' + PrevFrame.toString)
   }

   driver.BeginScene(video.ClearBufferFlag.All, background)
   smgr.DrawAll()
   driver.EndScene()
}

The Warrior model has 702 frames (0 to 701). When you run the code you can see that after the all the 702 frames are finished the animation starts over from the beginning. In the model's code above we set the animation speed to Warrior.AnimationSpeed = 20. Hence, the animation is played at 20 frames per second. (Setting the animation speed to zero freezes the model.) Now let's speed up the animation and also set the LoopMode to false so that the animation only plays once and not in a loop. Change the model's code to the following:

if(!isNull(Warrior)){
    Warrior.AnimationSpeed = 30
    Warrior.LoopMode = false
    Warrior.Scale = new core.Vector3Df(40)
    Warrior.SetMaterialFlag(video.MaterialFlag.Lighting, false)
    camera.Target = Warrior.Position + new core.Vector3Df(0,20,0)
}

3. SetFrameLoop function

By default the entire range of animation frames are played for an animated model. The SetFrameLoop function can be used to set the range of animation frames to loop through. The animation ranges for the Warrior model are shown in the code below. Comment/uncomment the lines in your program to play different animations.

if(!isNull(Warrior)){
    Warrior.AnimationSpeed = 30
    Warrior.LoopMode = false
    Warrior.Scale = new core.Vector3Df(20)
    Warrior.SetMaterialFlag(video.MaterialFlag.Lighting, false)
    camera.Target = Warrior.Position + new core.Vector3Df(0,20,0)
    //Warrior.SetFrameLoop(0,19) //take weapons
    //Warrior.SetFrameLoop(20,119) //stand
    //Warrior.SetFrameLoop(120,199) //turn right
    //Warrior.SetFrameLoop(200,219) //turn back to center from right
    //Warrior.SetFrameLoop(220,287) //turn left
    //Warrior.SetFrameLoop(288,307) //turn back to center from right
    //Warrior.SetFrameLoop(308,319) // start run
    //Warrior.SetFrameLoop(320,349) //run
    //Warrior.SetFrameLoop(349,369) //come to a stop after running
    //Warrior.SetFrameLoop(370,420) //swing sword
    //Warrior.SetFrameLoop(430,480) //slash with sword
    //Warrior.SetFrameLoop(481,489) //start walk
    Warrior.SetFrameLoop(490,520) //sexy walk
    //Warrior.SetFrameLoop(521,539) //stop walk
    //Warrior.SetFrameLoop(540,555) //jump up
    //Warrior.SetFrameLoop(556,589) //land from jump
    //Warrior.SetFrameLoop(590,639) //get hit
    //Warrior.SetFrameLoop(640,701) //get hit, then die
}

Note that you can use the IntelliDoc Symbol Info feature to look-up symbol types and definitions. The 'lightbulb' button on the toolbar looks-up the symbol type for the current cursor location and displays it in a tooltip. Pressing F1 also shows the tooltip.