Sunday, July 26, 2009

HOW TO FIX LOCAL ISSUES TO CONNECT YOUR XBOX 360 TO THE XBOX LIVE SERVERS

A few weeks ago I had to reset my router because Windows Vista was giving me problems with my desktop’s wired LAN & WAN connections (note: problem fixed when I upgraded to Windows 7).

The thing is that when I re-configured my router using the file with the last-saved settings, my XBox was having problems when attempting to connect to XBox Live’s channels (both, arcade and indie). In fact, from time to time I used to receive messages saying my connection got lost due to errors 80072741 and so on (as you will see in a moment, I just forgot to persist to disk the proper configuration values of my router. Sigh!).

When that happens, and assuming that the XBox Live Team isn’t working on the servers(testing, updating, etc.), then something wrong must be happening on your side (like in my case).

So, what could be possibly wrong?

  1. Your router is broken,
  2. Your router has a faulty/corrupt firmware,
  3. You’re connecting your XBox 360 using a faulty wire,
  4. Your 360 cannot retrieve a local IP address from the router,
  5. Your router’s firewall is preventing your 360 from connecting to the Internet,
  6. Your router is performing some strict or moderate Network Address Translation tasks (NAT),
  7. You get some weird error messages and or lose connection when playing some games online on multiplayer mode, and
  8. Other connectivity problems.

If one, a few or some of these happened to you, then maybe the following tips could help to solve the issues with your connection. Meaning? No solution guaranteed.

SO USE THESE TIPS AT YOUR OWN RISK!

Now that you were warned, read on carefully …

Your router is broken.

Buy a new one in case it’s not easy or worth repairing. In the meantime you can try to connect directly through your (DSL) modem.

Your router has a faulty/corrupt firmware.

Go to the manufacturer’s support page, download the latest firmware for your router’s model, and update it (first, read your router’s manual to find out how to do the update).

You’re connecting your XBox 360 using a faulty wire.

Just change the latter and try again.

But what if I’m using a wireless connection? Then check your router’s wireless settings, like, say the security method and password.

Your XBox 360 cannot retrieve a local IP address from the router.

First check your network settings on your XBox 360: whether you want to get a dynamic or static IP address, the values for primary and secondary “Domain Name System” (DNS) addresses, the IP address of the gateway, etc.

Now, check on the router the maximum number of connections allowed at the same time. Maybe you are already using all of them.

If the router is currently providing a “Dynamic Host Configuration Protocol” service (DHCP), then any computer, console and or LAN/WAN device may be configured to attempt to get an IP address from the router, dynamically.

This should work fine with your XBox 360 console for supported routers, but in case it doesn’t, just configure the console to get a static IP address.

Which one? Well, simply put, an IP address that you know other systems won’t normally use (for instance, if you have two computers and your console and you are allowing, say, 8 connections, then set the last one as the static one for your console and you’ll probably do just fine).

In order to set a static IP address, on the 360’s Dashboard browse to “System –> Network Settings –> Edit Settings”, and then enter:

  • The static IP address for the console,
  • The Subnet mask (same than the one set in the router),
  • The Gateway IP address,
  • The Primary and Secondary DNS addresses.

Try the connection again, and if everything goes well, your 360 now should have access to the LAN.

Your router’s firewall is preventing your XBox 360 from connecting to the Internet.

Having access to the local network doesn’t mean that the router has also granted access to the Internet. Sometimes, the firewall of your router stops any attempt of your device and or a set of IP addresses to reach the Internet.

If that is the case, then check all security rules set on your router. Most routers allows you to specify either each IP you want to allow access to the Internet, a range of IP addresses and even your devices’ “Media Access Control” addresses (MAC).

Since at home, in my case, the number of devices that connect to the Internet is low, I just specify each MAC address and presto!

It may also happen that Internet access is only available to certain days and hours per day. So you should check those rules, too.

Your router is performing some strict or moderate NAT tasks.

This is one of the most popular issues when an XBox 360 console attempts to establish a secure connection with the XBox Live’s servers.

In short, not all ports and protocols needed to establish an optimal communication are (properly) set.

Ok … uhh … what?

Do the following: test your 360’s connection to the LAN, the Internet and finally Live’s servers, and if you get the result that two out of three work fine, being the latter the one that “partially” fails, then your router’s NAT functionality is not “Open”.

In fact, if that is the case, you can connect to Xbox Live but the connection is not optimal for cases when you want to play, chat, talk and even accept a friend’s invite online.

