我刚刚开始学习.NET,所以很有可能这是一个很大的错误:
我正在尝试制作一个简单的乒乓球游戏,使用表格,然后使用 System :: Drawing :: Graphics类将游戏绘制到表单中。
我的代码的重要部分如下所示:
(主游戏循环):
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();
}
}
(表格初始化代码)
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。这不是确切的代码,我只是从内存中写的,所以这就是任何错别字或者 错误的名称或初始化表单的一些重要代码行将来自。
这就是代码。 我的问题是游戏肯定不是每15毫秒(大约60 fps)更新,它的速度要慢得多,所以我要做的就是每次移动桨/球更大的距离以补偿它不更新很快,这看起来非常糟糕。
简而言之,在绘制图形方面的一些事情正在大大减慢游戏速度。我觉得它与我的双缓冲有关,但我无法摆脱它,因为那会产生一些令人讨厌的闪烁。我的问题是, 我如何摆脱这种滞后?
答案 0 :(得分:6)
此代码存在多个问题,可能严重影响应用性能:
Bitmap
缓冲区而不是将其丢弃Thread.Sleep()
代码示例,它使用单独的线程来计算游戏标记和WinForms内置双缓冲:
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
}
}
}
可以进行更多改进(例如,仅使游戏画面的某些部分无效)。
答案 1 :(得分:2)
不要每帧都创建一个新的Bitmap
。
请勿使用Thread.Sleep
。而是检查Timer
组件(System.Windows.Forms
命名空间中的组件)。