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

C# .NET 版吃豆人游戏

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.38/5 (11投票s)

2004 年 7 月 14 日

CPOL

5分钟阅读

viewsIcon

128507

downloadIcon

3157

一篇关于 Pocket PC 游戏开发的文章。

引言

要玩游戏,您需要一台安装了 .NET Compact Framework 1.1 的 Pocket PC 设备。安装很简单,只需将 mypacman.exe 文件复制到设备上的新文件夹中即可。显然不需要任何附属文件,因为三个 Wav 音频文件和两个 GIF 图像文件都作为“嵌入式资源”集成到了可执行文件中。

要开始玩游戏,请按 Enter 键,然后使用方向键引导吃豆人。游戏的目标是不要被红色的幽灵吃掉。有四个紫色的“大点”,吃掉它们后,会把邪恶的红色幽灵变成温顺的蓝色幽灵,然后可以被吃掉。这个“自由时间”是有限的,它的延长通过一个出现在分数下方的彩色条来表示,并且开始变小。您有三条命。 一旦吃掉了所有的小点,您就进入新关卡,在该关卡中,“害怕”幽灵的时间会减少。从第二关开始,红色的幽灵开始“追踪”吃豆人(而不是随机改变方向),您需要格外小心!

当您失去所有生命后,游戏将进入演示模式,闪烁屏幕并显示幽灵四处移动。要重新开始游戏,只需按 Enter 键。

当前游戏只有一个迷宫设计,因此作为改进,您可以设计新迷宫用于不同关卡,也可以设计新型奖励和“反派”。

使用代码

此项目包含七个类,位于七个源文件中:GameForm.csGhostsManager.csPacmanManager.csSound.csSprite.csStopWatch.csGameFont.cs。前三个是重要的类;我将简要描述它们的功能。代码注释相当充分,您也可以从中得出结论。

项目的主类是 GameForm。它负责所有游戏流程逻辑,并包含 GhostsManager 类和 PacmanManager 类的实例作为成员。它派生自 System.Windows.Forms.Form 类,负责主游戏循环和所有图形。这个游戏的关键组件是一个 15x15 字节的数组,负责定义迷宫、小点和大点。

private byte[] LEVEL1DATA = 
{
  19,26,18,26,26,26,22,7,19,26,26,26,18,26,22,
  37,7,21,3,10,14,21,13,21,11,10,6,21,7,37,
  .....
  .....
  25,26,26,26,26,26,24,26,24,26,26,26,26,26,28
};

游戏场地尺寸由以下常量定义:BLOCKSIZE = 16,NROFBLOCKS = 15,SCRSIZE = NROFBLOCKS x BLOCKSIZE

游戏区域由 NROFBLOCKS x NROFBLOCKS 个块组成,每个块宽 BLOCKSIZE 像素。这意味着游戏场地是一个 SCRSIZE 像素宽的正方形。

数组中每个字节的位值决定了相应块是否(从 LSB 开始)有左迷宫墙、上迷宫顶、右迷宫墙、下迷宫底、小点和大点。还有两个位未使用,可以用于在未来的增强功能中为迷宫添加更多特性。

使用双缓冲来避免闪烁。在游戏开始时,整个迷宫会被加载到一个方便地命名为 mazeGraphicsGraphics 对象中。在游戏循环的每次迭代中,该 Graphics 对象会根据是否消耗了小点或大点而更新,然后由 mazeGraphics 表示的整个 Bitmap 对象 mazeBitmap 会被绘制到主屏幕外 Graphics 对象 offScreenGraphics 上。请注意,对 mazeGraphics 的唯一更改是移除一个小点或大点,而无需在每次迭代中完全重新构建整个迷宫。

