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

PocketDice

starIconstarIconstarIconstarIconemptyStarIcon

4.00/5 (11投票s)

2004 年 5 月 31 日

CPOL

4分钟阅读

viewsIcon

51103

downloadIcon

308

PocketPC 版的骰子游戏 Yacht 的变种。

引言

我喜欢在我的 PDA 上玩一些简单、小巧的游戏,以便在需要时提供几分钟的放松。PocketDice,是骰子游戏 Yacht 的一个变种,在此作为移动开发竞赛的参赛作品,并为 PocketPC 用户提供几分钟的免费消遣。在描述完游戏后,将提供关于持久化高分和显示在线帮助的代码示例。

玩游戏

PocketDice 是骰子游戏 Yacht 的一个变种,其特殊之处在于骰子点数与扑克牌的花色(梅花、红心、方块和黑桃)相对应。在每一轮中,玩家最多可以掷五颗骰子三次。在第二次或第三次掷骰子时,玩家可以选择重新掷任何一颗或所有骰子。点击“掷骰子”按钮会掷“未锁定”的骰子。点击一颗骰子可以切换该骰子是否被锁定。

在掷骰子三次中的任何一次之后,玩家可以通过点击任何可用的得分框来选择得分。一个得分框在一局游戏中只能使用一次。如果是在第三次掷骰子之后,玩家必须选择一个可用的得分框。得分根据下表计算:

得分选项

描述

A

每有一个 A 得一分

2

每有一个 2 得两分

3

每有一个 3 得三分

4

每有一个 4 得四分

5

每有一个 5 得五分

6

每有一个 6 得六分

三条

如果至少有三个骰子点数相同,则得五颗骰子点数之和;否则得 0 分

四条

如果至少有四个骰子点数相同,则得五颗骰子点数之和;否则得 0 分

满堂彩

如果三个骰子点数相同(即三条),另外两个骰子点数相同(即一对),则得 25 分

顺子

如果五颗骰子组成扑克牌中的顺子,则得 40 分;在此变种中,A 可以被视为最小或最大,因此可能的顺子包括 A-2-3-4-5、2-3-4-5-6 和 3-4-5-6-A。

Flush

如果五颗骰子花色相同,则得 40 分;否则得 0 分

机会

得五颗骰子点数之和。

红桃

如果所有五颗骰子都为红色花色(红心或方块),则得五颗骰子点数之和;否则得 0 分

黑桃

如果所有五颗骰子都为黑色花色(梅花或黑桃),则得五颗骰子点数之和;否则得 0 分

五条

如果所有五颗骰子点数都相同,则得 50 分;否则得 0 分

同花顺

如果五颗骰子花色相同并且组成 A-2-3-4-5、2-3-4-5-6 或 3-4-5-6-A 的顺子,则得 80 分;否则得 0 分。

除了上述分数外,如果 A 到 6 的得分总和达到 63 分或更高,还将获得 35 分的奖励。在计分时,A 被视为 1 点。

当所有得分框都被使用后,游戏结束。

代码结构

该项目以 .NET Compact Framework 为目标,包含四个窗体类和几个其他支持类。

窗体和控件类

以下窗体构成了应用程序的用户界面:

frmMain

包含应用程序入口点,并作为游戏进行的表面。

frmHighScores

用于显示已记录高分的对话框。

frmAbout

应用程序关于框;使用反射方法 Assembly.GetName() 来显示版本信息。

frmInputBox

用于向用户请求文本输入的对话框。

在主窗体之外,还有两个自定义控件类:SingleDieScoringBox。每个控件都重写了 OnPaint() 方法以进行自定义显示。

应用程序数据

应用程序的高分通过 Data 类中的函数保存在 XML 文件中。Data 构造函数尝试使用 XmlTextReader 从持久化文件中加载分数;如果文件不存在,则创建一个空白分数数组。

public class Data
{
    const int kMAX_HIGHSCORES = 10;
    const string kDATA_FILE = @"\Program Files\PocketDice\data.xml";

    private HighScoreRecord[] _list;
    
    . . .

