使用有限状态机构建游戏代理

本文是关于如何创建使用有限状态机(Finite State Machine, FSM)的代理的实用示例。在这篇文章中,将尝试解释如何使用WinForms和GDI+实现FSM代码。将探讨一个游戏环境,其中代理居住在一个名为WestWorld的Old West风格的金矿小镇。WestWorld有两个居民——一个名叫Miner Bob的金矿工人和他的妻子Amanda。

本教程的目标是向展示如何从头开始创建一个简单的游戏,不使用像XNA或DirectX这样的高级API,这些API为自动化了一半的过程。将只使用Windows表单和GDI+进行一些基本的绘图,并为了一点额外的方便,使用了几个表单的事件。

地图生成

WestWorld使用了一个修改版的VB.NET版本的RogueSharp。地图生成创建了一个随机生成的独特地图。地图可能看起来与显示的地图不同。

RogueSharp是一个用C#编写的免费库,帮助roguelike开发者在他们的游戏中取得领先。RogueSharp提供了许多实用功能,用于处理地图生成、视野计算、路径查找、随机数生成等。它还包含了制作房间和洞穴地图的策略。

与RogueSharp的大多数交互都是基于 Map 的概念,这是一个矩形网格的 Cells 。每个 Map 中的 Cell 具有以下属性:

  • IsTransparent:如果视野可以透过 Cell,则为true。
  • IsWalkable:如果玩家可以穿越 Cell,则为true。
  • IsExplored:如果玩家曾经有视线到 Cell,则为true。
  • IsInFov:如果 Cell当前在玩家的视野中,则为true。

要实例化一个新的 Map ,可以使用其构造函数,该构造函数接受宽度和高度,并创建一个具有这些尺寸的新地图,并将所有 Cells 的属性设置为false。

注意 Map 类上的 ToString() 运算符被重写,以提供地图的简单视觉表示。可以为 ToString() 提供一个可选的 bool 参数,以指示是否要使用视野。如果没有提供参数,则默认为false。

使用以下符号:

  • %:Cell不在视野中。
  • .:Cell透明、可行走,且在视野中。
  • s:Cell可行走且在视野中(但不透明)。
  • o:Cell透明且在视野中(但不可行走)。
  • #:Cell在视野中(但不透明或不可行走)。

创建地图的一个更有趣的方法是使用 Map 类的静态方法 Create ,它接受一个 IMapCreationStrategy 。RogueSharp提供了一些实现 IMapCreationStrategy 的简单类,但通过创建自己的类来实现策略,这是很容易扩展的。

对于RogueSharp的原始版本,可以在 上找到NuGet包。

精灵渲染

为了使WestWorld动画化,简单地绘制一个图像,然后移动到下一帧,然后绘制序列中的下一个图像。因此,需要跟踪正在动画化的帧数、动画中的帧数、单个精灵的宽度和高度,以及转向的方向。为了动画化图像,在 (0, 32) 处绘制图像,然后在下一帧,在 (33, 65) 处绘制图像,然后重复。

VB代码示例:

Dim sizeOfSprites As Integer = 32 Dim scale As Double = 0.5F Dim rectPosition As New System.Drawing.Rectangle(X * sizeOfSprites, Y * sizeOfSprites, _Width, _Height) buffer.DrawImage(_Image, rectPosition, imageX, imageY, _Width, _Height, GraphicsUnit.Pixel)

图像太大,无法适应屏幕。因此,让将所有的精灵缩小到1/2大小,16 x 16像素。使用 Bitmap 类的 DrawImage 方法,可以根据其当前位置设置要绘制的精灵的比例。

地图绘制

要实际看到地图,需要在 World.vb 中的 Draw() 方法中添加一些代码。设置一个变量,对应于用于地板和墙单元格的精灵大小。如果使用了提供的图形,这些是64像素的正方形。这个值将用于计算绘制每个精灵的位置。接下来,调用新创建的 _map 上的 GetAllCells ()方法。这返回一个 IEnumerable <cell> ,包含地图中的所有单元格,可以使用 For Each 循环遍历它们。当遍历每个 Cell 时,检查 IsWalkable 属性。这将决定否应该绘制地板。通过查看相应 CellXY 属性并将其乘以设置的变量来计算应该绘制精灵的位置。这就是实际调用 Bitmap 缓冲变量上的 Draw 方法并提供地板或墙壁纹理以及之前计算的位置的地方。

Public Sub Draw(ByVal g As Graphics) Dim sizeOfSprites As Integer = 64 Dim scale As Double = 0.5F Dim multiplier As Integer = CInt(sizeOfSprites * scale) Dim myBrush As Brush = New SolidBrush(Color.Yellow) For Each Cell As Cell In _map.GetAllCells Dim Text As String = String.Format("X:{0}, Y:{1}", Cell.X, Cell.Y) If Cell.IsWalkable And Cell.IsTransparent Then Dim position As New System.Drawing.Point(CInt(Cell.X * multiplier), CInt(Cell.Y * multiplier)) g.DrawImage(_Grass, position) Else Dim position As New System.Drawing.Point(CInt(Cell.X * multiplier), CInt(Cell.Y * multiplier)) g.DrawImage(_Wall, position) End If Next End Sub
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485