本项目的目标是创建一个可重用的Managed DirectX类库,作为基础2D游戏开发的基石。希望目标已经达成。作为游戏爱好者,向介绍GameUtil类库,可以自由使用它的代码。无论是启动自己的2D游戏项目,扩展或修改代码以满足个人需求,还是仅仅为了学习目的浏览源代码,这个类库都能为提供帮助。
为了方便使用,并作为小型教程,包含了一个演示项目,展示了如何使用GameUtil类库轻松构建基本的2D游戏引擎。
除了应该已经拥有的.NET 1.0/1.1之外,还需要安装最新版本的Managed DirectX SDK(截至本文撰写时为DirectX 9.0 SDK夏季更新2003)。是的,即使是演示项目也需要它。
DDGameSurface类可以作为游戏表面,可以附加到任何.NET控件上。它非常灵活,允许窗口模式(无论是Form还是Control)和伪全屏模式。它为处理一切,包括后缓冲区工作和恢复丢失的表面。
创建和显示DDGameSurface非常简单:
C#
DDGameSurface gameSurface = new DDGameSurface(control);
gameSurface.Clear(Color.White);
gameSurface.DrawText(0, 0, "Hello!", false);
gameSurface.Display();
gameSurface.Dispose();
DDGraphic类是从Surface类派生的,并提供了更适合游戏的功能,包括设置帧、帧大小和检索要绘制的帧区域。这非常适合动画。但是不用担心,如果图形没有帧,实际上不需要设置这些细节。
以下是上述示例的扩展,展示了如何创建和显示DDGameGraphic:
C#
DDGraphic playerGraphic = new DDGraphic("player.bmp", new SurfaceDescription(), gameSurface);
playerGraphic.SetTransparency(0x00111111);
playerGraphic.FrameSize = new Size(32, 32);
if (gameSurface.CanDraw) {
gameSurface.Clear(Color.White);
gameSurface.DrawTransparent(0, 0, playerGraphic, playerGraphic.GetFrameArea(0));
}
gameSurface.Display();
playerGraphic.Dispose();
通常不会直接创建DDGraphic,而是让DDGameGraphics类处理所有繁琐的工作。DDGameGraphics类充当游戏图形的查找表,可以通过简单的XML编辑技能随时更改它们。这样,可以通过简单的对象实例化加载所有游戏图形(或特定地图的图形)。DDGameGraphics类还提供了灵活性。不再需要将那些讨厌的常量硬编码到图形位置,而是可以使用DDGameGraphics类,它使用XML文档提供的信息为加载它们。是的,它支持嵌入式图形。
以下是代码示例:
C#
// graphics.xml (注意,唯一必需的属性是key和path)
<GameGraphics>
<graphic key="player" path="Namespace.player.bmp" frameWidth="32" frameHeight="32" transColor="00111111" embedded="true"/>
<graphic key="enemy" path="Namespace.enemy.bmp" frameWidth="32" frameHeight="32" transColor="00111111" embedded="true"/>
</GameGraphics>
// 游戏代码...
DDGameGraphics graphics = new DDGameGraphics("graphics.xml", gameSurface);
DDGraphic playerGraphic = graphics["player"];
DDGraphic enemyGraphic = graphics["enemy"];
// 绘制图形。
// 不需要处理DDGraphics的释放,DDGameGraphics会为处理。
graphics.Dispose();
DIMouse类可能一开始看起来有点奇怪。这是因为DIMouse对象只有在调用Update()方法时才会更新其内部状态。其他一切都很容易理解和使用。DIMouse类封装了期望从鼠标获得的几乎所有内容,包括光标坐标、按钮点击(甚至滚轮点击)和滚轮移动。与DDGameSurface不同,DIMouse必须为Form创建。
以下是快速示例:
C#
DIMouse mouse = new DIMouse(form);
// 在游戏循环内。
mouse.Update();
if (mouse.LeftClick) {
Console.WriteLine("Left click at coordinates: " + mouse.Location);
}
// --
mouse.Dispose();
DIKeyboard的工作方式与DIMouse相同,只是它提供了不同的接口来访问键盘信息。
DIKeyboard在行动中:
C#
DIKeyboard keyboard = new DIKeyboard(form);
// 在游戏循环内。
if (keyboard[Key.A]) {
Console.WriteLine("The A key is pressed!");
}
// --
keyboard.Dispose();
没有某种高性能计时器的游戏是不完整的。QPTimer类为封装了查询性能计数器和频率,因此只需要使用其简单的接口即可。而且不用担心,每秒的滴答数是一个浮点数。顺便说一句,没有属性返回每毫秒的滴答数,但这很容易自己解决 - 只需将TicksPerSecond属性乘以1000即可。
一个展示QPTimer的游戏循环示例:
C#
QPTimer timer = new QPTimer();
timer.Start(QPTimer.Counter);
while (gameRunning) {
timer.Record();
// 处理鼠标输入。
// 处理键盘输入。
// 使用timer.TicksPerSecond更新游戏逻辑。
// 绘制图形。
Console.WriteLine("FPS: " + 1.0F / timer.TicksPerSecond);
timer.Start(timer.RecordTime);
}
如果没有实际展示如何使用GameUtil类库来创建游戏引擎,那么仅仅提供一个类库是没有意义的。因此,创建了一个演示,展示了如何将GameUtil类库的大部分功能付诸实践。如果真的想,可以使用演示作为创建自己的2D游戏的模板。至少,它将是一个如何开始的很好的教程。