Jamisco
Jamisco

Reputation: 1862

How to make an animation look consistent and smooth

`So I have a total of 6 images that when animated, creates the illusion of a person walking. The problem is its not smooth, refresh(), invalidate(),update() have failed me. How do I go about this.

namespace Runner
{
    public partial class Form1 : Form 
    {
        Keys moveRight;
        Keys moveLeft;
    public static bool isMovingR = false;
    public static bool isMovingL = false;

    Bitmap stnd = new Bitmap(Properties.Resources.Standing);
    static Bitmap wlk_1_RL = new Bitmap(Properties.Resources.Walk_1_RL);
    static Bitmap wlk_2_RL = new Bitmap(Properties.Resources.Walk_2_RL);
    static Bitmap wlk_3_RL = new Bitmap(Properties.Resources.Walk_3_RL);
    static Bitmap wlk_4_LL = new Bitmap(Properties.Resources.Walk_4_LL);
    static Bitmap wlk_5_LL = new Bitmap(Properties.Resources.Walk_5__LL);
    static Bitmap wlk_6_LL = new Bitmap(Properties.Resources.Walk_6_LL);

    Graphics gfx;
    Animation animate = new Animation(new Bitmap[] { wlk_1_RL, wlk_2_RL, wlk_3_RL,
        wlk_4_LL, wlk_5_LL, wlk_6_LL });


    Timer timer = new Timer();

    int imageX = 5;
    int imageY = 234;

    public Form1()
    {
        InitializeComponent();
    }

    private void Form1_KeyDown(object sender, KeyEventArgs e)
    {
        moveRight = Keys.D;
        moveLeft = Keys.A;

        if (Keys.D == moveRight)
        {
            isMovingR = true;
            timer.Enabled = true;
            timer.Interval = 50;
            timer.Tick += timer1_Tick;                
            //imageX += 5;
            Refresh();
        } else if (Keys.A == moveLeft)
        {
            isMovingL = true;
            imageX -= 5;
            Refresh();
        }

    }

    private void timer1_Tick(object sender, EventArgs e)
    {
        gfx = this.CreateGraphics();
        gfx.DrawImage(animate.Frame2Draw(), imageX, imageY);
        //Refresh(); Invalidate(); Update();
    }
} 

}

Now, the problem is being able to make the animation consistent and smooth

UPDATE...animation class

 public class Animation
{
    int slctdImg = 0;
    public static Bitmap[] images;
    Bitmap frame2Draw;

    public Animation(Bitmap[] frames)
    {
        foreach (Bitmap btm in frames)
        {
            btm.MakeTransparent();
        }
        images = frames;
    }

    public Bitmap Frame2Draw()
    {

        if (slctdImg < images.Length)
        {
            frame2Draw = images[slctdImg];
            slctdImg++;
        }
        if (slctdImg >= images.Length)
        {
            slctdImg = 0;
            frame2Draw = images[slctdImg];
        }
        return frame2Draw;
    }
}

Upvotes: 2

Views: 295

Answers (1)

TaW
TaW

Reputation: 54433

Many issues:

  • I wonder why you would call MakeTransparent on each Tick?? I doubt it does what you expect.. It is changing pixels and rather expensive; you ought to cache the images instead.

  • Nor why you create an array of bitmap on each Tick??? And since it is always created the same way it always displays only the 1st image.. This should answer your question.

Further issues:

  • Using this.CreateGraphics(); will fail to create a persistent result although that may not be your aim as you try to animate.

  • Remember that a Timer.Interval can't run faster than 15-30 ms; also that winforms is notoriously bad at animation.

  • Remember that c# is zero-based, so this slctdImg > images.Length should probably be slctdImg >= images.Length

Here is what you should do instead:

  • Move the instantiation either to the form load or maybe to a key event.

  • Move the drawing to the Paint event of the form.

  • In the Tick count up frames and/or position and trigger the Paint by calling Invalidate on the form!

Update:

One more issue is the way you hook up the Tick event each time the right key is pressed. Hooking up an event multiple times will result in it running multiple times; this will create to gaps/jumps in your animation..

Either add an unhook each time before hooking up (it will fail quietly the 1st time)

timer.Tick -= timer1_Tick;
timer.Tick += timer1_Tick; 

or (better) hook it up only once in the original set up!

Upvotes: 2

Related Questions