Skip to main content
History: New Mogre Intermediate Tutorial 1
View published page
Source of version: 9
(current)
{TRANSCLUDE(page="tutbox")}In this tutorial we will be covering how to take an Entity, animate it, and have it walk between predefined points. This will also cover the basics of quaternion rotation by showing how to keep the Entity facing the direction it is moving. By the end of this tutorial you will be fully familiar with animations and quaternion in Mogre/OGRE. As you go through the tutorial you should be slowly adding code to your own project and watching the results as we build it. There is no substitute for actual programming to get familiar with these concepts! Resist the urge to simply read along. {TRANSCLUDE} If you find any errors in this tutorial please send a private message to [/addonforums/ucp.php?i=pm&mode=compose&u=14838|amirabiri] or [http://www.ogre3d.org/addonforums/memberlist.php?mode=viewprofile&u=14850&sid=b532ae9b4b3654ca0da8c28b5af2f562|McDonte]. {maketoc} !Prerequisites * This tutorial assumes you have knowledge of C# or VB.NET programming and are able to setup and compile a ((Mogre)) application. * This tutorial also assumes that you have created a project using the ((Mogre Wiki Tutorial Framework)). * This tutorial makes use of .NET's LinkedList<T> data structure. While no prior knowledge of how to use it, you should at least know what templates are. This is not needed for animation at all but used in this tutorial. * Finally this tutorial assumes you are familiar with the most basic concepts of Ogre/Mogre for example by having read the ((Mogre Basic Tutorials)). !Getting started Start with a fresh version of the ((Mogre Wiki Tutorial Framework|Tutorials Framework)). Add a reference to the "System" library which the tutorials framework doesn't link to normally. This library is needed because it provides an implementation of a [http://en.wikipedia.org/wiki/Linked_list|linked list]. Vist [http://msdn.microsoft.com/en-us/library/he2s3bh7.aspx|msdn] for more information. !Animations Animations are actually very simple in Mogre, at least from the programmers point of view. The mesh files contain information about animations that the mesh is capable of. Each animation is simply a series of transformations applied on the vertexes of the mesh based around its "skeleton". These transformations are perceived as animation of the mesh to human eyes. Defining these animation transformations is a tedious job and there are many different techniques to do it. However, once an animator has produced such a series of transformations, it is very simple to use them in code. To use an animation in code, all we need to do is acquire the AnimationState of the desired animation from the entity object, set its properties and enable it to start the animation. Once the animation is started you have to add time to it in each frame, i.e you will interact with it from a frame listener. Let's look at a simple example to accomplish this. We will use the robot mesh included in the media folder and use its walking animation. Add the following code to your ''CreateScene'' method to set up a simple scene and add the robot to it: {VERSIONS(nav="y",default="C#")} {CODE(wrap="1", colors="c#")} protected override void CreateScene() { mSceneMgr.AmbientLight = ColourValue.White; var robot = mSceneMgr.CreateEntity("Robot", "robot.mesh"); mSceneMgr.RootSceneNode.CreateChildSceneNode("Robot").AttachObject(robot); } {CODE} ---(VB.NET)--- {CODE(wrap="1", colors="vbnet")} Protected Overrides Sub CreateScene() mSceneMgr.AmbientLight = ColourValue.White Dim robot = mSceneMgr.CreateEntity("Robot", "robot.mesh") mSceneMgr.RootSceneNode.CreateChildSceneNode("Robot").AttachObject(robot) End Sub {CODE} {VERSIONS} So far there is nothing new, this should all be familiar from the previous tutorials. Since we are going to use the AnimationState object in every frame, we should keep a reference to it. So we need a member variable in the tutorial class to hold this reference: {VERSIONS(nav="y",default="C#")} {CODE(wrap="1", colors="c#")} AnimationState mAnimationState; {CODE} ---(VB.NET)--- {CODE(wrap="1", colors="vbnet")} Dim mAnimationState As AnimationState {CODE} {VERSIONS} Next, we will acquire the AnimationState object that represents the "Walk" animation of the robot mesh. Add the following code to your ''CreateScene'' method: {VERSIONS(nav="y",default="C#")} {CODE(wrap="1", colors="c#")} mAnimationState = robot.GetAnimationState("Walk"); {CODE} ---(VB.NET)--- {CODE(wrap="1", colors="vbnet")} mAnimationState = robot.GetAnimationState("Walk") {CODE} {VERSIONS} The name of the animation is chosen by the animator when they create the animation and it is stored in the __.mesh file__ for vertex animations and in the __.skeleton file__ for skeletal animations. Each mesh file can have different animation names. Whenever you use a mesh file you should find out which animations it has available. There are tools that allow you to view the animations as well which we will use later. Now that we have a reference to the AnimationState object, how do we actually use it? It's very simple: we set its properties depending on what we want to do, and enable it. In this case we want the robot to be walking continuously, so we set the animation to "loop" by setting its ''Loop'' property to true: {VERSIONS(nav="y",default="C#")} {CODE(wrap="1", colors="c#")} mAnimationState.Loop = true; {CODE} ---(VB.NET)--- {CODE(wrap="1", colors="vbnet")} mAnimationState.Loop = True {CODE} {VERSIONS} And finally we enable it: {VERSIONS(nav="y",default="C#")} {CODE(wrap="1", colors="c#")} mAnimationState.Enable = true; {CODE} ---(VB.NET)--- {CODE(wrap="1", colors="vbnet")} mAnimationState.Enable = True {CODE} {VERSIONS} All we have left to do now is feed our animation time in each frame. With the tutorials framework we can achieve this easily using the ''UpdateScene'' method: {VERSIONS(nav="y",default="C#")} {CODE(wrap="1", colors="c#")} protected override void UpdateScene(FrameEvent evt) { mAnimationState.AddTime(evt.timeSinceLastFrame); } {CODE} ---(VB.NET)--- {CODE(wrap="1", colors="vbnet")} Protected Overrides Sub UpdateScene(evt As FrameEvent) mAnimationState.AddTime(evt.timeSinceLastFrame) End Sub {CODE} {VERSIONS} And that's all there is to it. Pretty simple isn't it? Your tutorial class should now look something like this: {VERSIONS(nav="y",default="C#")} {CODE(wrap="1", colors="c#")} AnimationState mAnimationState; protected override void CreateScene() { mSceneMgr.AmbientLight = ColourValue.White; var robot = mSceneMgr.CreateEntity("Robot", "robot.mesh"); mSceneMgr.RootSceneNode.CreateChildSceneNode("Robot").AttachObject(robot); mAnimationState = robot.GetAnimationState("Walk"); mAnimationState.Loop = true; mAnimationState.Enabled = true; } protected override void UpdateScene(FrameEvent evt) { mAnimationState.AddTime(evt.timeSinceLastFrame); } {CODE} ---(VB.NET)--- {CODE(wrap="1", colors="vbnet")} mAnimationState As AnimationState Protected Overrides Sub CreateScene() mSceneMgr.AmbientLight = ColourValue.White Dim robot = mSceneMgr.CreateEntity("Robot", "robot.mesh") mSceneMgr.RootSceneNode.CreateChildSceneNode("Robot").AttachObject(robot) mAnimationState = robot.GetAnimationState("Walk") mAnimationState.Loop = True mAnimationState.Enabled = True End Sub Protected Overrides Sub UpdateScene(evt As FrameEvent) mAnimationState.AddTime(evt.timeSinceLastFrame) End Sub {CODE} {VERSIONS} Compile and run your application. You should see the robot mesh in front of he camera walking in place: {IMG(src="dl2026&display")}Screenshot1{IMG} So far about the basics but now we will put this into practise. !Setting up the Scene Before we begin, notice that we have already defined some variables: *__mEntity__ will hold the entity we create, *__mNode__ will hold the node we create, *__mAnimationState__ will hold the animation state of the object, *__mDistance__ will contain the distance from our location to the next waypoint, *__mDirection__ will hold the direction the object is moving, *__mDestination__ will hold the next waypoint location, *__mWalkList__ will contain all the points we wish the object to walk to, *__mWalkSpeed__ will hold our speed and *__mWalking__ will indicate whether or not we are moving. Go to the CreateScene method and add the following code to it. All what is done is very simple and is covered in the [http://www.ogre3d.org/tikiwiki/Mogre+Basic+Tutorials|Basic Tutorials]. Take a look there if you are running into problems. {VERSIONS(nav="y",default="C#")} {CODE(wrap="1", colors="c#")} // get the instance of the SceneManager SceneManager mgr = this.mSceneMgr; // set the ambient light mgr.AmbientLight = ColourValue.White; // create the robot Entity ent = mgr.CreateEntity("Robot", "robot.mesh"); SceneNode node = mgr.RootSceneNode.CreateChildSceneNode("RobotSceneNode", new Vector3(0.0f, 0.0f, 0.25f)); node.AttachObject(ent); {CODE} ---(VB.NET)--- {CODE(wrap="1", colors="vbnet")} ' get the instance of the SceneManager Dim mgr As SceneManager = Me.mSceneMgr ' set the ambient light mgr.AmbientLight = ColourValue.White ' create the robot Dim ent As Entity = mgr.CreateEntity("Robot", "robot.mesh") Dim node As SceneNode = mgr.RootSceneNode.CreateChildSceneNode("RobotSceneNode", New Vector3(0F, 0F, 0.25F)) node.AttachObject(ent) {CODE} {VERSIONS} In the next chunk of code, we are going to tell the robot where he needs to be moved to. For those of you who don't know anything about [http://msdn.microsoft.com/en-us/library/he2s3bh7.aspx|.NET's LinkedList], it is an efficient implementation of a doublely linked list that we can use as a two ended queue. We will only be using a few of its methods. The __AddFirst__ and __AddLast__ methods put items at the front and back of the list respectively. The __First__ and __Last__ methods return the items at the front and back of the list respectively. The __RemoveFirst__ and __RemoveLast__ methods remove the items from the front and back of the list respectively. Finally, the __Count__ method returns the number of entries in the list. This code creates the list, and then adds three Vectors to it. We will use these later when we make the robot move. {VERSIONS(nav="y",default="C#")} {CODE(wrap="1", colors="c#")} // create the walking list mWalkList = new LinkedList<Vector3>(); mWalkList.AddLast(new Vector3(550.0f, 0.0f, 50.0f)); mWalkList.AddLast(new Vector3(-100.0f, 0.0f, -200.0f)); mWalkList.AddLast(new Vector3(0.0f, 0.0f, 25.0f)); {CODE} ---(VB.NET)--- {CODE(wrap="1", colors="vbnet")} ' create the walking list mWalkList = New LinkedList(Of Vector3)() mWalkList.AddLast(New Vector3(550F, 0F, 50F)) mWalkList.AddLast(New Vector3(-100F, 0F, -200F)) mWalkList.AddLast(New Vector3(0F, 0F, 25F)) {CODE} {VERSIONS} Next, we want to place some objects on the scene to show where the robot is supposed to be moving. This will allow us to see the robot moving with respect to other objects on the screen. Notice the negative Y component to their position. This puts the objects under where the robot is moving to, and he will stand on top of them when he gets to the correct place. {VERSIONS(nav="y",default="C#")} {CODE(wrap="1", colors="c#")} // create some knot objects so we can see the robot's movement ent = mgr.CreateEntity("Knot1", "knot.mesh"); node = mgr.RootSceneNode.CreateChildSceneNode("Knot1Node", new Vector3(0.0f, -10.0f, 25.0f)); node.AttachObject(ent); node.Scale(0.1f, 0.1f, 0.1f); ent = mgr.CreateEntity("Knot2", "knot.mesh"); node = mgr.RootSceneNode.CreateChildSceneNode("Knot2Node", new Vector3(550.0f, -10.0f, 50.0f)); node.AttachObject(ent); node.Scale(0.1f, 0.1f, 0.1f); ent = mgr.CreateEntity("Knot3", "knot.mesh"); node = mgr.RootSceneNode.CreateChildSceneNode("Knot3Node", new Vector3(-100.0f, -10.0f, -200.0f)); node.AttachObject(ent); node.Scale(0.1f, 0.1f, 0.1f); {CODE} ---(VB.NET)--- {CODE(wrap="1", colors="vbnet")} ' create some knot objects so we can see the robot's movement ent = mgr.CreateEntity("Knot1", "knot.mesh") node = mgr.RootSceneNode.CreateChildSceneNode("Knot1Node", New Vector3(0F, -10F, 25F)) node.AttachObject(ent) node.Scale(0.1F, 0.1F, 0.1F) ent = mgr.CreateEntity("Knot2", "knot.mesh") node = mgr.RootSceneNode.CreateChildSceneNode("Knot2Node", New Vector3(550F, -10F, 50F)) node.AttachObject(ent) node.Scale(0.1F, 0.1F, 0.1F) ent = mgr.CreateEntity("Knot3", "knot.mesh") node = mgr.RootSceneNode.CreateChildSceneNode("Knot3Node", New Vector3(-100F, -10F, -200F)) node.AttachObject(ent) node.Scale(0.1F, 0.1F, 0.1F) {CODE} {VERSIONS} Now compile and run the code. You should see something like this: {IMG(src="dl2027&display")}Screenshot{IMG} !Moving the Robot Now we are going to perform the slightly tricky task of making the robot walk from waypoint to waypoint. Before we begin I would like to re-describe some of the variables that we are storing in the class. We are going to use four variables to accomplish the task of moving the robot. The direction the robot is moving is stored in mDirection. The robot's current destination is stored in mDestination. The distance the robot has left to travel is stored in mDistance. Last but not least, the robot's speed is stored in mWalkSpeed. %tip%__There are some nested if-statements in the following code. If you get confused about it, just watch the whole code at the bottom of the page.__ Since the variables are already initialized we can use them to set the robot in motion. To make the robot move, we simply tell it to change animations. However, we only want to start the robot moving if there is another location to move to. The __NextLocation__ method is used for this. Add this code to __FrameStarted__ method just above __mAnimationState.AddTime(mDeltaTime)__ which should be just above the return line: {VERSIONS(nav="y",default="C#")} {CODE(wrap="1", colors="c#")} if (!mWalking) // either we've not started walking or reached a way point { // check if there are places to go if (NextLocation() == true) { LinkedListNode<Vector3> tmp; // start the walk animation mAnimationState = ent.GetAnimationState("Walk"); mAnimationState.Loop = true; mAnimationState.Enabled = true; mWalking = true; // TO-DO: update the destination using the walklist } } {CODE} ---(VB.NET)--- {CODE(wrap="1", colors="vbnet")} If Not mWalking Then ' either we've not started walking or reached a way point ' check if there are places to go If NextLocation() = True Then Dim tmp As LinkedListNode(Of Vector3) ' start the walk animation mAnimationState = ent.GetAnimationState("Walk") mAnimationState.[Loop] = True mAnimationState.Enabled = True mWalking = True ' TO-DO: update the destination using the walklist End If End If {CODE} {VERSIONS} If you compile and run the code right now, the robot will walk in place. This is because the robot starts out with a __mWalking = false__ and our __NextLocation__ method always returns true. In later steps we will be adding a bit more intelligence to the __NextLocation__ method. Note that we also left a placeholder for the code to update the Robot's destination. We'll get to that later too. Now we are going to actually move the robot in the scene. To do this we need to have him move a small bit every frame. We will be adding the following code just after our previous if statement and just above the return line of the method. This code will handle the case when the robot is actually moving, so if __mWalking__ equals true. {VERSIONS(nav="y",default="C#")} {CODE(wrap="1", colors="c#")} else // we're in motion { // determine how far to move this frame mDistance -= (mWalkSpeed * deltaTime); {CODE} ---(VB.NET)--- {CODE(wrap="1", colors="vbnet")} Else ' we're in motion ' determine how far to move this frame mDistance -= (mWalkSpeed * deltaTime) {CODE} {VERSIONS} Now, we need to check and see if we've arrived at the waypoint. That is, if __mDistance__ is now less than or equal to zero, we need to set the point and setup the move to the next point. Note that we are setting __mDirection__ to the ZERO vector and that we are setting __mWalking__ to false. The robot stops at each waypoint, then checks to see if it has another waypoint. Put this code just after the last one: {VERSIONS(nav="y",default="C#")} {CODE(wrap="1", colors="c#")} // check to see if we've arrived at a waypoint if (mDistance <= 0.0f) { // set our node to the destination we've just reached and set direction to 0 node.Position = mDestination; mDirection = Vector3.ZERO; mWalking = false; } else { // TO-DO: rotation code goes here // TO-DO: movement code goes here } {CODE} ---(VB.NET)--- {CODE(wrap="1", colors="vbnet")} ' check to see if we've arrived at a waypoint If mDistance <= 0F Then ' set our node to the destination we've just reached and set direction to 0 node.Position = mDestination mDirection = Vector3.ZERO mWalking = False Else ' TO-DO: rotation code goes here ' TO-DO: movement code goes here End If {CODE} {VERSIONS} Now that we have moved to the point, we need to setup the motion to the next point. Once we know if we need to move to another point or not, we can set the appropriate animation; "walking" if there is another point to go to and "idle" if there are no more destination points. This is a simple matter of setting the Idle animation if there are no more locations. Update __FrameStarted__ just below the close of the if statement: {VERSIONS(nav="y",default="C#")} {CODE(wrap="1", colors="c#")} else // nowhere to go; set the idle animation { mAnimationState = ent.GetAnimationState("Idle"); } {CODE} ---(VB.NET)--- {CODE(wrap="1", colors="vbnet")} Else ' nowhere to go; set the idle animation mAnimationState = ent.GetAnimationState("Idle") End If {CODE} {VERSIONS} Note that we have no need to set the walking animation again if there are more points in the queue to walk to. Since the robot is already walking there is no reason to tell him to do so again. However, if the robot needs to go to another point, then we need to rotate him to face that point. For now we leave a placeholder comment in the else clause; remember this spot as we will come back to it later. This takes care of when we are very close to the target position. Now we need to handle the normal case, when we are just on the way to the position but we're not there yet. To do that we will translate the robot in the direction we are travelling, and move it by the amount specified by the move variable. This is accomplished by adding the following code: {VERSIONS(nav="y",default="C#")} {CODE(wrap="1", colors="c#")} else { // TO-DO: rotation code goes here // movement code goes here node.Translate(mDirection * mWalkSpeed * deltaTime); } {CODE} ---(VB.NET)--- {CODE(wrap="1", colors="vbnet")} Else ' TO-DO: rotation code goes here ' movement code goes here node.Translate(mDirection * mWalkSpeed * deltaTime) End If {CODE} {VERSIONS} We are almost done. Our code now does everything except set up the variables required for movement. If we can properly set the movement variables our Robot will move like he is supposed to. Find the __NextLocation__ method. This method returns false when we run out of points to go to. This will be the first of code line in our function. {VERSIONS(nav="y",default="C#")} {CODE(wrap="1", colors="c#")} if (mWalkList.Count == 0) return false; else return true; {CODE} ---(VB.NET)--- {CODE(wrap="1", colors="vbnet")} If mWalkList.Count = 0 Then Return False Else Return True End If {CODE} {VERSIONS} First we will extract the destination vector from the front of the LinkedList and then add the LinkedListNode that held it to the end of the list. This will make the robot keep walking around from point to point. We will set the direction vector by subtracting the SceneNode's current position from the destination. We have a problem though. Remember how we multiplied __mDirection__ by the move amount in __FrameStarted__? If we do this, we need the direction vector to be a unit vector (that is, it's length equals one). The normalise function does this for us, and returns the old length of the vector. Handy that, since we need to also set the distance to the destination. {VERSIONS(nav="y",default="C#")} {CODE(wrap="1", colors="c#")} // update the destination using the walklist. mDestination = mWalkList.First.Value; // get the next destination. tmp = mWalkList.First; // save the node that held it mWalkList.RemoveFirst(); // remove that node from the front of the list mWalkList.AddLast(tmp); // add it to the back of the list. // update the direction and the distance mDirection = mDestination - node.Position; mDistance = mDirection.Normalise(); {CODE} ---(VB.NET)--- {CODE(wrap="1", colors="vbnet")} ' update the destination using the walklist. mDestination = mWalkList.First.Value ' get the next destination. tmp = mWalkList.First ' save the node that held it mWalkList.RemoveFirst() ' remove that node from the front of the list mWalkList.AddLast(tmp) ' add it to the back of the list. ' update the direction and the distance mDirection = mDestination - node.Position mDistance = mDirection.Normalise() {CODE} {VERSIONS} Now compile and run the code. It works! Mostly... The robot now walks to all the points, but he is always facing the Vector3.UnitX direction (his default). We will need to change the direction he is facing when he is moving towards a new way point. What we need to do is get the direction the Robot is facing, and use the __Rotate__ function to rotate the object in the right position. Insert the following code where we left the following placeholder comment earlier: {CODE(wrap="1", colors="c#")}TO-DO: rotation code goes here{CODE} Now the code. The first line gets the direction the robot is facing. The second line builds a quaternion representing the rotation from the current direction to the destination direction. The third line actually rotates the Robot. {VERSIONS(nav="y",default="C#")} {CODE(wrap="1", colors="c#")} Vector3 src = node.Orientation * Vector3.UNIT_X; Quaternion quat = src.GetRotationTo(mDirection); node.Rotate(quat); {CODE} ---(VB.NET)--- {CODE(wrap="1", colors="vbnet")} Dim src As Vector3 = node.Orientation * Vector3.UNIT_X Dim quat As Quaternion = src.GetRotationTo(mDirection) node.Rotate(quat) {CODE} {VERSIONS} A lot is going on in that small chunk code! A few questions pop into mind. The most pertenant is: "What is a Quaternion?" Basically, Quaternions are representations of rotations in 3 dimensional space. They are used to keep track of how the object is positioned in space. In the first line we call the Orientation property of the SceneNode, which returns a vector representing the way the robot is currently facing. By multiplying it by the UnitX vector, we obtain the direction the robot is currently facing, which we store in src. In the second line, the __GetRotationTo__ method gives us a Quaternion that represents the rotation from the direction the robot is facing to the direction we want him to be facing. In the third line we use the quaternion to rotate the node so that it faces the new orientation. There is only one problem with the code we have created. There is a special case where __SceneNode.Rotate__ will fail. If we are trying to turn the robot 180 degrees, the rotate code will bomb with a __DivisionByZeroError__. In order to fix that, we will test to see if we are performing a 180 degree rotation. If so, we will simply yaw the Robot by 180 degrees instead of using rotate. To do this, delete the lines we just put in and replace them with this: {VERSIONS(nav="y",default="C#")} {CODE(wrap="1", colors="c#")} // rotation code goes here Vector3 src = node.Orientation * Vector3.UNIT_X; if ((1.0f + src.DotProduct(mDirection)) < 0.0001f) { node.Yaw(180.0f); } else { Quaternion quat = src.GetRotationTo(mDirection); node.Rotate(quat); } {CODE} ---(VB.NET)--- {CODE(wrap="1", colors="vbnet")} ' rotation code goes here Dim src As Vector3 = node.Orientation * Vector3.UNIT_X If (1F + src.DotProduct(mDirection)) < 0.0001F Then node.Yaw(180F) Else Dim quat As Quaternion = src.GetRotationTo(mDirection) node.Rotate(quat) End If {CODE} {VERSIONS} All of this should now be self explanatory except for what is wrapped in that if statement. If two unit vectors oppose each other (that is, the angle between them is 180 degrees), then their dot product will be -1. So, if we dotProduct the two vectors together and the result equals 1.0f, then we need to yaw by 180 degrees, otherwise we use rotate instead. Why do I add 1.0f and check to see if it is less than 0.0001f? Don't ever forget about floating point rounding error. You should never directly compare two floating point numbers. Finally, note that in this case the dot product of these two vectors will fall in the range -1, 1. In case it is not abundantly clear, you need to know at minimum basic linear algebra to do graphics programming! At the very least you should review the [http://www.ogre3d.org/tikiwiki/Quaternion+and+Rotation+Primer|Quaternion and Rotation Primer] and consult a book on basic vector and matrix operations. Now our code is complete! Compile and run the demo to see the Robot walk the points he was given. {IMG(src="dl2028&display")}Screenshot{IMG} !Exercises for Further Study !!Easy Questions # Add more points to the robot's path. Be sure to also add more knots that sit under his position so you can track where he is supposed to go. # Robots who have outlived their usefulness should not continue existing! When the robot has finished walking, have him perform the death animation instead of idle. The animation for death is “Die”. !!Difficult Questions # One of the limitations of this class is that you cannot add points to the robot's walking path after you have created the object. Fix this problem by implementing a new method which takes in a Vector3 and adds it to the mWalkList deque. (Hint, if the robot has not finished walking you will only need to add the point to the end of the deque. If the robot has finished, you will need to make him start walking again, and call nextLocation to start him walking again.) !!Expert Questions # Another major limitation of this class is that it only tracks one object. Reimplement this class so that it can move and animate any number of objects independently of each other. (Hint, you should create another class that contains everything that needs to be known to animate one object completely. Store this in a STL map object so that you can retrieve data later based on a key.) # After making the previous change, you might have noticed that Robots can now collide with each other. Fix this by either creating a smart path finding function, or detecting when robots collide and stopping them from passing through each other. !-Here's the full code {VERSIONS(nav="y",default="C#")} {CODE(wrap="1", colors="c#")} using System; using System.Collections.Generic; using System.Text; using Mogre; using MOIS; using Mogre.TutorialFramework; namespace Mogre.Tutorials { class Tutorial : BaseApplication { AnimationState mAnimationState = null; LinkedList<Vector3> mWalkList = null; Vector3 mDirection = Vector3.ZERO; Vector3 mDestination = Vector3.ZERO; float mDistance = 0.0f; float mWalkSpeed = 50.0f; bool mWalking = false; public static void Main() { new Tutorial().Go(); } protected override void CreateScene() { // get the instance of the SceneManager SceneManager mgr = this.mSceneMgr; // set the ambient light mgr.AmbientLight = ColourValue.White; // create the robot Entity ent = mgr.CreateEntity("Robot", "robot.mesh"); SceneNode node = mgr.RootSceneNode.CreateChildSceneNode("RobotSceneNode", new Vector3(0.0f, 0.0f, 0.25f)); node.AttachObject(ent); // create some knot objects so we can see the robot's movement ent = mgr.CreateEntity("Knot1", "knot.mesh"); node = mgr.RootSceneNode.CreateChildSceneNode("Knot1Node", new Vector3(0.0f, -10.0f, 25.0f)); node.AttachObject(ent); node.Scale(0.1f, 0.1f, 0.1f); ent = mgr.CreateEntity("Knot2", "knot.mesh"); node = mgr.RootSceneNode.CreateChildSceneNode("Knot2Node", new Vector3(550.0f, -10.0f, 50.0f)); node.AttachObject(ent); node.Scale(0.1f, 0.1f, 0.1f); ent = mgr.CreateEntity("Knot3", "knot.mesh"); node = mgr.RootSceneNode.CreateChildSceneNode("Knot3Node", new Vector3(-100.0f, -10.0f, -200.0f)); node.AttachObject(ent); node.Scale(0.1f, 0.1f, 0.1f); // create the walking list mWalkList = new LinkedList<Vector3>(); mWalkList.AddLast(new Vector3(550.0f, 0.0f, 50.0f)); mWalkList.AddLast(new Vector3(-100.0f, 0.0f, -200.0f)); mWalkList.AddLast(new Vector3(0.0f, 0.0f, 25.0f)); // set idle animation mAnimationState = mgr.GetEntity("Robot").GetAnimationState("Idle"); mAnimationState.Loop = true; mAnimationState.Enabled = true; } protected override void CreateFrameListener() { // create a frame listener for FrameStarted base.CreateFrameListener(); this.mRoot.FrameStarted += new FrameListener.FrameStartedHandler(FrameStarted); } private bool NextLocation() { if (mWalkList.Count == 0) return false; else return true; } private bool FrameStarted(FrameEvent evt) { float deltaTime = evt.timeSinceLastFrame * mWalkSpeed / 20; SceneNode node = this.mSceneMgr.GetSceneNode("RobotSceneNode"); Entity ent = this.mSceneMgr.GetEntity("Robot"); if (!mWalking) // either we've not started walking or reached a way point { // check if there are places to go if (NextLocation() == true) { LinkedListNode<Vector3> tmp; // start the walk animation mAnimationState = ent.GetAnimationState("Walk"); mAnimationState.Loop = true; mAnimationState.Enabled = true; mWalking = true; // update the destination using the walklist. mDestination = mWalkList.First.Value; // get the next destination. tmp = mWalkList.First; // save the node that held it mWalkList.RemoveFirst(); // remove that node from the front of the list mWalkList.AddLast(tmp); // add it to the back of the list. // update the direction and the distance mDirection = mDestination - node.Position; mDistance = mDirection.Normalise(); } else // nowhere to go. set the idle animation. (or Die) { mAnimationState = ent.GetAnimationState("Idle"); } } else // we're in motion { // determine how far to move this frame mDistance -= mWalkSpeed * deltaTime; // check to see if we've arrived at a waypoint if (mDistance <= 0.0f) { // set our node to the destination we've just reached & reset direction to 0 node.Position = mDestination; mDirection = Vector3.ZERO; mWalking = false; } else { // movement code goes here node.Translate(mDirection * mWalkSpeed * deltaTime); // rotation code goes here Vector3 src = node.Orientation * Vector3.UNIT_X; if ((1.0f + src.DotProduct(mDirection)) < 0.0001f) { node.Yaw(180.0f); } else { Quaternion quat = src.GetRotationTo(mDirection); node.Rotate(quat); } } mAnimationState.AddTime(deltaTime); return true; } } } } {CODE} ---(VB.NET)--- {CODE(wrap="1", colors="vbnet")} Imports System.Collections.Generic Imports System.Text Imports Mogre Imports MOIS Imports Mogre.TutorialFramework Namespace Mogre.Tutorials Class Tutorial Inherits BaseApplication Private mAnimationState As AnimationState = Nothing Private mWalkList As LinkedList(Of Vector3) = Nothing Private mDirection As Vector3 = Vector3.ZERO Private mDestination As Vector3 = Vector3.ZERO Private mDistance As Single = 0F Private mWalkSpeed As Single = 50F Private mWalking As Boolean = False Public Shared Sub Main() New Tutorial().Go() End Sub Protected Overrides Sub CreateScene() ' get the instance of the SceneManager Dim mgr As SceneManager = Me.mSceneMgr ' set the ambient light mgr.AmbientLight = ColourValue.White ' create the robot Dim ent As Entity = mgr.CreateEntity("Robot", "robot.mesh") Dim node As SceneNode = mgr.RootSceneNode.CreateChildSceneNode("RobotSceneNode", New Vector3(0F, 0F, 0.25F)) node.AttachObject(ent) ' create some knot objects so we can see the robot's movement ent = mgr.CreateEntity("Knot1", "knot.mesh") node = mgr.RootSceneNode.CreateChildSceneNode("Knot1Node", New Vector3(0F, -10F, 25F)) node.AttachObject(ent) node.Scale(0.1F, 0.1F, 0.1F) ent = mgr.CreateEntity("Knot2", "knot.mesh") node = mgr.RootSceneNode.CreateChildSceneNode("Knot2Node", New Vector3(550F, -10F, 50F)) node.AttachObject(ent) node.Scale(0.1F, 0.1F, 0.1F) ent = mgr.CreateEntity("Knot3", "knot.mesh") node = mgr.RootSceneNode.CreateChildSceneNode("Knot3Node", New Vector3(-100F, -10F, -200F)) node.AttachObject(ent) node.Scale(0.1F, 0.1F, 0.1F) ' create the walking list mWalkList = New LinkedList(Of Vector3)() mWalkList.AddLast(New Vector3(550F, 0F, 50F)) mWalkList.AddLast(New Vector3(-100F, 0F, -200F)) mWalkList.AddLast(New Vector3(0F, 0F, 25F)) ' set idle animation mAnimationState = mgr.GetEntity("Robot").GetAnimationState("Idle") mAnimationState.[Loop] = True mAnimationState.Enabled = True End Sub Protected Overrides Sub CreateFrameListener() ' create a frame listener for FrameStarted MyBase.CreateFrameListener() Me.mRoot.FrameStarted += New FrameListener.FrameStartedHandler(AddressOf FrameStarted) End Sub Private Function NextLocation() As Boolean If mWalkList.Count = 0 Then Return False Else Return True End If End Function Private Function FrameStarted(evt As FrameEvent) As Boolean Dim deltaTime As Single = evt.timeSinceLastFrame * mWalkSpeed / 20 Dim node As SceneNode = Me.mSceneMgr.GetSceneNode("RobotSceneNode") Dim ent As Entity = Me.mSceneMgr.GetEntity("Robot") If Not mWalking Then ' either we've not started walking or reached a way point ' check if there are places to go If NextLocation() = True Then Dim tmp As LinkedListNode(Of Vector3) ' start the walk animation mAnimationState = ent.GetAnimationState("Walk") mAnimationState.[Loop] = True mAnimationState.Enabled = True mWalking = True ' update the destination using the walklist. mDestination = mWalkList.First.Value ' get the next destination. tmp = mWalkList.First ' save the node that held it mWalkList.RemoveFirst() ' remove that node from the front of the list mWalkList.AddLast(tmp) ' add it to the back of the list. ' update the direction and the distance mDirection = mDestination - node.Position mDistance = mDirection.Normalise() Else ' nowhere to go. set the idle animation. (or Die) mAnimationState = ent.GetAnimationState("Idle") End If Else ' we're in motion ' determine how far to move this frame mDistance -= mWalkSpeed * deltaTime ' check to see if we've arrived at a waypoint If mDistance <= 0F Then ' set our node to the destination we've just reached & reset direction to 0 node.Position = mDestination mDirection = Vector3.ZERO mWalking = False Else ' movement code goes here node.Translate(mDirection * mWalkSpeed * deltaTime) ' rotation code goes here Dim src As Vector3 = node.Orientation * Vector3.UNIT_X If (1F + src.DotProduct(mDirection)) < 0.0001F Then node.Yaw(180F) Else Dim quat As Quaternion = src.GetRotationTo(mDirection) node.Rotate(quat) End If End If End If mAnimationState.AddTime(deltaTime) Return True End Function End Class End Namespace{CODE} {VERSIONS} ! !Credits Original version by Clay Culver. C# changes by DigitalCyborg. Mogre changes by Djthorn and [/addonforums/memberlist.php?mode=viewprofile&u=14850|McDonte].
Search by Tags
Search Wiki by Freetags
Latest Changes
Projects using OGRE
Building Your Projects With CMake
Compiled API Reference
Overlay Editor
Introduction - JaJDoo Shader Guide - Basics
RT Shader System
RapidXML Dotscene Loader
One Function Ogre
One Function Ogre
...more
Search
Find
Online Users
136 online users
OGRE Wiki
Support and community documentation for Ogre3D
Ogre Forums
ogre3d.org
Log in
Username
Password
CapsLock is on.
Remember me (for 1 year)
Log in