In order to configure the ports and protocols needed to establish a “sound” connection to the XBox Live services, you either:

  • Place your console in the “demilitarized zone” (DMZ), or
  • Manually configure the specific values using “Port forwarding”.

Note: in order to do one of these, you must first set a static IP address on the console.

DMZ means, in short, that you open all ports and protocols in order to communicate to a certain device with a specified IP address. So your device is placed inside an unsecured zone or if you prefer an unrestricted area. DMZ is too risky!

The alternative (the one I prefer): to manually set only the pair of ports & protocols actually needed for the connection for a certain device with a static IP address (in this case, your 360’s IP address).

All you have to do in the latter option, is selecting the “Port Forwarding” tab in your router and the setting something similar to:

  • Applications name (say, “XBox360Live”),
  • Each port range (“from 80 to 80”, and so on),
  • The accepted protocols (UDP/TCP/Both),
  • The local IP address (that is, your 360’s static IP address value), and
  • Check “Enable” (or whatever option you need to activate the rule).

Read this article in order to know which ones you must set.

As I said at the beginning of this post, the above-mentioned issue was the one preventing my 360 console from connecting to Xbox Live, properly. In short, the configuration file I had saved long ago as a backup didn’t include these settings. Fixed!

Now, continuing with the topic …

Optional: some recommend (I don’t) that when you receive the error code 8007274c, unchecking an option similar to “block anonymous Internet requests” on your router’s firewall may help. Plus, in some cases, clearing your console’s cache (warning: doing the latter will also erase all software updates! You will have to load the updates again) and or verifying that the proper DNS values are set.

By the way, port forwarding only works for one application at a time, which means that if two applications on the LAN attempt to get access, say, to the Internet using the same port, a conflict occurs and if your router cannot resolve the situation, connectivity gets affected … maybe your 360 is one of the devices in conflict!

If your router’s firewall has a log, check it to see which device and application is the source of the conflict. You can also try to check the log of your devices’ respective firewalls –if any.

If you cannot identify what’s causing the port conflict, I guess that turning off all devices but the 360 console, should fix this connectivity issue, so you can play some games online again.

You get some weird error messages and or lose connection when playing some games online on multiplayer mode.

If you do have a valid Live Gold Membership, then this is somewhat related to the port issue.

Some games need a few ports open for certain protocols (TCP/UDP/Both), which differ from the ones listed here.

Again, if you don’t want to set (the IP address of) your console on DMZ, then you should manually set both, port plus protocol, for that game.

Ok, how can I know which pair should I set? Well, you can either do an Internet search to find out or visit sites like http://www.portforward.com/, which have a lot of info in this respect, for a list of routers and services (including 360’s connections).

Other connectivity problems … plus fixes?

Say, your router must support a minimum MTU (“Maximum Transmission Unit”); in case of XBox Live that is: 1364. Or your ISP’s DSL modem is not good enough (request a change).

It would be great to know both, the problem you experienced when connecting your 360 to XBox Live and, of course, the fix.

Well, this is it. I hope you find this info useful.

Enjoy your games!
~Pete

> Link to Spanish version.

Friday, July 24, 2009

XNA CREATORS CLUB ONLINE REVAMP

Wow! When I woke up this morning and turned on my desktop computer I found quite pleasant news on the creators’ site: it has been revamped!

The homepage has gone through some changes in its look: the news, the ads, the general info have been all rearranged in a more attractive way! Just check it out.

Plus, there’s some new panels like “Top Movers” … wait! What’s a “top mover? From now on, all you do in XNA CCO will give you reputation, either in a positive or negative way:

  • Good contribution: clink! Your reputation moves up. Congrats!
  • Bad contribution: bam! Behave …

Please read this article to get detailed info on how reputation works.

But wait! There’s more:

  • New Countries: Japan an Germany (and also updates to Singapore and Sweden),
  • Tokens: you are a premium member of XNA CCO, you create and submit your games, you receive 50 tokens per game title! Be smart: use them to “increase awareness of your game”,
  • Game Updates: when you submit and publish a new version of your game to the XBox 360, a notice will pop up for existing customers asking if they want to download the newest version,
  • 3.1 Submission: you can now submit games created with XNA GS 3.1, but you will see them on the 360's marketplace (after passing peer review) from August 11, 2009 and on,
  • New Price Structure: 80, 240 and 400 points! Read carefully how this new structure will affect games already available in the marketplace, and
  • XBox Live Indie Games: yes, finally! The new name for our videogames is starting to show up almost everywhere. The name change will be completed later this summer.

