MULTIMEDIA

Game Programming with DirectX : Time-Based Simulations (part 1)

5/15/2013 7:34:53 PM

Time and the measurements that are based on it are very important in video games. When it comes to animation, time-based calculations allow for consistent updates to occur in real time. When calculations are based on the frame rate, the simulation can slow down or speed up based on the frame rate change. On PCs there is no way to guarantee that a game will run at the same performance rate from one machine to another.

The term frame-based calculation refers to calculating some value every frame—for example, if the position of an object was moved every frame like the following.

position += direction;

Therefore, the speed at which the object moves is solely dependent on the frame rate. If there is a sudden drop in the frame rate, the object will appear to move slower. Usually this is not the effect developers have in mind, especially when they intend for an object or some other calculation to be updated at a specific rate of speed.

If you use time-based calculations, it does not matter if a game’s frame rate suddenly drops to a crawl or jumps to very high levels because the simulation updates consistently. For example, if an object is being moved five units per second, it doesn’t matter what the frame rate is because a second is still a second, regardless of frame rate. Therefore, when the next update call is made, the elapsed time is examined and the object is moved the distance it would have moved during the time frame.

If too much time goes by between update calls, the object can appear to jump from one location to another. This can also be seen in online games where a lot of lag causes the updates of some players to occur so far apart that a jumping effect can be observed. However, by using time-based calculations, we can keep updates consistent and accurate.

Line Path Animations

The first type of animation path we will look at is a simple straight-line path. A straight line is made up of two end points that go from point A to point B. When we move an object, we move the object starting at point A, and it continues until it reaches point B. We use linear interpolation to gradually move the object’s position from point A to point B. For example, if an object has been linearly interpolated between two points at 50%, then the object’s position is midway between point A and point B. Take a look at Figure 1 for an example of this.

Figure 1. An example of a straight-line path.


To interpolate between two numbers, we can use linear interpolation. Linear interpolation has been used for many things, from moving objects to character animation. To perform linear interpolation, we need three pieces of information. The first two pieces of information are the two numbers between which we are interpolating. The third piece of information needed is a scalar value that is a value from 0 to 1, with 1 being 100%. Using 0% will basically say we are at point A, and using 100% means we are at point B. Any value between 0% and 100% will place us somewhere between point A and point B. The following equation makes up linear interpolation, where Final is the interpolated value, A is point A, B is point B, and dt is a percentage to interpolate between A and B.

Final = (B - A) * dt + A;

To perform straight-line animation, we need point A, point B, and a percentage. We can have a bunch of straight lines that form a complete path, such a guard patrolling an area or a car driving around a neighborhood block. For the mathematics we can use 3D vectors for the end points and a floating-point value for the percent of interpolation. Interpolating between a 3D vector is not that much different than what we did for single numbers. The only real difference is that we are interpolating three values (X, Y, and Z axes) instead of just the one. An example of this can be seen as follows:

Final.x = (B.x - A.x) * Scalar + A.x;
Final.y = (B.y - A.y) * Scalar + A.y;
Final.z = (B.z - A.z) * Scalar + A.z;

Curve Path Animations

The next type of animation path we will look at is the curve path. This path goes from point A to point B in a curve instead of a straight line. To create a curve with straight lines would take a lot of very small lines connected to each another. The more lines you use, the smoother the curve will look. The problem is that this is still not perfect and would take a huge amount of data. A different way to create a curve path is to use two points for point A to point B and two control points that define the curve, giving it a total of four points. This type of curve is known as a cubic Bezier curve. The control points are used to bend the line into a curve, so these two values determine how the curve will appear, while the end points specify the starting and ending locations. Take a look at Figure 2 for an example of a cubic Bezier curve.

Figure 2. An example of a cubic Bezier curve.


The straight line uses two points and a scalar value to calculate the final position of the object. For the cubic Bezier curve we use four points and a scalar value. The curve can bend and twist in any way based on the position of the control points. Like the straight-line path, a value of 0% places our object at point A, and a value of 100% places our object at point B. The equation used to calculate a position along this curve is not as simple as it is with a straight line. The equation is shown as follows, where the points in the equation are A for point A, B for point B, C1 for control point 1, and C2 for control point 2. Also in the equation is S for the scalar, S2 for (scalar * scalar) and S3 for (scalar * scalar * scalar).