public void DotConsumed(int arraypos, Sprite pacman)
//callback function invoked by pacManager 
//notifying that dot has been consumed
{
    ...
    if ((ch&16)!=0) // you just ate a dot! 
    {
        ...
        mazeGraphics.FillRectangle(brush, 
          pacman.x+BLOCKSIZE/2,pacman.y+BLOCKSIZE/2,3,3);
        // clear bits 16 and 32 (no dot or yummy)
        screendata[arraypos]=(byte)(ch&15);
        score++;
    }
    if ((ch&32)!=0) // just ate a yummy 
        {
        ...
        mazeGraphics.FillRectangle(brush, 
          pacman.x+BLOCKSIZE/3, 
          pacman.y+BLOCKSIZE/3,BLOCKSIZE/3,BLOCKSIZE/3);
        screendata[arraypos]=(byte)(ch&15);
        score+=5;
    }
}

private void DrawMaze()
{
    offScreenGraphics.DrawImage(mazeBitmap, 0, 0, 
            this.ClientRectangle, GraphicsUnit.Pixel);
}

另外两个重要的类是 GhostsManagerPacmanManager

PacmanManager,顾名思义,负责吃豆人的移动和显示。吃豆人封装在一个 Sprite 对象中。吃豆人的所有视图都包含在 PacMans.gif 中。GameFormKeyEventHandler(在调用 this.focus() 获取焦点后)委托给 PacmanManagerkeydown() 方法,该方法会更新吃豆人请求的移动方向。这里重要的概念是,吃豆人在每次游戏循环迭代中以 PACMANSPEED=2 的增量移动,而 PACMANSPEEDBLOCKSIZE=16 的一个因子,因此吃豆人保证会填满它访问的每个块。当吃豆人完全移动到一个块中时,如果最后一个请求的方向更改有效(即没有撞到迷宫墙),它就会改变方向。

public void MovePacMan(GameForm form)
{
    byte ch;   
    if (reqdx==-pacman.dx && reqdy==-pacman.dy)
    //this is when it reverses direction
    {
        pacman.dx=reqdx;
        pacman.dy=reqdy;
        viewdx=pacman.dx;
        viewdy=pacman.dy;
    }
    else if (pacman.x%GameForm.BLOCKSIZE==0 && 
      pacman.y%GameForm.BLOCKSIZE==0) //its in the middle of a block 
    {
        arraypos=pacman.x/GameForm.BLOCKSIZE  +  
          GameForm.NROFBLOCKS*(pacman.y/GameForm.BLOCKSIZE);
        ch = form.screendata[arraypos];
        ....
        ....
        OnDotConsumed(arraypos, pacman);
        //notify parent that yummy or dot has been 
        //consumed so as to update maze
    }
    DrawPacMan();
}

GhostsManager 是负责处理幽灵所有移动和显示的类。幽灵包含在一个 Sprite 对象数组中,在第一关游戏中,它们会随机改变方向。GhostsManager 还负责检测与吃豆人的碰撞并设置相应的变量。如果游戏处于“害怕”模式且幽灵被撞到,它将被“杀死”,在撞击处消失,并在游戏场地中心重生。如果在游戏模式下(当它们是红色时)撞到幽灵,将从玩家那里减去一条生命。幽灵的所有可能速度也是 BLOCKSIZE 的因子。

private int[] VALIDSPEEDS = { 1,2,4,8 };
// all these are factors of BLOCKSIZE

关注点

一个值得注意的点是 GameForm.cs 中的事件处理方法 DotConsumed(int arraypos, Sprite pacman)。它订阅了 PacManager.OnDotConsumed 委托实例。每当吃豆人消耗了一个小点或大点时,父类 GameForm 就会通过此机制得到通知,以便更新 mazeGraphics 并将其从显示中移除。

//In GameForm() constructor:
pacManager.OnDotConsumed += new PacmanManager.DotConsumedHandler(this.DotConsumed);

//In PacManager.cs:
public delegate void DotConsumedHandler(int arraypos, Sprite pacman);
public event DotConsumedHandler OnDotConsumed;

另一个值得注意的点是幽灵在完成第一关后使用的追踪算法(一种简单的“人工智能”)。在可能的情况下,它只会考虑能够缩短其与吃豆人之间 x-y 距离的移动方向。

if(form.pacManager.pacman.y<ghosts[i].y || goRandom)
{
    dx[count]=0;
    dy[count]=-1;
    count++;
}
© . All rights reserved.