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

PocketPC 版的扫雷和 MinsweeperFlags(多人版)

starIconstarIconstarIconstarIconemptyStarIcon

4.00/5 (14投票s)

2004 年 5 月 31 日

CPOL

4分钟阅读

viewsIcon

64661

downloadIcon

627

Pocket PC .NET Compact Framework 版扫雷和MinsweeperFlags(多人游戏)合一

引言

这是我制作的经典游戏版本,也是对CodeProject移动开发者竞赛的贡献。这是我的第二个.NET Compact Framework应用程序(第一个当然是HelloWorld。)这也是我的第一篇CodeProject文章。

我一直在Pocket PC上怀念着我们以前的扫雷游戏。所以我决定花上几个晚上,尝试使用Visual Studio .NET。一个星期后,我制作出了一个普通的单人版。

第二步是对这个游戏进行多人修改(类似于MSN Messenger的MinsweeperFlags)。一个热座模式(两位玩家在同一台Pocket PC上)很快就完成了,但我的目标是实现网络或IrDA连接的游戏。我写了网络层……这就是我目前的进度。

游戏规则

单人模式

大家都知道扫雷的简单规则。我的单人模式也是一样的。

多人模式

因为MinsweeperFlags不像经典的扫雷那么出名,我想多说几句它的规则。游戏中有两个玩家:红色和蓝色。游戏目标是找到并标记隐藏在地雷上的地雷。第一个标记超过一半地雷的玩家获胜。用鼠标左键点击一个格子,看看里面是否有地雷。如果有地雷,它就会被揭示,并且你会被标记上你玩家颜色的旗子。然后你将获得下一个回合。如果格子里面没有地雷,你的回合就会结束。每位玩家标记的每颗地雷都得一分。

使用代码

事实上,整个程序可以分为三个层次。

  • 第一个层次是在Field类中实现的。它描述了游戏场地中地雷的位置以及每个格子的当前状态。所以这个类只是作为数据存储结构来设计的。

  • 游戏逻辑和规则在SinglePlayerGameMultiplayerGame类中实现。这些类继承自抽象类GameBase,该类实现了两个游戏版本的通用行为。所有这些类都实现了IGame接口。这使得GUI层可以在不确切知道(在大多数情况下)当前运行的是哪个版本的情况下进行操作。

我使用事件来简化层之间的交互。例如,会触发OnCellChanged事件来通知表示层某个格子的内容已更改,并且需要重新绘制。

  public class SinglePlayerGame: GameBase
  {

    public SinglePlayerGame(byte aWidth, byte aHeight, 
     byte aBombCount): base(aWidth, aHeight, aBombCount)
    {
    }

    public override void ClickCell(byte x, byte y)
    {
      // Open a cell and open all neigbors whenn needed. 
      // This all is implemented in our base class.
      base.ClickCell(x,y);

      // The condition to loose, because it is game version secific.
      if (_field.Bombs[x,y]==Field.ISBOMB) GameOver(Player.None);
      // The condition to win, because it is game version secific.
      if (ClosedCount==_field.BombCount ) GameOver(CurrentPlayer);
    }

    // The SetFlag behavior is different in both versions 
    // that is why it must be implemented here.
    public override void SetFlag(byte x, byte y)
    {
      // When cell is already opened do nothing
      if (_field.CellStates[x,y]==CellState.Open) return;
      // remember cell state before changes are made
      CellState BeforeState = _field.CellStates[x,y];
      // Unmark when already marked
      if (_field.CellStates[x,y]==GetFlagColorOfCurrentPlayer()) 
        _field.CellStates[x,y]=CellState.Closed; 
      // Mark when not marked
      else _field.CellStates[x,y]=GetFlagColorOfCurrentPlayer(); 
      // Inform others that this cell was modified.
      CellChanged(x,y, BeforeState, _field.CellStates[x,y]);
    }
  }
  
  • GamePresentation类负责绘制游戏场地以及与主窗体的交互。所有的用户交互、音效和其他类似的东西都集中在frmMain中。
  • 实际上还有一层(UdpComm类)用于实现网络通信。在这个程序当前版本中,它只在frmStartMultiplayer窗体中用于检测网络是否存在以及执行握手。

关注点

我想和大家分享一些有趣的问题。

  • Pocket PC上的应用程序图标 - 当一个Windows应用程序只有一个大图标(32×32像素)并且需要以小图标视图显示时,它会自动缩放。令我惊讶的是,在我的Pocket PC 2002上情况并非如此,它只显示左上角的16×16像素矩形。因此,我不得不创建32×32和16×16的图标。
  • ImageButton - 如您可能知道,Compact Framework中没有ImageButton。我的最初想法是将格子表示为ImageButtons,并在需要时更改图像。我找到了一篇微软的文章如何创建基于Microsoft .NET Compact Framework的Image Button,并使用了他们对ImageButton的实现。为了提高绘画面板的性能,我切换到了使用Graphics手动绘制。这样它的工作速度要快得多。
  • Compact Framework中的线程 - 为了简化开发,我在Windows应用程序中编写和测试了几乎所有的模块(GUI除外,当然)。然后我将这段代码移植到了移动应用程序中。在大多数情况下,它在没有任何修改的情况下就能工作,但例如,我发现Compact Framework中的Thread没有IsAlive属性,也没有Abort方法。因此,在编程Compact Framework时,请始终考虑它的局限性。
  • 此外,您还可以从源代码中找到许多有用的东西。例如,使用嵌入式资源或异步播放WAV文件。令我惊讶的是,2002年的模拟器可以正常播放系统声音但不能播放我的WAV文件。另一方面,2003年的模拟器两者都可以。
© . All rights reserved.