views:

334

answers:

2

I am constantly drawing frames, and I need the form to not flicker. How do I accomplish this?

namespace GraphicsEngine
{
public partial class Form1 : Form
{

    Image[] dude = new Image[3];

    static int renderpoint = 0;


    int lastimage = 0;

    public Form1()
    {

        dude[1] = new Bitmap(@"C:\Documents and Settings\Boys\Desktop\Gang Garrison 2\Source\snipe1.bmp");
        dude[0] = new Bitmap(@"C:\Documents and Settings\Boys\Desktop\Gang Garrison 2\Source\snipe0.bmp");



        InitializeComponent();
    }

    private void Form1_Shown(object sender, EventArgs e)
    {
        MainLoop();
    }

    private void MainLoop()
    {
        double FPS = 10;

        long ticks1 = 0;
        long ticks2 = 0;
        double interval = (double)Stopwatch.Frequency / FPS;


        while (true)
        {

            ticks2 = Stopwatch.GetTimestamp();
            if (ticks2 >= ticks1 + interval)
            {
                ticks1 = Stopwatch.GetTimestamp();

                MoveGraphics();
                this.Refresh(); 
            }

            Thread.Sleep(1); 

        }
    }


    private void Form1_Paint(object sender, PaintEventArgs e)
    {
        Graphics g = e.Graphics;
        Rectangle rect = new Rectangle(renderpoint, 0, 100, 100);
        Color lowcolor = Color.FromArgb(0, 128, 64);
        Color highcolor = Color.FromArgb(0, 128, 64);

        ImageAttributes imageAttr = new ImageAttributes();
        imageAttr.SetColorKey(lowcolor, highcolor);

        if (lastimage == 1)
        {
            lastimage = 0;
            g.DrawImage(dude[1], rect, 0, 0, 100, 100, GraphicsUnit.Pixel, imageAttr);
        }

        else
        {
            lastimage = 1;
            g.DrawImage(dude[0], rect, 0, 0, 100, 100, GraphicsUnit.Pixel, imageAttr);
        }  
    }

    void MoveGraphics()
    {
        if (renderpoint > 950)
        {
            renderpoint = 0;
        }

        else
        {
            renderpoint += 10;
        }
    }
}
}

There's the current code. Suggestions?

+6  A: 
  1. Do your rendering in the Paint event handler
  2. Disable automatic erasing of the background.
  3. Enable double buffering either via the Styles or manually.
  4. When you want to repaint, call Invalidate

If you're trying to pull of smooth animation, then may I recommend jumping ship to WPF, OpenGL, or XNA. GDI+ was not designed for animation (the Windows message loop is not a real-time system, so you will always have jittering).

Frank Krueger
Also, use a timer instead of `Thread.Sleep`.
SLaks
#1 ... I think you meant to say do your rendering to an offscreen buffer when needed, and simply BitBlt to your form in the Paint event handler.
overslacked
@overslacked Yes, but it's not actually that simple. Ideally, you would only draw to the back buffer when not using Terminal Services. When using TS, you should draw directly to the context. To simplify this, Microsoft added some extensions to GDI+ to do OS/Framework based double buffering.
Frank Krueger
@ SLaks: would it not require more resources to create a timer than to suspend the threads execution?
Bloodyaugust
@ Frank: Invalidate causes it to no longer work.Also, I believe I am using the paint event handler to do my rendering... Am I not?
Bloodyaugust
@Bloodyaugust, In the code you posted, you never subscribe to the Paint event.
Frank Krueger
@ Frank: So I'm just seeing Form1_Paint? Or is there some jargon I'm missing...
Bloodyaugust
could you post some code along with your answer to illustrate how to perform your 4 points? (especially 2)
m_oLogin
+1  A: 

Paste this into your Form1 constructor:

this.DoubleBuffered = true;
Hans Passant
This seems to work fine... But holding out the jury until I can test it with more and simultaneous graphics.
Bloodyaugust