I am trying to create a simple Breakout type game. I have a game panel on my form that holds my game (the paddle, ball, and board of blocks). I use a timer with an interval of 10 to move the ball a set distance every tick. The problem is that I also draw the board everytime this timer ticks and it flickers. I tried setting the doublebuffered attribute of my form to true but it didnt help.
Anyone have any ideas either a different/ebtter way to buffer it or a different way of drawing the board I tried making a new panel on top of my game panel to just draw the board in but that didnt work for me either (unless I did something wrong).
Thanks in advance

graphics flicker problem (double buffer not working)
Sevugan
By the way, you can still use the Designer to set properties of the BreakOutPanel as if it was a regular Panel. In VS2005, a message box comes up to report an error but you can ignore it. It will draw a red X icon in the panel in the Designer but that's all.
All you should have to do in the BreakOut.Designer.cs file (or whatever you called it) is to change the Panel type of the panel variable from 'System.Windows.Forms.Panel' to your 'BreakOutPanel'. And then change the line where the Designer "new"s it (like my previous post demonstrates) in the InitializeComponent() function.
LennyBaby
toodie44
Here is some my code, if you want to look exactly at what I have instead of trying to go on my description and let me know if I am not doing something right or something. I am pretty sure I have done what you were talking abuot. Invalidate is only called once every time the timer ticks, and all my painting is done in the OnPaint() method (or well, a method called from it).
private void Breakout_Paint(PaintEventArgs e)
{
e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
Graphics g = e.Graphics;
myPen.Width = 1;
g.FillRectangle(Brushes.Black, paddle);
g.FillEllipse(Brushes.Green, ball);
g.SmoothingMode = SmoothingMode.HighSpeed;
drawBoard(g);
}
private void gamePanel_MouseMove(object sender, MouseEventArgs e)
{
if (paddle.X > gamePanel.Location.X + gamePanel.Width)
{
paddle.X = gamePanel.Location.X + gamePanel.Width - paddle.Width;
}
else if (paddle.X < 0)
{
paddle.X = 0;
}
else
{
paddle.X = e.X;
}
}
protected override void OnPaintBackground(PaintEventArgs e)
{
}
protected override void OnPaint(PaintEventArgs e)
{
e.Graphics.Clear(Color.White);
Breakout_Paint(e);
}
}
}
I've included the paint stuff, which is called from the tick method of the timer that has an interval of 10 (I thought that this might be a problem and I am just trying to call it too often and the computer cant handle it, but if I increase the timer then the ball movement gets choppy or really slow)
Thank you all for your help, its greatly appreciated
Welly
Who calls the "Breakout_Pain()" function You said you use Invalidate() to draw. In that case, How is anything ever getting drawn if you're not overriding OnPaint() Unless, you're calling Breakout_Pain() from a loop from within your Main()
Anyways, try just calling Invalidate() from you Main() loop. Then override the OnPaint(), and just call your Breakout_Pain() from within OnPaint(). Still, you need to override the OnPaintBackground() to do nothing. You'll probably need to add a g.Clear() call in the OnPaint() first, before you draw anything else.
teddy_hk
Find in your code where the initializeComponetes is Examples is show be fore and try the three Line i have BIGGER in size and see if theis helps your flickering probelm. Another think i have heard here and there is that double buffer doesnt work in the timer is like under 50 supposably but i have not seen any proof on that.
public
frmAirCraft(){
// // Required for Windows Form Designer support //InitializeComponent();
// // TODO: Add any constructor code after InitializeComponent call // SetStyle( ControlStyles.u, true);SetStyle( ControlStyles.AllPaintingInWmPaint, true);
SetStyle( ControlStyles.UserPaint, true);
}
Joe Lynn
Ya, when I do that nothing ever redraws, it just leaves whatever it drew previously. So like the path of the ball jsut turns into a big line. Unless I am just not doing something that I need to to redraw it.
Oh I should mention that I use Invalidate() to redraw. Is this not right or is there something better
David Yue
Did you try overriding the OnPaintBackground() in your form, then not do anything from inside there
like this:
protected override OnPaintBackground(PainteventArgs e)
{
// Don't call this. Just do nothing.
//base.OnPaintBackground(e);
}
MacroHard
What does your OnPaint() look like
Dhileep
What code do you have in OnPaint()
LarsWa
I just realized that you may want to just get framerate on one specific panel within the form. Then do this.
Create a class that is derived from Forms.Panel.
class BreakOutPanel : public System.Windows.Forms.Panel
{
...
protected override void OnPaint(PaintEventArgs e)
{
// you can call your Breakout_Paint() from within here, or just copy the contents over.
// remove your "sender" parameter. Where's that coming from
BreakOut_Paint(e);
}
protected override void OnPaintBackground(PaintEventArgs e)
{
//base.OnPaintBackground(e); // Don't call this, just to make sure
}
...
}
Then, from your main form's timer handler, you just call that specific control's Invalidate(). Something like:
...
// The Designer will have code like this: Panel bopanel = new Panel();
// but you need to change it to this:
BreakOutPanel bopanel = new BreakOutPanel();
// Your timer could look like this:
System.Timers.Timer timer = new System.timers.Timer();
timer.Tick += new EventHandler(timer_FrameRate);
timer.Interval = 17; // will probably sit at 55 according to .NET docs
timer.Start();
...
void timer_FrameRate(Object sender, EventArgs myEventArgs)
{
bopanel.Invalidate();
}
All this should get just that specific panel (the Breakout game panel) to draw as often as possible, not the rest of your form.
avmoldovan
Thanks for the suggestions, but neither of these fixed my problem. And mike, I'm not really sure how stuff gets drawn because I never do call Breakout_Paint from anywhere, I just assume it gets called when the default OnPaint gets called or something like that.
I think my problem is that I just try to redraw it too often and it just can't draw what I want fast enough and make it not flicker.
JReddy
Okay, I think maybe you're using a timer to call your Breakout_Paint() function is that correct
If you're using a timer to get a framerate, then that's okay I guess--as long as you only call your panel.Invalidate() from the timer.Tick event handler. Don't call Breakout_Paint() directly from the timer.Tick event handler. Instead, move the call to Breakout_Paint() to inside your "protected overriden OnPaint(PaintEventArgs e)" function--that you must override.
The call to Invalidate() will cause the Windows system to in turn call your overriden OnPaint() and OnPaintBackground(). This is the proper way to get anything drawn on your form.
By the way, the contents of my OnPaint() look just like the contents of your Breakout_Paint().
If you're NOT using a timer to call Breakout_Paint(), then where the hack are you calling it from You can right-click the function name, then select "Find All References".
In case you just can't seem to find out how to "override" OnPaint(), here's an example:
class myForm : public System.Windows.Forms.Form
{
...
protected override void OnPaint(PaintEventArgs e)
{
// you can call your Breakout_Paint() from within here, or just copy the contents over.
// remove your "sender" parameter. Where's that coming from
BreakOut_Paint(e);
}
protected override void OnPaintBackground(PaintEventArgs e)
{
//base.OnPaintBackground(e); // Don't call this, just to make sure
}
...
}
Remember, if you're using a timer to get framerate, only call myFormInstance.Invalidate(), and nothing else, from within the timer's Tick event handler, that I think you're using.
Karulont
I dont override the OnPaint() method, I just do a lot of stuff in the Breakout_Pain() method [Breakout is the name of my main form];
private
void Breakout_Paint(object sender, PaintEventArgs e){
Graphics g = e.Graphics;g.FillRectangle(
Brushes.Black, paddle);g.FillEllipse(
Brushes.Green, ball);drawBoard(g);
}
thats all I havei n there. drawBoard() just has a couple loops that go through an array of rectangles and just call g.FillRectangle() for all of them to draw the blocks.
NetMage
With Windows programs, you can't draw stuff and have it hang around - you have to have an OnPaint() handler and draw everything in there. Otherwise, it just won't work.