Nice one, guys!
~Pete

> Link to Spanish version.

Tuesday, July 21, 2009

Friday, July 17, 2009

XBOX LIVE DASHBOARD UPDATE PREVIEW

Many websites are reporting details about the upcoming “Autumn Update” for the XBox 360’s Dashboard.

There are really great features being added in this one like, among others:

For a full list of the new features, you can read this article.

Cannot wait!
~Pete

> Link to Spanish version.

Sunday, July 05, 2009

“XNAVATARS” - PART 2 – NO SHADOWS?

As promised, I’m hereby posting the second part of the series about using Avatars with XNA GS on the XBox 360.

If you remember, on my first article I showed how to draw an animated avatar on screen taking into account transitions between two animations.

In this part, I will talk about one factor that will help you improve a little bit the eye-candy in your game when using avatars: shadows.

As you may know, the Avatar’s rendering system does not allow us to use a custom shader effect to render an avatar on screen; instead, we must only use the built-in system to accomplish that task.

On one side, this simplify things but on the other, it limits our possibilities a little bit.

Casting shadows is an example of this limitation. As I will show you in a minute or two, a “cheap” workaround can can used, for simple games.

The technique I’ll use is known as “Flat Shadows” (the XNA Framework includes all we need for it). It is a rather basic substitute for “real” shadows, but it will do the trick just fine for projects that don’t require “picky” shadow effects.

We will be using the project I had included last time as a starting point and mainly focus on the code to add and or modify.

1. Fields to add:

private Matrix[] transitionTransforms, shadowTransforms;
...
private Plane plane;
private float lightRotation;
private Model floor;

What’s new? The ‘shadow transforms’ array will store the matrices we need to flatten the model based on a reference plane, which we also define.

2. The constructor:

...
// Create the array of matrices that will hold bone transforms for shadows.
this.shadowTransforms = new Matrix[ 71 ];
...

Nothing fancy here. Just create the array that will hold the collection of matrices to flatten the model.

3. Initializing the game:

/// <summary>
/// Allows the game to perform any initialization it needs to before starting to run.
/// This is where it can query for any required services and load any non-graphic
/// related content.  Calling base.Initialize will enumerate through any components
/// and initialize them as well.
/// </summary>
protected override void Initialize()
{
    this.plane = new Plane( Vector3.Up, 0 );
 
    // As usual, initialize all compoenents.
    base.Initialize();
}

We just create the reference plane with a normal facing up and without moving along that normal (so it’s a XZ plane where the Y coordinate is zero, initially).

4. Loading content:

...
// Set the "World" value wit a rotarion of 180ยบ.
this.avatarRenderer.World = Matrix.CreateTranslation(
    Vector3.Right * -1 + Vector3.Up * 0 + Vector3.Forward * -1 ) *
    Matrix.CreateRotationY( MathHelper.Pi );
...

We just modify the line that places the avatar in the world.

5. Updating the game:

We will only add this line:

...
// Update the value used to rotate the light.
this.lightRotation += .5f * (float)gameTime.ElapsedGameTime.TotalSeconds;
...

So the light will rotate to show the effect.

6. Drawing the avatar:

/// <summary>
/// This is called when the game should draw itself.
/// </summary>
/// <param name="gameTime">Provides a snapshot of timing values.</param>
protected override void Draw( GameTime gameTime )
{
    // As usual, clear the backbuffer (or the current render target).
    GraphicsDevice.Clear( Color.CornflowerBlue );
 
    // Create the array of bone transforms for the floor and populate it.
    ModelBone[] transforms = new ModelBone[ this.floor.Bones.Count ];
    this.floor.Bones.CopyTo( transforms, 0 );
 
    // For each mesh in the floor model.
    foreach(var mesh in this.floor.Meshes)
    {
        // Get the basic effect.
        foreach ( BasicEffect effect in mesh.Effects )
        {
            // Set values and commit changes.
            effect.DiffuseColor = Color.LightSteelBlue.ToVector3();
            effect.View = this.avatarRenderer.View;
            effect.Projection = this.avatarRenderer.Projection;
            effect.World = transforms[ mesh.ParentBone.Index ].Transform;
            effect.CommitChanges();
        }
 
        // Finally, draw the mesh.
        mesh.Draw();
    }
 
    // Can we draw the avatar?
    if ( avatarRenderer != null && currentAnimation != null )
    {
        // If we can, is the animation in transition?
        if ( this.isInTransition )
        {
            // If so, draw it with the interpolated transforms.
            this.avatarRenderer.Draw(
                this.transitionTransforms,
                currentAnimation.Expression );
        }
        else
        {
            // If not, draw it with the actual transforms.
            this.avatarRenderer.Draw(
                this.currentAnimation.BoneTransforms,
                currentAnimation.Expression );
        }
 
        // Make the light sources of the avatar dark.
        Vector3 ambientColor = this.avatarRenderer.AmbientLightColor;
        Vector3 lightColor = this.avatarRenderer.LightColor;
        this.avatarRenderer.AmbientLightColor =
            this.avatarRenderer.LightColor =
                -10 * Vector3.One;
 
        // Enable alpha blending.
        GraphicsDevice.RenderState.AlphaBlendEnable = true;
        GraphicsDevice.RenderState.SourceBlend = Blend.SourceAlpha;
        GraphicsDevice.RenderState.DestinationBlend = Blend.InverseSourceAlpha;
 
        // Change the depth bias just a bit to avoid z-fighting.
        float sourceDepthBias = GraphicsDevice.RenderState.DepthBias;
        GraphicsDevice.RenderState.DepthBias = -0.0001f;
 
        // Set the new light direction.
        this.avatarRenderer.LightDirection = Vector3.Normalize(
            Vector3.Right * 7.5f * (float)Math.Cos( lightRotation ) +
            Vector3.Forward * 15.0f * (float)Math.Sin( lightRotation ) +
            Vector3.Up * 10.0f );
 
        // If the avatar is stepping over the floor, then move the plane 
        // according to the "altitude" of the avatar in the world so as
        // to calculate and cast shadows in the correct world position
        // (also, take into account that in case of a "jump" movement, in a 
        // "complete" shadow system you must reposition the shadow along the 
        // floor taking into account the place where the light-ray hits the 
        // floor while it points to the avatar; otherwise, it will stand still 
        // as if the avatar never jumped in the first place).
        this.plane.D = -this.avatarRenderer.World.Translation.Y;
 
        // Calculate and set the world transform that will flatten the 
        // avatar's geometry, taking into account the original rotation,
        // scale and translation factors.
        Matrix world = this.avatarRenderer.World;
        this.avatarRenderer.World *= Matrix.CreateShadow(
               this.avatarRenderer.LightDirection,
               this.plane );
 
        // Is the animation in transition?
        if ( this.isInTransition )
        {
            // If so, draw it with the interpolated transforms.
            this.avatarRenderer.Draw(
                this.transitionTransforms,
                currentAnimation.Expression );
        }
        else
        {
            // If not, draw it with the actual transforms.
            this.avatarRenderer.Draw(
                this.currentAnimation.BoneTransforms,
                currentAnimation.Expression );
        }
 
        // Reset all affected values.
        this.avatarRenderer.World = world;
        this.avatarRenderer.AmbientLightColor = ambientColor;
        this.avatarRenderer.LightColor = lightColor;
        GraphicsDevice.RenderState.DepthBias = sourceDepthBias;
        GraphicsDevice.RenderState.AlphaBlendEnable = false;
    }
 
    // The following is used to show some statistics and other info
    // on screen. It can be omitted (or optimized).
    this.spriteBatch.Begin();
 
    // No need for further explanation.
    this.spriteBatch.DrawString(
        this.font,
        "Press 'A' to force changing animations or 'Back' to exit.",
        new Vector2( 50, 25 ),
        Color.White );
 
    // No need for further explanation.
    this.spriteBatch.DrawString(
        this.font,
        "Press 'B' to change the type of selection : " +
        ( this.moveRandomly ? "RANDOMLY" : "IN ASCENDING ORDER" )
        + ".",
        new Vector2( 50, 55 ),
        Color.White );
 
    // Draw the animation pointer, whether we are processing a transition and
    // the current transition time. Please notice that in this implementation
    // when the current animation is about to end (that is, 1 second or less),
    // the pointer "currentAnimationId" will change even if the animation is still
    // the same, so you will see a different number and name during 1 second or so.
    this.spriteBatch.DrawString(
        this.font,
        this.currentAnimationId + " : " +
            ( (AvatarAnimationPreset)this.currentAnimationId ).ToString() +
            " (" +
            ( !this.isInTransition ? "no transition" : this.transitionProgress.ToString() + " processed" ) +
            ").",
        new Vector2( 50, 85 ),
        Color.White );
 
    // Draw the current position and length of the animation being rendered.
    if ( currentAnimation != null )
    {
        this.spriteBatch.DrawString(
            this.font,
            "Processed " +
            this.currentAnimation.CurrentPosition.ToString() +
                " of " +
                this.currentAnimation.Length.ToString() +
                ".",
            new Vector2( 50, 115 ),
            Color.White );
    }
 
    // Flush the batch.
    this.spriteBatch.End();
 
    // As usual, call the base method.
    base.Draw( gameTime );
}

