Animation With Timers

June 15, 2011 by Dave · 1 Comment
Filed under: C#, Game Programming, XNA 

Last time I talked about using timers for scheduling events by simply keeping track of a time limit and how much time elapsed. Another good use for timers is performing some action over time, such as modifying alpha to fade an object in or out, or sliding an object from one location to another.

Let’s use the fading example. Fading is often done by animating transparency. The object starts out completely transparent, and gradually becomes less transparent until it’s fully opaque. An object is fully transparent when it’s drawn using alpha blending with an alpha of zero, and fully opaque when alpha is one. By quickly changing alpha from 0 to 1 over time, and redrawing the object  with the new alpha, it appears to fade into view.

You might say that when alpha is 0 the object is 0% visible, and when alpha is 1 it’s 100% visible. Thinking about the starting and ending values as percentages is very useful. For example, If you’re moving an object from one position to another, the object hasn’t moved at all at 0%, it’s moved halfway at 50%, and it’s moved all the way at 100%.  Another example, if you’re fading in a song, it’s completely silent at 0% volume, it’s medium loudness at 50% volume, and it’s full volume at 100%. Being able to animate a value from 0 to 1 has all kinds of applications in a video game.

So we need to be able to animate a value from 0 to 1, and we want it to take a specified amount of time. In the last post we already made a timer that can run for a specified amount of time.

In that timer, the variable Elapsed keeps track of how much time has elapsed since the timer started. Elapsed starts out at 0, and as the timer runs it progresses to Limit, which is when the timer expires. Looking at it another way, Elapsed has progressed 0% when it starts, and 100% when it ends. In order to calculate the progress as a percentage, we simply divide Elapsed by Limit.

Let’s change the SimpleTimer class so it calculates this percentage for us. We’ll save it in a field called Time. Here’s the class as it stood at the end of the last post.

public class SimpleTimer
{
  public float Limit;
  public float Elapsed;

  public SimpleTimer(float limit)
  {
    Limit = limit;
    Stop();  // make sure it's not running
  }

  public void Start()
  {
    Elapsed = 0.0f;
  }

  public void Stop()
  {
    Elapsed = -1.0f;
  }

  public bool Update(float elapsedTime)
  {
    bool result = false;

    if (Elapsed >= 0.0f)
    {
      Elapsed += elapsedTime;
      result = Elapsed >= Limit;
    }

    return result;
  }
}

 

First, add our Time field right after Elapsed:

    public float Limit;
    public float Elapsed;
    public float Time;   // <-- add this

 

Next, add an UpdateTime method that does the percentage calculation and saves it to the Time fied:

    private void UpdateTime()
    {
      Time = Elapsed / Limit;
    }

 

Now, every time we modify Elapsed we need to call UpdateTime so Time is recalculated. We set Elapsed to 0 in the Start method, so we need an UpdateTime call there:

    public void Start()
    {
      Elapsed = 0.0f;
      UpdateTime();        // <-- add this
    }

We also modify Elapsed in the Update method:

      
      if (Elapsed >= 0.0f)
      {
        Elapsed += elapsedTime;
        result = Elapsed >= Limit;
        UpdateTime();            // <-- add this
      }

And that’s it.  Here’s the full class:

  public class SimpleTimer
  {
    public float Limit;
    public float Elapsed;
    public float Time;

    public SimpleTimer(float limit)
    {
      Limit = limit;
      Stop();
    }

    public void Start()
    {
      Elapsed = 0.0f;
      UpdateTime();
    }

    public void Stop()
    {
      Elapsed = -1.0f;
    }

    private void UpdateTime()
    {
      Time = Elapsed / Limit;
    }

    public bool Update(float elapsedTime)
    {
      bool result = false;

      if (Elapsed >= 0.0f)
      {
        Elapsed += elapsedTime;
        result = Elapsed >= Limit;
        UpdateTime();
      }

      return result;
    }
  }

 

Now, as our timer is running, it’s always calculating how far it’s gone towards Limit as a percentage, which gives us a value between 0 and 1.  If we’re animating something like alpha that already takes a value between 0 and 1 then we can just use Time directly. But what if we need to change from one color to another, or move an object from one position on the screen to another?

This is where interpolation comes into play. The dictionary defines interpolation as “the process of determining the value of a function between two points at which it has prescribed values”. The “prescribed values” are our starting and ending colors, or our starting and ending positions. There are multiple ways to do the interpolation depending on your needs. A common one is Linear Interpolation, and that’s what we’ll use here. I’m just going to describe a couple of methods supplied by the XNA framework. If you want to learn how linear interpolation works you should be able to find the information on the web pretty easily.

XNA provides several Lerp (Linear intERPolation) methods:

