GDI+ : DoubleBuffer makes my animation slower...

H

hstagni

Im starting to code C# and I tried to make a simple animation of a
ball moving in the screen(i will transform it later in a pong game).
My program worked fine, but the ball was blinking while moving. So, I
tried to put this lines of code into form constructor, cause I saw on
a forum that this would prevent the background to be redrawed every
time:
/**************TESTING...************************/
this.SetStyle(ControlStyles.UserPaint, true);
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
this.SetStyle(ControlStyles.DoubleBuffer, true);
/********************************************************/


My ball stopped blinking, but the animation is slower now. WHY???????
I heard of overriding OnPaintBackground method, but it just destroys
my hole program. [Can you also give me some tips based on my code?]
HERE IS THE CODE:

/******************************************************************/
using System;
using System.Windows.Forms;
using System.Drawing;

class Ball
{


public int xPos, yPos;
int xVet, yVet;
public Color currColor;
public Ball(int xIniPos, int yIniPos)
{
this.xPos = xIniPos;
this.yPos = xIniPos;
this.xVet = 1;
this.yVet = 3;

currColor = Color.Red;
}


public void NextPositionAndVector()
{
xPos += xVet;
yPos += yVet;

if (yPos<=0 || yPos>=500){
yVet = -yVet;
}
if (xPos<=0 || xPos>=500)
xVet = -xVet;

}
}




public class MainForm : Form
{
Timer ballTimer = new Timer();
Ball myBall = new Ball(100, 100);

public MainForm(){

this.Bounds = Screen.PrimaryScreen.Bounds;
this.ResumeLayout(true);
this.TopMost = true;
this.FormBorderStyle = FormBorderStyle.None;
Cursor.Hide();
this.BackColor = Color.Black;



ballTimer.Interval = 1;

/**************TESTING...Double buffer********************/
this.SetStyle(ControlStyles.UserPaint, true);
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
this.SetStyle(ControlStyles.DoubleBuffer, true);
/********************************************************/

this.Show();
this.KeyDown += new KeyEventHandler(MainFormKeyDown);
ballTimer.Tick += new EventHandler(ballTimer_OnTick);
ballTimer.Start();
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
Graphics g = e.Graphics;
g.FillEllipse(new SolidBrush(myBall.currColor), myBall.xPos,
myBall.yPos, 40, 40);

}


// protected override void OnPaintBackground(PaintEventArgs e)
// {
// }


public void ballTimer_OnTick(object Sender, EventArgs e)
{

myBall.NextPositionAndVector();
this.Invalidate();

}

public void MainFormKeyDown(object Sender, KeyEventArgs e)
{
this.Close();

}


}


public class App
{

public static void Main(){
Application.Run(new MainForm());
}

}

/*****************************************************************/
 
B

Ben Voigt [C++ MVP]

public void ballTimer_OnTick(object Sender, EventArgs e)
{

myBall.NextPositionAndVector();
this.Invalidate();

You may get better performance if you only invalidate the changed region...
that is the old and new ball positions.

You might consider doing the double buffering yourself, it certainly isn't
hard. Also, GDI+ is not designed for speed. Use Avalon (WPF, also badly
named .NET 3.0) or DirectX if frame rate is a concern.
 
P

Peter Duniho

Im starting to code C# and I tried to make a simple animation of a
ball moving in the screen(i will transform it later in a pong game).
My program worked fine, but the ball was blinking while moving. So, I
tried to put this lines of code into form constructor, cause I saw on
a forum that this would prevent the background to be redrawed every
time:
/**************TESTING...************************/
this.SetStyle(ControlStyles.UserPaint, true);
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
this.SetStyle(ControlStyles.DoubleBuffer, true);
/********************************************************/


My ball stopped blinking, but the animation is slower now. WHY???????

Because everything has to be drawn at least twice: once to the off-screen
buffer, and then again when that buffer is copied to the screen.

Double-buffering may or may not be faster than not double-buffering. It
really just depends on what you're drawing. The main point is that the
point of double-buffering is to improve the visual appearance of your
drawing; it's not about making things faster, and in many cases drawing
will in fact be slower.

By the way, double-buffering does _not_ prevent the background from being
redrawn every time. It just affects where the background is redrawn
(along with everything else). With DoubleBuffer set to true, the
on-screen representation of the window is never erased; the off-screen
version is, which is then copied to the on-screen version. But the
erasing still happens.

In some cases, you may be able to do a better job that the default
double-buffering implementation is doing. It depends on what exactly
you're drawing. The basic requirement to avoid flickering is to only
every touch any given pixel on the screen once per update. You get
flicker when you draw one thing to somewhere in your window, and then
immediately draw something else over what you just drew. The most common
example of this is erasing the background before drawing the contents, but
any sort of z-ordered content will cause flickering if all of the
composition is done on-screen.

So, if you can ensure that every part of your window that needs to be
drawn can be drawn exactly once, and without having to erase the
background before drawing, you can avoid flicker without
double-buffering. If not, then you probably do need double-buffering, and
the performance hit is probably unavoidable.

Pete
 
H

hstagni

THANKS.... I understand i was painting twice the area where the ball
is moving(first when refreshing screen and second when redrawing the
ball at its new position).
Now I am manually redrawing the background, and Im making all graphics
operations with a Bitmap object. When the next frame is completely
ready, I draw it on the screen. Now my ball is fast and it isn´t
blinking!

On more question: I had to override the OnPaintBackground method to
make it work only once at the beggining. Here is the code... IS THERE
AN EASIER WAY TO DO IT?

protected override void OnPaintBackground(PaintEventArgs e)
{
if (ft==true){
base.OnPaintBackground(e);
ft=false;
}

}
 
P

Peter Duniho

[...]
On more question: I had to override the OnPaintBackground method to
make it work only once at the beggining. Here is the code... IS THERE
AN EASIER WAY TO DO IT?

Is the off-screen Bitmap object a representation of the entire window,
complete with a filled-in background? If so, then you can simply skip
doing anything in your OnPaintBackground method altogether. Override it
but don't call the base method.
 
H

hstagni

[...]
On more question: I had to override the OnPaintBackground method to
make it work only once at the beggining. Here is the code... IS THERE
AN EASIER WAY TO DO IT?

Is the off-screen Bitmap object a representation of the entire window,
complete with a filled-in background? If so, then you can simply skip
doing anything in your OnPaintBackground method altogether. Override it
but don't call the base method.


It wasn´t, but now it is and now I am overriding the OnPaintBackground
without doing anything. So, everything is fine, excepts for
performance. Anyway, the ball is moving faster than it was with those
"SetStyle", so its fine..Thanks
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top