Here’s where most changes occur; the game ...:

  1. ... draws the avatar as on my previous example,
  2. ... changes the values of the lights that affect the avatar,
  3. ... adjusts the depth-bias to avoid any eventual z-fight,
  4. ... rotates the light and adjusts the plane altitude before flattening the model,
  5. ... updates the position of the flattened model using the static method of the matrix struct, which is named in the code as “CreateShadow”,
  6. ... draws the fake shadow, and finally ...
  7. ... restores the values of the lights and position of the avatar’s model meshes.

7: Changes to transitions code: none.

If everything goes fine you will see something like this:

Things to notice, though:

  1. Shadows will be drawn even when there’s no elements to cast shadows on (see how part of the shadow is rendered beyond the “floor” for a short period of time),
  2. You will have to modify the location of the shadow when the position of the avatar changes its height (i.e.: if jumping),
  3. The model’s meshes are flattened onto a reference plane, so it will only work for objects on that specific plane (like, in my example, a floor), and
  4. Thus, there’s no self-shadowing.

A more precise approach would be extending this example by trying to use the stencil buffer and depth data, as explained at the end of this thread.

Well, this is it for today. You can find the source code for this example here.

Cheers!
~Pete

> Link to Spanish version.

Wednesday, July 01, 2009

"XNAVATARS" - PART 1

At the very end of my article "Avatars 101" I said I would post an example with a slightly different approach in order to render avatar's transitions.

Well, I have decided to extend the example and split the end result in a series of -most likely- 3 or 4 articles.

For starters, on this article we will concentrate on the transitions' code I promised.

To simplify the explanation a little bit, the whole code to render the avatar is implemented in the Game class (but this is going to change in the third part of the series).

Ok, let's begin ...

1. Create a XNA GS game project on Visual Studio and named it, say, "AvatarGame".

2. Include the following fields (in addition to the ones that are automatically created for you by XNA GS):

// We will use a font to draw statistics.
private SpriteFont font;
 
// These are needed to handle our avatar.
private AvatarDescription avatarDesc;
private AvatarRenderer avatarRenderer;
private AvatarAnimation currentAnimation, targetAnimation;
 
// Holds an array of all animations available for our avatar.
private AvatarAnimation[] animations;
 
// These are needed to handle transitions between animations.
private bool isInTransition, moveToNextAnimation, moveRandomly;
private float transitionProgress, transitionStep;
private Matrix[] transitionTransforms;
private int currentAnimationId;
private Random randomizer;
 
// These will help to detected pressed buttons.
private GamePadState currentGamePadState, lastGamePadState;

The code is self-explainable. Basically, we are adding the basic fields we need to render avatar plus the helper ones to handle transitions.

3. The constructor:

/// <summary>
/// Initializes a new instance of the <see cref="AvatarGame"/> class.
/// </summary>
public AvatarGame()
{
    // These are implemented for you.
    graphics = new GraphicsDeviceManager( this );
    Content.RootDirectory = "Content";
 
    // Create and add the GamerServices component.
    Components.Add( new GamerServicesComponent( this ) );
 
    // Create the array that will hold the collection of animations.
    this.animations = new AvatarAnimation[ 30 ];
 
    // Create the array of matrices that will hold bone transforms for transitions.
    this.transitionTransforms = new Matrix[ 71 ];
 
    // Create the random-number generator.
    this.randomizer = new Random( DateTime.Now.Millisecond );
}

As usual, you must create the managers/services you will use to render the avatars.

But why do we also need two arrays and a random number generator? The latter, in case we want to change animations in no particular order.

And the arrays? Read on …

4. Loading content:

/// <summary>
/// LoadContent will be called once per game and is the place to load
/// all of your content.
/// </summary>
protected override void LoadContent()
{
    // Create a new SpriteBatch, which can be used to draw textures.
    spriteBatch = new SpriteBatch( GraphicsDevice );
 
    // Load a spritefont.
    this.font = this.Content.Load<SpriteFont>( "MainFont" );
 
    // For each position in the array.
    for ( int i = 0; i < this.animations.Length; i++ )
    {
        // Create and store the corresponding animation.
        this.animations[ i ] = new AvatarAnimation( (AvatarAnimationPreset)i );
    }
 
    // Create a random description (instead, you can try to get the 
    // description of a signedIn gamer).
    this.avatarDesc = AvatarDescription.CreateRandom();
 
    // Create the renderer with a standard loading effect.
    this.avatarRenderer = new AvatarRenderer( avatarDesc, true );
 
    // Just for fun, set the current animation, randomly.
    this.currentAnimationId = this.randomizer.Next( this.animations.Length );
    this.currentAnimation = this.animations[ this.currentAnimationId ];
 
    // Set the "World" value.
    this.avatarRenderer.World =
        Matrix.CreateRotationY( MathHelper.ToRadians( 180.0f ) );
 
    // Set the "Projection" value.
    this.avatarRenderer.Projection =
        Matrix.CreatePerspectiveFieldOfView(
            MathHelper.ToRadians( 45.0f ),
            this.GraphicsDevice.Viewport.AspectRatio,
            .01f,
            200.0f );
 
    // Set the "View" value.
    this.avatarRenderer.View =
        Matrix.CreateLookAt(
            new Vector3( 0, 1, 3 ),
            new Vector3( 0, 1, 0 ),
            Vector3.Up );
}

As you can see, in this method we populate the array of animations with each built-in available animation for avatars. The reason? We use this array as a cache so as to speed up the look-up process when phasing out from one animation to the next one.

Then, we set-up the initial transition and set the view and projection fields (note: both matrices are always “fixed“ in this example).

There is no significant code for the Initialize and Unload methods, and thus we move to the Update method.

5. Updating the game:

/// <summary>
/// Allows the game to run logic such as updating the world,
/// checking for collisions, gathering input, and playing audio.
/// </summary>
/// <param name="gameTime">Provides a snapshot of timing values.</param>
protected override void Update( GameTime gameTime )
{
    // Update the gamepad state for player one.
    this.lastGamePadState = this.currentGamePadState;
    this.currentGamePadState = GamePad.GetState( PlayerIndex.One );
 
    // Allow the game to exit.
    if ( this.currentGamePadState.Buttons.Back == ButtonState.Pressed )
    {
        this.Exit();
    }
 
    // Force moving to the next animation without waiting for the 
    // current animation to end.
    if ( this.currentGamePadState.Buttons.A == ButtonState.Pressed &&
        this.lastGamePadState.Buttons.A == ButtonState.Released &&
        !this.isInTransition )
    {
        this.moveToNextAnimation = true;
    }
 
    // Change the type of selection: ascending order or randomly.
    if ( this.currentGamePadState.Buttons.B == ButtonState.Pressed &&
        this.lastGamePadState.Buttons.B == ButtonState.Released )
    {
        this.moveRandomly = !this.moveRandomly;
    }
 
    // Is there any animation to update?
    if ( currentAnimation != null )
    {
        // Is the current animation just about to finish or forced to end?
        if ( !this.isInTransition &&
            this.targetAnimation == null &&
            ( this.currentAnimation.RemainingTime().TotalSeconds <= 1 ||
                this.moveToNextAnimation ) )
        {
            // Are we moving randomly?
            if ( this.moveRandomly )
            {
                // If so, select a new animation at random.
                this.currentAnimationId = this.randomizer.Next( this.animations.Length );
            }
            else
            {
                // If not, point to the next animation.
                this.currentAnimationId++;
 
                // Keep the id pointing to a valid position in the array.
                this.currentAnimationId %= this.animations.Length;
            }
 
            // Set the corresponding target animation.
            this.targetAnimation = this.animations[ this.currentAnimationId ];
        }
 
        // Has the animation reached its last frame? Or is it forced 
        // to change by the user?
        if ( this.currentAnimation.LastFrameReached() || this.moveToNextAnimation )
        {
            // If so, start by resetting this marker flag to false.
            this.moveToNextAnimation = false;
 
            // State that we will process a transition.
            this.isInTransition = true;
 
            // Make a copy of the readonly transforms to the transition array.
            this.currentAnimation.BoneTransforms.CopyTo( this.transitionTransforms, 0 );
 
            // Reset the current animation.
            this.currentAnimation.CurrentPosition = TimeSpan.Zero;
 
            // Set the target one as the current one.
            this.currentAnimation = this.targetAnimation;
            this.targetAnimation = null;
 
            // You can tweak this value to meet your game's need,
            // considering the lenght of your animations (it could vary).
            this.transitionStep = .5f;
        }
 
        // Update the current animation (in this example, there is no looping).
        this.currentAnimation.Update( gameTime.ElapsedGameTime, false );
 
        // Are we processing a transition?
        if ( this.isInTransition )
        {
            // If so, update the progress value.
            this.transitionProgress += this.transitionStep * (float)gameTime.ElapsedGameTime.TotalSeconds;
 
            // Is the progress below 100%?
            if ( transitionProgress < 1f )
            {
                // Calculate the proper bone transforms.
                this.CalculateTransition();
            }
            else
            {
                // When the progress reaches 100%, reset everything.
                this.isInTransition = false;
                this.transitionProgress = 0;
            }
        }
    }
 
    // As usual, call the base method.
    base.Update( gameTime );
}

