65.9K
CodeProject 正在变化。 阅读更多。
Home

游戏开发框架

2010年5月20日

GPL3

4分钟阅读

viewsIcon

50251

downloadIcon

2314

用C#编写的简单游戏开发框架(地图、图形、寻路AI)

VS 2008解决方案,所有代码都通过XML注释进行了彻底的文档记录,方便智能感知。所有变量、方法和类型都得到了详细描述。

引言

游戏开发框架(GameFX)本质上是一组库,用作任何简单2D瓦片游戏的底层基础。它可以用于构建诸如吃豆人、贪吃蛇、俄罗斯方块甚至国际象棋之类的游戏。

如果您想查看一个完整的教程,其中我们将逐步开发此项目,请单击此处。我们将从构思开始,然后经历设计程序的过程,思考所有程序员必须考虑的重要细节。最后,我们将敲定所有必要的代码使其能够工作。

背景

构建和重用一个框架可以极大地简化实际开发游戏的任务。您无需考虑地图、图形和AI的所有繁琐细节,因为它们已经被分离和封装。

这就像建造一个带有按钮、旋钮和开关的盒子。我们将构建一个盒子,里面包含了处理地图逻辑、绘制地图图形和寻找路径的所有机制。在这个盒子的外部,我们将拥有用于操纵地图、寻路器和图形引擎的假想按钮、开关和旋钮。这样做可以使它更简单、更易于使用。如果我们不这样做,那么我们为构建的每个游戏都必须在里面进行调整。

Using the Code

GameFX将处理基于瓦片的地图、图形和寻路,因此我们可以将GameFX分为这三个主要类别。

让我们从瓦片映射开始。瓦片映射的最高层功能单元当然是TileMap。TileMap的基本单位是Tile,它使用Coordinates。

很好,我们已经将第一个类别(瓦片映射)分解为三个功能组件,这些组件可以组合起来执行瓦片映射的功能。

  • Tile瓦片地图的基本单位
  • TileMap可操作的瓦片二维地图
  • Coordinate一种简单的数据类型,表示瓦片地图上的X、Y值

这是图形引擎。

  • GraphicsEngine以图形方式渲染TileMap的机制

我们可以将寻路类别分解为这三个组件。

  • Node一种用于在两个坐标之间寻找路径的有趣机制
  • NodeHeap一种排序存储机制,是A*寻路算法的关键
  • SimplePathFinder在TileMap上寻找从一个坐标到另一个坐标的路径的机制

这是GameFX最简单的可工作示例。代码创建一个10x10的Byte类型Tile地图。0代表地板,1代表路径,2代表墙壁。图形引擎会将地图绘制到Form1上,地图的所有更改都将实时渲染。地图中间有一堵墙。寻路器将寻找从左上角到右下角的路径。

using HenizeSoftware.GameFX.PathFinding;
using HenizeSoftware.GameFX.TileMap;

namespace WindowsFormsApplication1
{
  public partial class Form1 : Form
  {
    TileMap<byte> myMap;
    GraphicsEngine<byte> gfx;
    SimplePathFinder<byte> path;
  
    public Form1()
    {
      InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
      myMap = new TileMap<byte>(10, 10);
      gfx = new GraphicsEngine<byte>(myMap, this.CreateGraphics(), 
		10, 10, RenderMode.OnChanged);
      path = new SimplePathFinder<byte>(myMap);

      path.ResistanceDictionary.Add(2, 255);
      
      path.Start = new Coordinate(0, 0);
      path.End = new Coordinate(9, 9);

      gfx.ColorDictionary.Add(0, Color.Black);
      gfx.ColorDictionary.Add(1, Color.Pink);
      gfx.ColorDictionary.Add(2, Color.White);

      gfx.DrawAllTiles();

      for (ushort i = 8; i > 0; i--) //draw wall down the middle
        myMap[4, i].Value = 2;
    }

    private void Form1_Paint(object sender, PaintEventArgs e)
    {
      if(gfx != null)
        gfx.DrawAllTiles();
    }

    private void button2_Click(object sender, EventArgs e)
    {
      foreach (Coordinate c in path.GetFullPath())
        myMap[c].Value = 1;
    }
  }
}

关注点

代码中可能存在一些我尚未发现的小错误。但是我开发了一个测试程序,可以让你创建任意大小的地图,并在地图上放置任意数量的蛇,只要你的电脑能处理。蛇在地图上追逐食物。你可以在地图运行时在其上绘制。你还可以选择使用位图图形进行绘制。速度也可以调整。

首先,你必须在可以进行任何操作之前单击“新建地图”。你也无法移除最后一条蛇。

代码本身很容易理解,但我将重点讲解示例程序的核心部分,也就是让它运转起来的部分。

//Each snake has its own pathfinder. For each snake on the map, 
//find the path to the food and increment the snake toward it.
private void timer_Tick(object sender, EventArgs e)
{
//Go through all of the snakes that are currently on the map
  for (int i = 0; i < snakeList.Count; i++)
  {
    //If the snake being processed has eaten the food then find a 
    //new place to drop food, and then tell all the other snakes
    //the new location of the food.
    if (snakeList[i].HeadCoordinate == pathFinderList[i].End)
    {
      //Drop new food on clear area of map
      while (true)
      {
        food = new Coordinate((ushort)rnd.Next(0, map.Width - 1), 
		(ushort)rnd.Next(0, map.Height - 1));
        if (map[food].Value == SLThTile.Floor) break;
      }
      
      //Tell the other snakes the new location of the food.
      foreach(SimplePathFinder<SLThTile> p in pathFinderList)
        p.End = food;
      
      map[food].Value = SLThTile.Food;
      
      if (btnAutoGrow.Checked == true)
        snakeList[i].Grow(1);
   }
   
    Coordinate next = new Coordinate(); //default 0,0 incase Snake is trapped.
    
    //Try to find the path to the food.
    try
    {
      next = pathFinderList[i].GetNextMove();
    }
    catch (PathNotFoundException)
    {
      snakeList[i].Reverse(); //if no path found then make the snake reverse.
    }
    
    //Figure out the general direction the snake needs to go.
    if (next.X == snakeList[i].HeadCoordinate.X && 
		next.Y < snakeList[i].HeadCoordinate.Y)
      snakeList[i].Direction = SnakeDirection.Up;
    else if (next.X == snakeList[i].HeadCoordinate.X && 
		next.Y > snakeList[i].HeadCoordinate.Y)
      snakeList[i].Direction = SnakeDirection.Down;
    else if (next.X > snakeList[i].HeadCoordinate.X && 
		next.Y == snakeList[i].HeadCoordinate.Y)
      snakeList[i].Direction = SnakeDirection.Right;
    else if (next.X < snakeList[i].HeadCoordinate.X && 
		next.Y == snakeList[i].HeadCoordinate.Y)
      snakeList[i].Direction = SnakeDirection.Left;
      
    snakeList[i].IncrementForward();
    
    pathFinderList[i].Start = snakeList[i].HeadCoordinate;
  }

GameFX的功能远远超出此处所示的示例。通过简单地初始化和配置属性,就可以实现位图图形和许多配置。不要害怕尝试,它可能对你的某个项目有所帮助。

如果您想要更详细的文章,请单击此处

这是GameFX的类图。

ClassDiagram1.jpg - Click to enlarge image

历史

  • 2010年5月20日星期四:首次公开发布
© . All rights reserved.