MathHelper.Lerp
Vector2.Lerp
Vector3.Lerp
Matrix.Lerp
Color.Lerp
Quaternion.Lerp

 

Each of these takes starting and ending values of the appropriate data type, an amount value between 0 and 1, and returns a new value that’s amount percent between the starting and ending values. For example, MathHelper.Lerp performs linear interpolation on float values. Here are some sample values and what the function returns:

MathHelper.Lerp(10, 20, 0.0f);  // returns 10
MathHelper.Lerp(10, 20, 0.2f);  // returns 12
MathHelper.Lerp(10, 20, 0.5f);  // returns 15
MathHelper.Lerp(10, 20, 0.8f);  // returns 18
MathHelper.Lerp(10, 20, 1.0f);  // returns 20

 

To move an object you can use the Vector2.Lerp method and pass in Time from our timer class as amount. In this example position will start at <50, 50> and work its way in a straight line towards <750, 400> as timer.Time changes from 0 to 1.

Vector2 start = new Vector2(50, 50);
Vector2 end = new Vector2(750, 400);
Vector2 position = Vector2.Lerp(start, end timer.Time);

 

Similarly, color can be interpolated between two values like this:

color = Color.Lerp(Color.CornflowerBlue, Color.White, timer.Time);

 

I’ve included a sample project that contains the timer class as well as a simple demonstration that moves a square across the screen and cycles colors using the timer and linear interpolation.

There are many more useful things you can add to your timers, such as pausing, reversing, auto-reversing, auto-restarting. It’s also very useful to add events that fire when the Time value updates, when the timer ends, and so on.

Download SimpleTimer.zip

Make Your Time!

June 1, 2011 by Dave · Leave a Comment
Filed under: C#, Game Programming, WP7DEV, XNA 

It’s going on seven months since my last post, which is kind of pathetic. When finishing a large project, like the WP7 port of Guardian, my brain tends to shut down for awhile for recharging. That, on top of starting a new job back in November, lead to a much longer blogging hiatus than intended. So, how about something simple to get back into the swing of things. And since we’re talking about time…

Very often in video games there is a need to perform some action after a certain amount of time elapses. Examples include deciding when to show the next frame of an animation, deciding when to spawn the next enemy, hiding a message after it’s been displayed for awhile, and so on. For a most basic implementation of this we need two values: something to describe how long we want to wait, and something to track how long we’ve been waiting.


float timerLimit = 2.0f;
float timerElapsed = 0.0f;

We also need to pick a unit of time to work with. Seconds seem to be pretty convenient, and that’s what we’ll use here. So the value of 2.0 for timerLimit means we want to wait 2 seconds before doing something.

Once we have these values established it’s a matter of updating timerElapsed each frame and checking it against timerLimit to see if the desired amount of time has passed. Since the game programming API of choice here is XNA, the proper place to do this updating is in the game’s Update() method.

protected override void Update(GameTime gameTime)
{
  // grab the number of seconds that have elapsed since the last frame, including fractional seconds,
  // so if you're running at 60fps this value will be 0.0166667 more or less, or 1/60th of a second.
  float elapsedTime = (float)gameTime.ElapsedGameTime.TotalSeconds;

  // add the elapsed time to our timer
  timerElapsed += elapsedTime;

  // if the timer has exceed our limit then do something
  if (timerElapsed >= timerLimit)
  {
    // TODO : do something
  }
}

Once timerElapsed passes timerLimit then we can perform our action. There’s a problem with this code though. Once the timer exceeds our limit it will keep executing the action every frame thereafter. While this may be what we want sometimes, in many cases, if not most, it isn’t. So we need a way to turn off the timer, or restart it.

To restart it we can simply reset timerElapsed back to zero if we want to the event to fire again in the same amount of time. To stop the timer we can use timerElapsed as a flag and set to -1 to indicate that the timer is inactive. Our timer code now looks like this:

  // update the timer if it's enabled
  if (timerElapsed != -1)
  {
    // add the elapsed time to our timer
    timerElapsed += elapsedTime;

    // if the timer has exceed our limit then do something
    if (timerElapsed >= timerLimit)
    {
      // TODO : do something

      // set the elapsed time back to 0 to schedule the event again,
      // otherwise set it to -1 to disable the timer
      timerElapsed = -1.0f;
    }
  }

To start the timer initially our code needs to set timerElapsed to 0 which will being the process of tracking elapsed time until timerLimit is reached.

This code practically begs to become a class, so let’s not disappoint it.

public class SimpleTimer
{
  public float Limit;
  public float Elapsed;

  public SimpleTimer(float limit)
  {
    Limit = limit;
    Stop();  // make sure it's not running
  }

  public void Start()
  {
    Elapsed = 0.0f;
  }

  public void Stop()
  {
    Elapsed = -1.0f;
  }