At runtime, if you press the ‘A’ button and no transition is being executed, then you force “the avatar” to start a transition to the next animation.

By pressing the ‘B’ button, you change the way the next animation is selected: in ascending order or randomly.

Notice that when the current animation is about to end, the game selects the next animation, in the current order method selected by the user.

When either the last frame of the animation being played is reached (no looping) or the user forces the transition, we then copy the bone transforms for the position in that animation, reset the position to zero and change the animation to the “target” one.

You may wondering what’s the purpose of the field “transitionStep”. This factor states the time we will spend to move from “the last” position of the ending animation to the “current” position of the starting one.

Why to the “current”? The behavior I decided to choose in order to create a believable look’n’feel for the transition was to avoid going from “last to first” and instead from “last to current” (notice that the starting animation will play from the moment we execute the transition out, and so the current position will change).

Of course that you can change this behavior if you prefer going “from last to first” position behavior before playing the entering animation.

Finally, we call the “CalculateTransition” method which I will explain after the Draw one.

6. Drawing the avatar:

/// <summary>
/// This is called when the game should draw itself.
/// </summary>
/// <param name="gameTime">Provides a snapshot of timing values.</param>
protected override void Draw( GameTime gameTime )
{
    // As usual, clear the backbuffer (or the current render target).
    GraphicsDevice.Clear( Color.CornflowerBlue );
 
    // Can we draw the avatar?
    if ( avatarRenderer != null && currentAnimation != null )
    {
        // If we can, is the animation in transition?
        if ( this.isInTransition )
        {
            // If so, draw it with the interpolated transforms.
            avatarRenderer.Draw(
                this.transitionTransforms,
                currentAnimation.Expression );
        }
        else
        {
            // If not, draw it with the actual transforms.
            avatarRenderer.Draw(
                this.currentAnimation.BoneTransforms,
                currentAnimation.Expression );
        }
    }
 
    // The following is used to show some statistics and other info
    // on screen. It can be omitted (or optimized).
    this.spriteBatch.Begin();
 
    // No need for further explanation.
    this.spriteBatch.DrawString(
        this.font,
        "Press 'A' to force changing animations or 'Back' to exit.",
        new Vector2( 50, 25 ),
        Color.White );
 
    // No need for further explanation.
    this.spriteBatch.DrawString(
        this.font,
        "Press 'B' to change the type of selection : " +
        ( this.moveRandomly ? "RANDOMLY" : "IN ASCENDING ORDER" )
        + ".",
        new Vector2( 50, 55 ),
        Color.White );
 
    // Draw the animation pointer, whether we are processing a transition and
    // the current transition time. Please notice that in this implementation
    // when the current animation is about to end (that is, 1 second or less),
    // the pointer "currentAnimationId" will change even if the animation is still
    // the same, so you will see a different number and name during 1 second or so.
    this.spriteBatch.DrawString(
        this.font,
        this.currentAnimationId + " : " +
            ( (AvatarAnimationPreset)this.currentAnimationId ).ToString() +
            " (" +
            ( !this.isInTransition ? "no transition" : this.transitionProgress.ToString() + " processed" ) +
            ").",
        new Vector2( 50, 85 ),
        Color.White );
 
    // Draw the current position and length of the animation being rendered.
    if ( currentAnimation != null )
    {
        this.spriteBatch.DrawString(
            this.font,
            "Processed " +
            this.currentAnimation.CurrentPosition.ToString() +
                " of " +
                this.currentAnimation.Length.ToString() +
                ".",
            new Vector2( 50, 115 ),
            Color.White );
    }
 
    // Flush the batch.
    this.spriteBatch.End();
 
    // As usual, call the base method.
    base.Draw( gameTime );
}

