I just started learning .NET so chances are this is a big n00b mistake:
I'm trying to make a simple pong game, using a form and then the System::Drawing::Graphics class to draw the game to the form.
The significant bits of my code look like this:
(Main Game Loop):
void updateGame()
{
//Update Game Elements
(Update Paddle And Ball) (Ex. paddle.x += paddleDirection;)
//Draw Game Elements
//Double Buffer Image, Get Graphics
Bitmap dbImage = new Bitmap(800, 600);
Graphics g = Graphics::FromImage(dbImage);
//Draw Background
g.FillRectangle(Brushes::White, 0, 0, 800, 600);
//Draw Paddle & Ball
g.FillRectangle(Brushes::Black, paddle);
g.FillRectangle(Brushes::Red, ball);
//Dispose Graphics
g.Dispose();
//Draw Double Buffer Image To Form
g = form.CreateGraphics();
g.DrawImage(dbImage, 0, 0);
g.Dispose();
//Sleep
Thread.sleep(15);
//Continue Or Exit
if(contineGame())
{
updateGame();
}
else
{
exitGame();
}
}
(Form Initialization Code)
void InitForm()
{
form = new Form();
form.Text = "Pong"
form.Size = new Size(800, 600);
form.FormBorderStyle = FormBorderStyle::Fixed3D;
form.StartLocation = StartLocation::CenterScreen;
Application::Run(form);
}
PS. This is not the exact code, I just wrote it from memory, so that's where any typos or wrong names, or some important lines of code to do with initializing the form would be coming from.
So that is the code. My issue is is that the game is certainly not updating every 15 milliseconds (about 60 fps), its going much slower, so what I have to do instead is move the paddle/ball larger amounts of distance each time to compensate for it not updating very quickly, and that looks very bad.
In a nutshell, something when it comes to drawing the graphics is slowing the game down a very large amount. I have a feeling it has something to do with me double buffering, but I cannot get rid of that, since that would create some yucky flickering. My question is, how do I get rid of this lag?
There are several issues with this code that can heavily impact app performance:
Bitmap
buffer every frame and not disposing itThread.Sleep()
in GUI threadCode sample, which uses separate thread to count game ticks and WinForms built-in double-buffering:
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.Run(new GameWindow());
}
class GameWindow : Form
{
private Thread _gameThread;
private ManualResetEvent _evExit;
public GameWindow()
{
Text = "Pong";
Size = new Size(800, 600);
StartPosition = FormStartPosition.CenterScreen;
FormBorderStyle = FormBorderStyle.Fixed3D;
DoubleBuffered = true;
SetStyle(
ControlStyles.AllPaintingInWmPaint |
ControlStyles.OptimizedDoubleBuffer |
ControlStyles.UserPaint,
true);
}
private void GameThreadProc()
{
IAsyncResult tick = null;
while(!_evExit.WaitOne(15))
{
if(tick != null)
{
if(!tick.AsyncWaitHandle.WaitOne(0))
{
// we are running too slow, maybe we can do something about it
if(WaitHandle.WaitAny(
new WaitHandle[]
{
_evExit,
tick.AsyncWaitHandle
}) == 0)
{
return;
}
}
}
tick = BeginInvoke(new MethodInvoker(OnGameTimerTick));
}
}
private void OnGameTimerTick()
{
// perform game physics here
// don't draw anything
Invalidate();
}
private void ExitGame()
{
Close();
}
protected override void OnPaint(PaintEventArgs e)
{
var g = e.Graphics;
g.Clear(Color.White);
// do all painting here
// don't do your own double-buffering here, it is working already
// don't dispose g
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
_evExit = new ManualResetEvent(false);
_gameThread = new Thread(GameThreadProc);
_gameThread.Name = "Game Thread";
_gameThread.Start();
}
protected override void OnClosed(EventArgs e)
{
_evExit.Set();
_gameThread.Join();
_evExit.Close();
base.OnClosed(e);
}
protected override void OnPaintBackground(PaintEventArgs e)
{
// do nothing
}
}
}
Even more improvements can be made (for example, invalidating only parts of game screen).
Don't create a new Bitmap
every frame.
Don't use Thread.Sleep
. Instead check out the Timer
component (the one in the System.Windows.Forms
namespace).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With