Search code examples
c#winforms2d-games

Prevent Flickering for moving object


I'm trying to make a breakout game for an assignment in windows form and I've made games before, but I've just not used winforms before. I've found things that are supposed to help like OnPaint() (which you're supposed to override), DoubleBuffered andInvalidate`. But I'm just struggling applying it to my code

Here's what I have:

 int xSpeed, ySpeed;

    Graphics display;
    Brush brush;

    Rectangle ballRect;

    public Form1()
    {
        InitializeComponent();



        timer1.Enabled = true;
        timer1.Interval = 1;

        xSpeed = 5;
        ySpeed = 5;
        ballRect = new Rectangle(10, 10, 20, 20);

        display = this.CreateGraphics();

        brush = new SolidBrush(Color.Red);


    }

    private void timer1_Tick(object sender, EventArgs e)
    {
        DoubleBuffered = true;

        ballRect.X += xSpeed;
        ballRect.Y += ySpeed;

        if (ballRect.X >= 469)
            xSpeed = -xSpeed;

        if (ballRect.Y >= 457)
            ySpeed = -ySpeed;

        if (ballRect.X <= 0)
            xSpeed = -xSpeed;

        if (ballRect.Y <= 0)
            ySpeed = -ySpeed;

        display.Clear(Color.White);
        display.FillEllipse(brush, ballRect);

    }

I'm drawing the ball in Update method (timer1_tick), but I feel like I shouldn't be. Thanks :)


Solution

  • You can create your custom Control or Form and:

    • In constructor Set styles for flicker free painting OptimizedDoubleBuffer, UserPaint, AllPaintingInWmPaint
    • In constructor Set style for redraw if the size changes ResizeRedraw
    • In Tick event just update position of ball and then Invalidate the control
    • override OnPaint method of your control and put the paint logic there
    • Also you should use properties for speed or ball size, to be able to invalidate the control if those values changed. (I didn't implement properties in below code.) Also you can increase the interval a little.

    For example:

    public partial class CustomControl1 : Control
    {
        public CustomControl1()
        {
            InitializeComponent();
    
            this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
            this.SetStyle(ControlStyles.UserPaint, true);
            this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
            this.SetStyle(ControlStyles.ResizeRedraw, true);
    
            timer1.Enabled = true;
            timer1.Interval = 1;
    
            xSpeed = 5;
            ySpeed = 5;
    
            ballRect = new Rectangle(10, 10, 20, 20);
            brush = new SolidBrush(Color.Red);
        }
    
        protected override void OnPaint(PaintEventArgs pe)
        {
            pe.Graphics.FillEllipse(brush, ballRect);
        }
    
        int xSpeed, ySpeed;
        Brush brush;
        Rectangle ballRect;
        private void timer1_Tick(object sender, EventArgs e)
        {
            ballRect.X += xSpeed;
            ballRect.Y += ySpeed;
    
            if (ballRect.X + ballRect.Width >= this.Width)
                xSpeed = -xSpeed;
    
            if (ballRect.Y + ballRect.Height >= this.Height)
                ySpeed = -ySpeed;
    
            if (ballRect.X <= 0)
                xSpeed = -xSpeed;
    
            if (ballRect.Y <= 0)
                ySpeed = -ySpeed;
    
            this.Invalidate();
        }
    
    }