The only important code to notice here is the one in charge of rendering either the animation as is, or the calculated transition.

Since the Draw method of the AvatarAnimation expects an instance of type “IList”, we can pass an array of matrices directly without creating a ReadOnlyCollection.

7. Finally, the magic:

/// <summary>
/// Calculates the proper bone transoforms for the current transition.
/// </summary>
private unsafe void CalculateTransition()
{
    // If so, declare all needed helper primitives.
    // For debugging purposes you can use local fields marked as "final",
    // which in this example are commented out.
    Matrix currentMatrix, targetMatrix;
    Vector3 currentScale, targetScale; //, finalScale;
    Quaternion currentRotation, targetRotation; //, finalRotation;
    Vector3 currentTranslation, targetTranslation; //, finalTranslation;
 
    // For each transform's matrix.
    for ( int i = 0; i < this.transitionTransforms.Length; i++ )
    {
        // Since we are pointing to a managed struct we must use the 
        // reserved word "fixed" with an "unsafe" method declaration,
        // if we want to avoid traversing the array several times.
        fixed ( Matrix* matrixPointer = &this.transitionTransforms[ i ] )
        {
            // Get both, the current and target matrices.
            // Declaring these two local fields could be omitted 
            // and be used directly in the calcs below, but 
            // they are really useful when debugging.
            currentMatrix = *matrixPointer;
            targetMatrix = this.currentAnimation.BoneTransforms[ i ];
 
            // Get the components for the current matrix.
            currentMatrix.Decompose(
                out currentScale,
                out currentRotation,
                out currentTranslation );
 
            // Get the components for the target matrix.
            targetMatrix.Decompose(
                out targetScale,
                out targetRotation,
                out targetTranslation );
 
            // There's no need to calculate the blended scale factor, since we
            // are mantaining the current one, but I include it in the example
            // for learning purposes in case you need it.
            /*Vector3.Lerp(
                ref currentScale,
                ref targetScale,
                this.transitionProgress,
                out currentScale );*/
 
            // Interpolate a rotation value from the current an target ones,
            // taking into account the progress of the transition.
            Quaternion.Slerp(
                ref currentRotation,
                ref targetRotation,
                this.transitionProgress,
                out currentRotation );
 
            // Interpolate a translation value from the current an target ones,
            // taking into account the progress of the transition.
            Vector3.Lerp(
                ref currentTranslation,
                ref targetTranslation,
                this.transitionProgress,
                out currentTranslation );
 
            // Calculate the corresponding matrix with the final components.
            // Again, in this example, the creation of the scale matrix can be omitted
            // from the formula below (you may only use the rotation and tranlsation
            // factors obtaining the same result and save some processing power per loop).
            //this.transitionTransforms[ i ] =
            *matrixPointer =
                //Matrix.CreateScale( currentScale ) *
                Matrix.CreateFromQuaternion( currentRotation ) *
                Matrix.CreateTranslation( currentTranslation );
        }
    }
}

Every time we need to calculate and update the interpolated transition transforms, we’ll have to decompose the matrices of both, the last position in the ending animation and the updated position in the entering animation.

If the last position of the old animation is “fixed”, why do we need to decompose its matrices every time we call this method? Good question. Short answer: we don’t. We could calculate the old transforms once and store them in a private field for the game, but I include them here in case you want to change the default behavior (for instance, if you decide to keep the ending animation playing as well as the entering one).

What’s with the words “unsafe” and “fixed”? We must declare those two in order to use pointers to value types (plus mark the project to allow unsafe code). Fixing the field will prevent the GC from collecting it until we do not need it anymore, plus, in this case, it will allow us to directly use and set the value store in the stack without traversing the array of transition transforms twice per “for” loop to first get and then update the value type.

Phew! That’s it for now; when you compile and run the program you will see a random created avatar do some nice transitions either when the last animation ends or when you press the ‘A’ button.

You can download an example project for this article from here (you will find an extra class with two extension methods for the AvatarAnimation, named “LastFrameReached” & “RemainingTime”).

You can tweak the behavior and optimize the code a little more (say the rendering, create a specific class for the avatar and so on), or wait for the upcoming parts on the series …

Enjoy!
~Pete

> Link to Spanish version.