    public Data()
    {

        // check if a high scores data file already exists
        // if not, use a blank score array and we'll
        // save it later
        _list = new HighScoreRecord[kMAX_HIGHSCORES];
        int count = -1;
        XmlTextReader xml = null;
        FileStream stream = null;

        try
        {
            stream = new FileStream(kDATA_FILE, FileMode.Open);
            xml = new XmlTextReader(stream);
            xml.MoveToContent();
            
            while (xml.Read())
            {
                switch (xml.Name)
                {
                    case "HighScore": 
                        count++;
                        if (count < kMAX_HIGHSCORES)
                        {
                            _list[count] = new HighScoreRecord(xml);
                        }
                        break;
                }
            }

            count++;
            if (count < kMAX_HIGHSCORES)
            {
                for (int i=count; i<kMAX_HIGHSCORES; i++)
                {
                    _list[i] = new HighScoreRecord();
                }
            }
            
        }
        catch (System.IO.FileNotFoundException)
        {
            // file isn't here; initialize the structure for later saving
            for (int i=0; i<kMAX_HIGHSCORES; i++)
            {
                _list[i] = new HighScoreRecord();
            }
        }

        catch (Exception ex)
        {
            System.Windows.Forms.MessageBox.Show(
                ex.ToString(), "Error Loading High Scores");
            for (int i=0; i<kMAX_HIGHSCORES; i++)
            {
                _list[i] = new HighScoreRecord();
            }
        }

        finally
        {
            if (xml != null) xml.Close();
            if (stream != null) stream.Close();
        }

    }
    
    . . .
    
}

HighScoreRecord 类,也在源文件 Data.cs 中找到,其构造函数接受 XmlTextReader 作为参数。

  public HighScoreRecord(XmlTextReader xml)
  {
    // read attributes given this XmlTextReader
    _score = int.Parse(xml.GetAttribute("score"));
    _name = xml.GetAttribute("name");
    _date = XmlConvert.ToDateTime(xml.GetAttribute("date"), "yyyy-MM-dd");
  }

frmMainLoad 事件处理程序中创建了一个 Data 对象。然后,在其 Closing 事件处理程序中调用其 Save() 方法,使用 XmlTextWriter 持久化分数。

public class Data
{
    . . .
    
    public void Save()
    {

        // before saving, sort the HighScores array
        SortHighScores();

        // now attempt to save;
        XmlTextWriter xml = null;

        try
        {
            xml = new XmlTextWriter(kDATA_FILE, System.Text.Encoding.ASCII);
            xml.WriteStartDocument();

            // write the HighScore list
            xml.WriteStartElement("HighScores");
            for (int i=0; i<_list.Length; i++)
            {
                _list[i].WriteXmlRecord(xml);
            }

            xml.WriteEndElement();  // </HighScores>

            xml.WriteEndDocument();
        }
        catch (Exception ex)
        {
            System.Windows.Forms.MessageBox.Show(ex.ToString());
        }
        finally
        {
            if (xml != null) xml.Close();
        }

    }

}

Save() 方法中调用的 HighScoreRecord 对象的 WriteXmlRecord() 方法负责持久化其高分属性。

public class HighScoreRecord
{
    ...
    public void WriteXmlRecord(XmlTextWriter xml)
    {
        xml.WriteStartElement("HighScore");
        
        xml.WriteStartAttribute("score","");
            xml.WriteString(_score.ToString());
        xml.WriteEndAttribute();

        xml.WriteStartAttribute("name","");
            xml.WriteString(_name);
        xml.WriteEndAttribute();

        xml.WriteStartAttribute("date", "");
            xml.WriteString(_date.ToString("yyyy-MM-dd"));
        xml.WriteEndAttribute();

        xml.WriteEndElement();
    }
    
}

关注点

在考虑如何显示在线帮助时,我决定需要一些格式,并选择了使用 HTML 文件。来自 .NET Compact Framework QuickStart Tutorial 的文章 Launching Applications and Resuming Processes [^][^],对于提供启动进程的手段非常有用。我添加了一个名为 OpenWebPage() 的函数,并将其封装在项目中的 Launcher 类中。这个函数用于打开包含游戏说明的 HTML 文件。

摘要

PocketDice,PocketPC 版的骰子游戏 Yacht 的变种,提供了一种简单的消遣方式,玩一局完整的游戏只需要几分钟。文章中的代码示例演示了如何使用 XmlTextReaderXmlTextWriter 对象将游戏数据持久化到 XML 文件中,并且从 .NET Compact Framework QuickStart Tutorial 借用的代码用于启动进程,提供了一种显示 HTML 文件以获取在线帮助的解决方案。祝您游戏愉快!

© . All rights reserved.