快捷搜索:  as  2018  FtCWSyGV  С˵  test  xxx  Ψһ  w3viyKQx

澳门新葡亰平台app_龟发之家论坛



本文来自codeprojct上一篇文章http://www.codeproject.com/Articles/25909/Game-Programming-One,可以说是翻译,然则只保留精髓部分。

Winform窗体是事故驱动的,但游戏不是。以是我们必要为游戏设计一个轮回体(俗称游戏轮回?)

///

/// 游戏平日不是事故驱动的。///

以是我们设计一个轮回,在轮回里面进行“获取输入”、“逻辑处置惩罚”和“绘图”操作。

///

毛病:电脑设置设置设备摆设摆设不合,场景繁杂程度不合等都邑导致游戏更新速率不合。///

实际上,游戏平日会运行的过快,使得玩家反映不过来。

///private static void GameLoop1()

{bool runGame = true;

while (runGame){

GetInput();PerformLogic();

DrawGraphics();}

}

如注释所说,GameLoop1实现了获取输入、逻辑处置惩罚和绘图这三项基础功能,算是游戏的骨架。然则这个轮回在99%的环境下会由于速率太快使得玩家澳门新葡亰平台app无法反映过来。

于是呈现了下面的改进版。

static bool doStuff = false;

////// 用计时器节制游戏更新的速率。客服了GameLoop1的毛病。

///

实际上从这一版的游戏开始才是真正能玩的。///

毛病:平日DrawGraphics是最慢的部分。若这部分太慢,全部游戏速率就会下降。

///

你可以想象DrawGraphics逐步悠悠的进行着,而mainTimer已经滴答了很多多少次,doStuff已经多次被置为true,游戏输入和逻辑却无法更新。///

private static void GameLoop2(){

Timer mainTimer = new Timer();mainTimer.Interval = 1000 / 60;

mainTimer.Elapsed += new Elaps澳门新葡亰平台appedEventHandler(mainTimer_Elapsed);bool runGame = true;

while (runGame){

if (doStuff){

GetInput();PerformLogic();

DrawGraphics();doStuff = false;

}}

}

static void mainTimer_Elapsed(object sender, ElapsedEventArgs e){

doStuff = true;}

GameLoop2用计时器节制游戏更新的速率。理论上是办理了GameLoop1的问题。

但实际上,一个游戏最耗时的部分是绘图。你可以想象DrawGraphics逐步悠悠的进行着,而mainTimer已经滴答了很多多少次,doStuff已经多次被置为true,游戏输入和逻辑却无法更新。

于是又呈现了下面的改进版。

static uint speedCounter = 0;

//static澳门新葡亰平台app bool doStuff = false;///

/// 若DrawGraphics太慢,会导致speedCounter跨越1,这样,下次就只进行输入、逻辑处置惩罚,省略了绘制画面。///

降服了GameLoop2的毛病。

///private static void GameLoop3()

{Timer mainTimer = new Timer();

mainTimer.Interval = 1000 / 60;mainTimer.Elapsed += new ElapsedEventHandler(mainTimer_Elapsed);

bool runGame = true;while (runGame)

{if (speedCounter > 0澳门新葡亰平台app)

{GetInput();

PerformLogic();speedCounter--;

if (speedCounter == 0){

DrawGraphics();}

}}

}

static void mainTimer_Elapsed(object sender, ElapsedEventArgs e){

speedCounter++;//doStuff = true;

}

你可以想象,当绘图部分跨越一帧(mainTimer的一个Interval),speedCounter会跨越1,这样就省略一次绘图操作。办理了GameLoop2的问题。

演化到这里就算是理论可行了。不过要放到Winform法度榜样中,必要形式上做一点改变,本色是不变的。

步骤如下:

1. 创建Winform法度榜样,为主窗体Form1添加一个Timer控件timer1,设置timer1.Enabled属性为true。

2. 为Form1添加两个成员变量。

uint speedCounter = 0;

bool drawGraphics = false;

3. 为timer添加Tick事故。

private void timer1_Tick(object sender, EventArgs e)

{speedCounter++;

PerformGameLogic();

speedCounter--;

if (speedCounter == 0){

drawGraphics = true;}

this.Invalidate();}

4. 覆盖窗体的OnPaint事故和OnPaintBackground事故

protected override void OnPaint(PaintEventArgs e)

{//base.OnPaint(e);

if (drawGraphics){

Brush myBrush = new SolidBrush(Color.Black);e.Graphics.FillRectangle(myBrush, 0, 0, this.Width, this.Height);

myBrush = new SolidBrush(Color.Green);e.Graphics.FillPie(myBrush, 100, 100, 200, 200, 0, 360);

myBrush.Dispose();

drawGraphics = false;}

}

protected override void OnPaintBackground(PaintEventArgs e){

//base.OnPaintBackground(e);// Nothing to do.

}

大年夜功告成,运行结果如下:

刚刚说了形式上的变更在步骤中已经看到了:逻辑处置惩罚放到了timer事故里(输入部分由Winform的各类鼠标键盘事故完成)。

假如你想问timer1_Tick里面的

if (speedCounter == 0)

是不是始终都是true?有什么意义?

这便是改到Winform后的又一个改进了。假如timer1_Tick的履行光阴跨越了timer1.Interval,speedCounter == 0可能就不是true了!

以是,这个改进便是,当游戏逻辑的履行光阴跨越一帧的时刻,只有着末一次的超长光诡计略后才更新绘图。

这个版本还有一个潜在“问题”,若绘图部分速率太慢,timer1的Tick事故里不绝的调用this.Invalidate();,会不会导致OnPaint()事故在一次履行尚未完毕的时刻就开始了下一次的履行?

谜底是不会。缘故原由嘛,不知道……我只是经由过程试验发明,纵然Invalidate()函数比OnPaint()履行的频率快,也不会引起OnPaint()事故发生那种环境。最多是一次履行完毕的瞬间急速开始履行下一次。我猜想这是windows底层的消息行列步队机制在起感化吧。有高手懂的话请多多辅导哈。

而且我又经由过程试验发明,纵然澳门新葡亰平台app把timer1的Interval设定为很小(比如10毫秒),若OnPaint履行光阴很长,timer1的下一次Tick也会被顺延到OnPaint履行完之后才发生。便是说,这个版本不能包管游戏每一帧的等时性。

好吧, 问题太多了。原作者原先很好的思路,到着末弄的什么都不是。Timer只应该用来计时,GameLogic和绘图分手用两个线程完成,输入应该保存到一个行列步队里,在Tick时统一处置惩罚。这才对。

我只好自己收拾了一个新版本。算是接受了原作者的英华,利用到Winform上面来了。

以是我自己创建了新的版本。

用SharpGL做绘图,后台线程做GameLogic,System.Timers.Timer做准时器的3D游戏骨架。

下载链接在这里:Game骨架.rar

您可能还会对下面的文章感兴趣: