Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I'm trying to convert a AS3 game to C# / XNA and I'm looking for a way to animate a sprite.

More precisely, I want the sprite to rotate and scale a bit, then return to its starting position.

In AS3 I just use a tweening library and add a touch listener to the sprite, but I haven't been able to find something like this for XNA. How would you do something like that in C#?
Thanks in advance!

share|improve this question

2 Answers 2

I'm under the impression AS3 is a retained-mode API. You create a collection of objects - it draws and manages them for you. XNA, on the other hand, is an immediate-mode API. You are responsible for drawing things each frame, reading inputs each frame, keeping track of time, and so on.

Here is a complete game class to demonstrate what you want. Just paste it over the one in the default template, and add your own texture called "myTexture" to the content project.

public class Game1 : Microsoft.Xna.Framework.Game
{
    GraphicsDeviceManager graphics;
    SpriteBatch spriteBatch;

    public Game1()
    {
        graphics = new GraphicsDeviceManager(this);
        Content.RootDirectory = "Content";
        IsMouseVisible = true;
    }

    Texture2D texture;

    protected override void LoadContent()
    {
        spriteBatch = new SpriteBatch(GraphicsDevice);
        texture = Content.Load<Texture2D>("myTexture");
    }

    bool animating;
    const float totalTime = 1;
    float time;

    MouseState lastMouseState;

    protected override void Update(GameTime gameTime)
    {
        MouseState mouseState = Mouse.GetState();

        if(mouseState.LeftButton == ButtonState.Pressed && lastMouseState.LeftButton == ButtonState.Released)
        {
            time = 0;
            animating = true;
        }
        else if(animating)
        {
            time += (float)gameTime.ElapsedGameTime.TotalSeconds;
            if(time > totalTime)
            {
                time = 0;
                animating = false;
            }
        }

        lastMouseState = mouseState;
    }

    protected override void Draw(GameTime gameTime)
    {
        GraphicsDevice.Clear(Color.CornflowerBlue);
        spriteBatch.Begin();

        float alpha = time / totalTime; // from 0 to 1
        Vector2 position = new Vector2(GraphicsDevice.Viewport.Width / 2f, GraphicsDevice.Viewport.Height / 2f);
        Vector2 origin = new Vector2(texture.Width / 2f, texture.Height / 2f);
        float rotation = MathHelper.TwoPi* alpha;
        float scale = alpha < 0.5 ? MathHelper.SmoothStep(1, 2, alpha * 2f) : MathHelper.SmoothStep(2, 1, (alpha-0.5f) * 2f);

        spriteBatch.Draw(texture, position, null, Color.White, rotation, origin, scale, SpriteEffects.None, 0);

        spriteBatch.End();
    }
}

(I've used Mouse here, and tested on Windows, but the code should work on the phone too (where Mouse is emulated). It should be easy enough to convert it to use actual touch inputs.)

On the one hand - this is an awful lot more code than you're probably used to. On the other hand - you get a lot more control and performance. Also - if you structure your code nicely and reuse things (admittedly this may take some practice) you can significantly reduce the amount of code you need to write in real-world situations, at least compared to the above.

And you could even go so far as to implement your own retained-mode style classes (eg: your own Sprite class). You can do this on top of an immediate-mode API. Whereas it's practically impossible to do the inverse: an immediate-mode style code on a retained-mode API.

(Personally I recommend just embracing the immediate-mode API. Let your own game model retain things - eg: a Player object that can draw itself, rather than a Player object that owns a Sprite object.)

share|improve this answer

What you're trying to do is not a part of the Microsoft XNA Framework so you have to create this behavior yourself. Here's what I would recommend.

1) First create a Sprite class which exposes the properties you need to animate, or simply expose these properties on your game object model classes, such as the Player. This is related to the difference between immediate-mode and retained-mode that Andrew talked about, so just pick the way you'd like to work.

public class Sprite {
    public Vector2 Position { get; set; }
    public float Rotation { get; set; }
    public float Scale { get; set; }
    public Texture2D Texture { get; set; }
    public void Draw(SpriteBatch spriteBatch);
}

2) Instead of managing the animations directly inside your game object model, create an external class that encapsulates and manages all types of animations. You could...

  • Try an existing tweening library such as XnaTweener Library and see if it works for you (never used it).

  • I like to treat this concept at an even higher level. What I usually do is create a class that can manage any sequence of actions, instead of just tweening properties. Then I create specific types of actions for tweening properties if I need it. Check the following answer for such an implementation "How to chain actions/animations together and delay their execution?".

3) Finally, queue the animations on your manager! For example, with the ProcessQueue class I wrote about in the other answer, this would be done with something like:

processQueue.Add(new Rotate(23f));
processQueue.Add(new Scale(1.5f));
processQueue.Add(new Move(new Vector2(400, 200));
share|improve this answer
    
Might as well share two useful types of processes: Move and FloatInterpolation –  David Gouveia Aug 31 '12 at 11:17

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.