PocketDice
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 |
应用程序关于框;使用反射方法 |
frmInputBox |
用于向用户请求文本输入的对话框。 |
在主窗体之外,还有两个自定义控件类:SingleDie
和 ScoringBox
。每个控件都重写了 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");
}
在 frmMain 的 Load
事件处理程序中创建了一个 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 的变种,提供了一种简单的消遣方式,玩一局完整的游戏只需要几分钟。文章中的代码示例演示了如何使用 XmlTextReader
和 XmlTextWriter
对象将游戏数据持久化到 XML 文件中,并且从 .NET Compact Framework QuickStart Tutorial 借用的代码用于启动进程,提供了一种显示 HTML 文件以获取在线帮助的解决方案。祝您游戏愉快!