Final = A * (1 – S)3 + C1 * 3 * S * (1 – S)2 + C2 * 3 * S2 * (1 – s) + B * S3

Routes

So far we’ve look at a few different paths that can be used for moving objects in a 3D scene. The paths by themselves are not really helpful in representing a lot of different movements. It is only when we string them together that we get something useful for our games. Using multiple paths allows us to define an entire route of animation along which an object can travel. This route can be made up of a lot of straight lines or curve paths and, when character animation is applied, can add a huge amount of detail and believability to our 3D games. Additional types of paths that can be created to add to the mix include:

  • Circular paths

  • Splines

  • Graphs used for path-finding (such as A* for artificial intelligence)

  • Elliptical paths

  • Any other path that can be defined by a start and end position

To create a route, we need to list the paths that make up that route, and we then travel through each path. Once we hit that end of a specific path, we move to the next path, reset the start time, and travel along that until we hit the end of it. We keep doing this until we’ve hit the last path, which would complete the route. At this point we can either stop the movement, or we can loop and start it all over again from the beginning. Starting from the beginning is the best bet if we want to have our patrolling guards or other characters moving around nonstop until something forces them to perform another action—for example, if the gamer shoots at the character or anything else that can cause the AI to take action.

Once we have a route system, we can take things one step further by allowing the route information to be read in by a file, and we can apply a route to our camera.Creating routes this way will move us toward creating cut-scenes, which is something that is very popular in today’s games.

Animation Paths Demo

Animation paths are predefined paths that, when put together, create a route from one location to another along which a character or object can travel. A collection of routes for a scene can constitute a cut-scene if the routes are used for story-telling purposes. Add a walking animation to characters when using animation paths, and you will have the type of behavior that we see in many games. An example of this can be seen in Call of Duty 4 for the Xbox 360 and PlayStation 3, where enemy characters walk around patrolling an area. When you walk in their field of view, the enemies react. This reaction is mostly aggression on the part of the enemy AI character, but the reaction can be anything such as running away, running from the character’s current location to the location of the nearest alarm button, taking cover from possible enemy gun fire, and so on.

We will create a class for each type of animation path in our system. We will then create a class that will store a list of paths that make up an entire route. The types of paths we will be creating are straight-line paths and curve paths.

The Animation Path Classes

The demo specifies a base class called Path that has two classes that derive from it called StraightLinePath and CurvePath. The Path base class has two functions and three variables.

The Release() function from the Path class is used to delete the next path in the list. The paths are specified by using a simple link list setup, where each path has a pointer to the next path in the list. The Release() function’s purpose is to delete the path that is next in the link. Since we are not using arrays, we need a way to release these objects from memory, and in a link list this is done by traversing the nodes one at a time and deleting them. Also, using a link list allows us to add paths to the list without having to allocate or re-allocate an array every time the list grows.

The GetPathPos() function from the Path class is used to get the position within the path based on the percentage (dt) that is passed in the parameter. This is used to return to the caller the time-based position that marks where the object is while it travels along the current path.

The variables of the Path class are straightforward. The first variable is the next pointer, which is used for the link list behavior. The second variable is the start time of the animation for the path. The third variable is the total time it takes to travel along the animation path. The start time is equal to 0 if this is the first path in the list, but if it is not the first in the list, the start time equals the last path’s start time plus the last path’s total time. In other words, the path, assuming it’s not the first in the list, has a start time that equals the end time of the path that came before it.

The Path base class is shown in Listing 1. Listing 2 shows the Path class’s constructor, destructor, and Release() functions. The GetPathPos() function is a virtual function that is to be implemented by each class that derives from the Path base class.

Listing 1. The Path Base Class
class Path
{
   public:
      Path();
      ~Path();

      void Release()
      virtual Vector3D GetPathPos(float dt) = 0;

   public:
      float m_start;
      float m_total;

      Path *m_next;
};

Listing 2. The Path Class’s Functions
path::path()
{
   m_start = 0;
   m_total = 0;
   m_next = NULL;
}


Path::~Path()
{
   Release()
}
void Path::Release()
{
   if(m_next)
   {
      m_next->Release()
      delete m_next;
      m_next = NULL;
   }
}

