上一篇笔记最后提到游戏是一种背景工作(background work)吗? 回答这个问题先要了解游戏和普通的GUI的区别在于哪里. 游戏和普通GUI程序最大的差异在于即使用户没有输入, 游戏内部也在进行大量的逻辑处理(物理碰撞, 人工智能等), 而普通的GUI程序则是根据用户输入进行某种响应. background work可以把系统的闲置资源充分利用起来, 适合于大型游戏.
在游戏和普通GUI程序之间, 还有第三个选择: 图形动画程序. 这种程序要将绘制逻辑放在Idle中来处理吗? 还是有其他的方法. 我觉得MSDN论坛的一个问题做了很好的解答.
Event Driven WPF vs XNA style looping
https://social.msdn.microsoft.com/Forums/en-US/356dd3b1-4168-46fa-bc1d-ba0137feb133/event-driven-wpf-vs-xna-style-looping?forum=wpf
解答如下:
The two options you listed are usually used because of the differences in how applications update:
1) Event-Driven is usually used because your application is responding to a user.
2) Loop-Driven is used when the application needs to update, regardless of user interaction. (Games, ie: XNA, often use this because the screen is updating even if the user is doing nothing).
The two are not mutually exclusive (互斥). In fact, it’s quite common to see an event based application start a timer that will trigger an “event” in a repeated “loop”. Typically, this is done differently than a loop-driven application, but the effect is similar.
I would recommend not using a full render loop style loop in a GUI-based application, however. They are very oriented towards games and attempts to have a near-realtime experience, and tend to cause user interaction to suffer. Instead, use a timer, such as the DispatcherTimer, or subscribe to CompositionTarget.Rendering when you need to have a loop-driven style. You can easily remove the event handler when you are done with your continual update.
他的意思是基于GUI的程序(普通GUI程序+图形动画程序)更适合用Timer去做. 而且, 放在Idle里面的话, 用户的输入会打断正在进行的逻辑处理.
进一步, WPF和Silverlight同样可以做游戏(卡牌, 页游等)
Game Programming with Silverlight一书中提到3种图形动画开发方式
其中有两种就是上面提到的DispatcherTimer和CompositionTarget.Rendering, 另外一种是故事板(storyboard)
1 | DispatcherTimer dispatcherTimer = new DispatcherTimer(DispatcherPriority.Normal); |
1 | public partial class Page : UserControl |
另外可以参考Channel 9上的Creating Games with Silverlight: A Simple Shooter
https://channel9.msdn.com/coding4fun/articles/Creating-Games-with-Silverlight-A-Simple-Shooter1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18public Page()
{
InitializeComponent();
keyHandler = new KeyHandler(this);
GenerateStarField(350);
InitializeGame();
}
void InitializeGame()
{
gameLoop = new GameLoop(this);
gameLoop.Update += new GameLoop.UpdateHandler(gameLoop_Update);
PlayerShip = new Ship(10, 10, new Point(100, 360));
gameRoot.Children.Add(PlayerShip.SpriteCanvas);
gameLoop.Start();
}
这就是用Timer去模拟loop-driven的方式.
Silverlight在技术分类上等同于Flash, 可以想象Flash页游的GameLoop是怎样的一个实现, 关于Flash另外展开.
这里提到的full render loop style loop代码如下, 就是上一篇笔记提到的game loop
https://blogs.msdn.microsoft.com/tmiller/2005/05/05/my-last-post-on-render-loops-hopefully/
用在ManagedDX中(托管的DX)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46//The most common topic on my blog returns again. This time it will be brief as all I’m going to to do now is show you the render loop the June’05 SDK will be using. A coworker in another group came up with this markedly simple, yet deceptively effective loop for that groups projects. I liked it so much, i’m sharing it with everyone else. =)
//The basic loop (slightly modified from his original version and the version in the new SDK for ease of reading):
public void MainLoop()
{
// Hook the application’s idle event
System.Windows.Forms.Application.Idle += new EventHandler(OnApplicationIdle);
System.Windows.Forms.Application.Run(myForm);
}
private void OnApplicationIdle(object sender, EventArgs e)
{
while (AppStillIdle)
{
// Render a frame during idle time (no messages are waiting)
UpdateEnvironment();
Render3DEnvironment();
}
}
private bool AppStillIdle
{
get
{
NativeMethods.Message msg;
return !NativeMethods.PeekMessage(out msg, IntPtr.Zero, 0, 0, 0);
}
}
And the declarations for those two native methods members:
[]
public struct Message
{
public IntPtr hWnd;
public WindowMessage msg;
public IntPtr wParam;
public IntPtr lParam;
public uint time;
public System.Drawing.Point p;
}
[] // We won’t use this maliciously
[]
public static extern bool PeekMessage(out Message msg, IntPtr hWnd, uint messageFilterMin, uint messageFilterMax, uint flags);