  public bool Update(float elapsedTime)
  {
    bool result = false;

    if (Elapsed >= 0.0f)
    {
      Elapsed += elapsedTime;
      result = Elapsed >= Limit;
    }

    return result;
  }
}

Our previous example now looks like this:


SimpleTimer timer = new SimpleTimer(2.0f);
protected override void Update(GameTime gameTime)
{
  // grab the number of seconds that have elapsed since the last frame, including fractional seconds,
  // so if you're running at 60fps this value will be 0.0166667 more or less, or 1/60th of a second.
  float elapsedTime = (float)gameTime.ElapsedGameTime.TotalSeconds;

  if (timer.Update(elapsedTime))
  {
    // TODO : do something

    timer.Stop();  // or use timer.Start() to restart it
  }
}

Somewhat less crappy.

Scheduling events like this is one use for a timer. Another thing that’s often needed is the ability to perform an action over time, such as fading out text. The next post will cover that.

WP7 Planet Defender Progress Video

September 23, 2010 by Dave · Leave a Comment
Filed under: C#, Game Programming, WP7DEV, XNA, XNA 4.0 

I’ve been working on a Windows Phone 7 port of Guardian and finally have something to show for it. All of the systems are in place now, just need to do a lot of tuning and game play tweaking. Of course, at this point I have no idea how it’s going to perform on an actual phone, but it should do fairly well. Hopefully there won’t be too much optimization required after I get my hands on some hardware.

I recorded the video using Fraps while running the version compiled for Windows. Keeping a version working in Windows has made testing and debugging work much more smoothly than having to deploy to the simulator each time I make a change. It’s also a fairly simple matter to simulate the touch functionality using the mouse.

Using CLR Profiler 2.0 with XNA 4.0

September 6, 2010 by Dave · 9 Comments
Filed under: C#, XNA 4.0 

By default (at least on my computer, running Windows 7), CLR Profiler 2 won’t work with new XNA apps since they utilize the new .NET framework.  It looks like it’s working when you try it, but when it shows the final statistics window it’s empty.  Fortunately, it’s possible to enable support using the new profiler compatibility settings functionality, which for this case involves simply setting the COMPLUS_ProfAPI_ProfilerCompatibilitySetting environment variable before running CLR Profiler.

Here’s what I did:

Create a batch file called start_clr_profiler.bat with this content, save it in Documents or wherever:


c:
cd "\program files (x86)\clrprofiler\binaries\x86
set COMPLUS_ProfAPI_ProfilerCompatibilitySetting=EnableV2Profiler
clrprofiler

It goes without saying that you’ll need to change the drive and path to where you have CLR Profiler installed.

Once you have this file, create a shortcut  to it on your desktop.  Right click on the shortcut, select Properties, click the Advanced button and check “Run as Administrator”.  Click OK a couple of times, and you’re good to go. Just start the profiler with the batch file and the environment variable will be set, and the profiling magic will happen.

You could also set that environment variable at the user or machine level so it’s set all the time, but I don’t know what ramifications that has so prefer setting it just when needed. Happy garbage collecting!

Texture Modification in XNA 3.1

September 5, 2010 by Dave · Leave a Comment
Filed under: C#, Game Programming, WP7DEV, XNA, XNA 3.1 

I’ve had a couple of questions about what changes are needed to get the texture modification tutorial to work in XNA 3.1.

So, here’s a 3.1 version of the project, and a quick overview of the major things that need to change.

  • You need to create the depth/stencil buffer yourself, set it on the GraphicsDevice when setting the render target, and restore the previous buffer when you’re done.
  • RenderTarget2D can’t be used directly as a texture, you must call RenderTarget2D.GetTexture instead and use that when drawing.
  • Render states are all set in GraphicsDevice.RenderState instead of the various classes used in 4.0.
  • Various minor syntax changes.

Some Sugar with your Syntax?

August 11, 2010 by Dave · 2 Comments
Filed under: C#, Crappy Code 

In my recently posted tutorial, I created the render state objects using some old-school syntax.

StencilAlways = new DepthStencilState();
StencilAlways.StencilEnable = true;
StencilAlways.StencilFunction = CompareFunction.Always;
StencilAlways.StencilPass = StencilOperation.Replace;
StencilAlways.ReferenceStencil = 1;
StencilAlways.DepthBufferEnable = false;

You can do this in a much prettier way nowadays.

StencilAlways = new DepthStencilState()
{
  StencilEnable = true,
  StencilFunction = CompareFunction.Always,
  StencilPass = StencilOperation.Replace,
  ReferenceStencil = 1,
  DepthBufferEnable = false
};

That is so much nicer to read. I’ve seen this syntax before, but 20 years of habits die hard and I rarely remember to use it. Hopefully it will stick now, and make my crappy code that much less crappy.

Next Page »