The StraightLinePath class has a member variable for the start position and one for the end position, and it implements the GetPathPos() function from the Path base class. The StraightLinePath class declaration is shown in Listing 3. Listing 4 shows the class’s constructor, which sets the two member variables, and the GetPathPos() function. In the GetPathPos() function, the equation we looked at earlier for the linear interpolation is used for the line.

Listing 3. The StraightLinePath Class Declaration
class StraightLinePath : public Path
{
   public:
      StraightLinePath(Vector3D start, Vector3D end);

      Vector3D GetPathPos(float dt);

   public:
      Vector3D m_startPos;
      Vector3D m_endPos;
};

Listing 4. The StraightLinePath Class Functions
StraightLinePath::StraightLinePath(Vector3D start, Vector3D end)
{
   m_startPos = start;
   m_endPos = end;
}

Vector3D StraightLinePath::GetPathPos(float dt)
{
   return ((m_endPos - m_startPos) * dt + m_startPos);
}

The CurvePath class has a member variable for the start position, one for the end position, and two positions for each control point, and it implements the GetPathPos() function from the Path base class. The CurvePath class declaration is shown in Listing 5, and the class’s functions are shown in Listing 6

Listing 5. The CurvePath Class Declaration
class CurvePath : public Path
{
   public:
      CurvePath(Vector3D p1, Vector3D c1,
                Vector3D c2, Vector3D p2);

      Vector3D GetPathPos(float dt);

   public:
      Vector3D m_p1;
      Vector3D m_control1;
      Vector3D m_control2;
      Vector3D m_p2;
};

Listing 6. The CurvePath Class Functions
CurvePath::CurvePath(Vector3D p1, Vector3D c1,
                     Vector3D c2, Vector3D p2)
{
   m_p1 = p1;
   m_control1 = c1;
   m_control2 = c2;
   m_p2 = p2;
}

Vector3D CurvePath::GetPathPos(float dt)
{
   return (m_p1 * (1.0f - dt) * (1.0f - dt) * (1.0f - dt) +
           m_control1 * 3.0f * dt * (1.0f - dt) * (1.0f - dt) +
           m_control2 * 3.0f * dt * dt * (1.0f - dt) +
           m_p2 * dt * dt * dt);
}

Each of these classes can be found in Route.h and Route.cpp of the Animation Paths demo’s source files.

Other  
 
Top 10
Review : Sigma 24mm f/1.4 DG HSM Art
Review : Canon EF11-24mm f/4L USM
Review : Creative Sound Blaster Roar 2
Review : Philips Fidelio M2L
Review : Alienware 17 - Dell's Alienware laptops
Review Smartwatch : Wellograph
Review : Xiaomi Redmi 2
Extending LINQ to Objects : Writing a Single Element Operator (part 2) - Building the RandomElement Operator
Extending LINQ to Objects : Writing a Single Element Operator (part 1) - Building Our Own Last Operator
3 Tips for Maintaining Your Cell Phone Battery (part 2) - Discharge Smart, Use Smart
REVIEW
- First look: Apple Watch

- 3 Tips for Maintaining Your Cell Phone Battery (part 1)

- 3 Tips for Maintaining Your Cell Phone Battery (part 2)
VIDEO TUTORIAL
- How to create your first Swimlane Diagram or Cross-Functional Flowchart Diagram by using Microsoft Visio 2010 (Part 1)

- How to create your first Swimlane Diagram or Cross-Functional Flowchart Diagram by using Microsoft Visio 2010 (Part 2)

- How to create your first Swimlane Diagram or Cross-Functional Flowchart Diagram by using Microsoft Visio 2010 (Part 3)
Popular Tags
Microsoft Access Microsoft Excel Microsoft OneNote Microsoft PowerPoint Microsoft Project Microsoft Visio Microsoft Word Active Directory Biztalk Exchange Server Microsoft LynC Server Microsoft Dynamic Sharepoint Sql Server Windows Server 2008 Windows Server 2012 Windows 7 Windows 8 Adobe Indesign Adobe Flash Professional Dreamweaver Adobe Illustrator Adobe After Effects Adobe Photoshop Adobe Fireworks Adobe Flash Catalyst Corel Painter X CorelDRAW X5 CorelDraw 10 QuarkXPress 8 windows Phone 7 windows Phone 8
Visit movie_stars's profile on Pinterest.