推箱子Pro(译文)
By robot-v1.0
本文链接 https://www.kyfws.com/games/sokoban-pro-zh/
版权声明 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
- 7 分钟阅读 - 3257 个词 阅读量 0推箱子Pro(译文)
原文地址:https://www.codeproject.com/Articles/9149/Sokoban-Pro
原文作者:JasperB
译文由本站 robot-v1.0 翻译
前言
Sokoban Pro is a modern version of the classic Sokoban puzzle game.
推箱子Pro是经典的推箱子益智游戏的现代版本.
介绍(Introduction)
推箱子Pro是经典的推箱子益智游戏的现代版本.游戏规则非常简单,但游戏却充满挑战性和令人上瘾.游戏规则是将所有盒子移到正确的位置.您只能推一个盒子,不能拉.您可以通过按U撤消您的最后一步.(Sokoban Pro is a modern version of the classic Sokoban puzzle game. The game rules are extremely simple, yet the game is very challenging and addictive. The rule of the game is to move all the boxes in the right places. You can only push a box, not pull. You can undo your last moves by pressing U.) 游戏的新版本现已在(A new version of the game is now available on the) 推箱子Pro网站(Sokoban Pro website) .因为所有最重要的内容(例如读/写XML,移动和绘图)都在CodeProject的源代码中,所以我决定在这里保留第一个原始版本.您可以在Sokoban Pro网站上下载该游戏的最新版本.(. Because all the most important stuff (like reading/writing XML, moving and drawing) is in the source code here on CodeProject, I’ve decided to leave the first, original version here. The latest version of the game, you can download at the Sokoban Pro website.) 最新版本(v1.0b)对CodeProject上的版本进行了以下改进:(The latest version (v1.0b) includes the following improvements over the version on CodeProject:)
-
“官方"测试版发布(‘Official’ beta release)
-
新增菜单(Added menus)
-
我发现每个级别的窗口大小都会改变,这很烦人,所以现在它的大小是固定的(I found it irritating that the window size changed with each level, so it has fixed size now)
-
您可以在不同级别之间跳转,但只能跳到之前完成的级别(You can jump between different levels, but only to levels that you’ve finished before)
-
1级撤消功能(1-level undo functionality)
-
启动画面和图标(Splash screen and icons)
-
修复了许多错误(Fixed many bugs)
-
可能还有其他东西(Probably some other stuff, too) 游戏开始时,您可以创建一个新玩家或选择一个现有玩家.由于Sokoban Pro会保存您的进度,因此您也可以选择是否要继续以前的游戏.创建播放器后,您可以选择一个级别集.一个关卡集包含任意多的关卡.推箱子Pro带有原始BoxWorld游戏的前40个关卡.级别集存储在XML文件中,这意味着您可以从Internet上不同的Sokoban网站下载级别集.您也可以创建自己的关卡.将Sokoban Pro放入关卡目录中时,它们会自动识别这些关卡集.(When the game starts, you can create a new player or select an existing player. Since Sokoban Pro saves your progress, you can also choose if you want to continue your previous game. After creating a player, you can choose a level set. A level set contains as many levels as you like. Sokoban Pro comes with the first 40 levels from the original BoxWorld game. Level sets are stored in XML files, which means that you can download level sets from the different Sokoban sites on the Internet. You can also create your own levels. Sokoban Pro will automatically recognize the level sets when you put them in the levels directory.) 您的保存游戏也是XML文件.它会保存上一次玩的游戏级别和上一次玩的游戏级别,因此您可以继续上次玩游戏时退出的级别.它还可以保存您完成的级别和得分(移动和推动的次数).如果您重试一个水平并且您的表现更好,则分数会更新.(Your Save Game is also an XML file. It saves the last played level set and the last played level so you can continue where you left off the previous time you played the game. It also saves the levels that you’ve finished and the scores (number of moves and pushes). If you retry a level and your performance is better, your scores are updated.) 基本上,游戏包含以下类别:(Basically, the game consists of the following classes:)
-
LevelSet
-包含有关级别集的所有信息(作者信息,级别数等).它还将来自级别集XML的级别加载到内存中.(- Contains all the information about a level set (author information, number of levels, etc..). It also loads the levels from the level set XML into memory.) -
Level
-代表关卡集中的关卡.这里发生的最重要的事情是,它跟踪您的所有动作.当玩家移动或推箱子时,它将在一个级别中更新项目.它更新相应的图形.它实现了撤消功能,最后,它在屏幕上绘制了级别.(- Represents a level inside a level set. The most important thing that happens here is that it keeps track of all your moves. It updates the items in a level when the player moves or pushes a box. It updates the corresponding graphics. It implements undo functionality, and lastly, it draws the level on the screen.) -
PlayerData
-跟踪所有玩家信息.基本上,它反映了您的SaveGame.(- Keeps track of all the player information. Basically, it reflects your SaveGame.) -
Board
((()Form
)-主窗体处理所有玩家输入并初始化所有对象.() - The main form handles all the player input and initializes all objects.) -
Players
((()Form
)-可让您创建新的播放器或选择现有的播放器.() - Lets you create a new player or select an existing one.) -
Levels
((()Form
)-让您选择要播放的关卡.() - Lets you select a level set that you want to play.) 该应用程序利用读取和写入XML文件的方式.例如,采用以下方法-(The application makes use of reading and writing XML files. Take, for example, the following method -)SaveLevel()
-在玩家完成关卡后保存玩家数据.(- which saves the player data after the player finished a level.)
public void SaveLevel(Level level)
{
XmlDocument doc = new XmlDocument();
doc.Load(filename);
XmlNode lastFinishedLvl = doc.SelectSingleNode("//lastFinishedLevel");
lastFinishedLvl.InnerText = level.LevelNr.ToString();
XmlNode setName = doc.SelectSingleNode("/savegame/levelSets/" +
"levelSet[@title = \"" + level.LevelSetName + "\"]");
XmlNode nodeLevel = setName.SelectSingleNode("level[@levelNr = " +
level.LevelNr + "]");
if (nodeLevel == null)
{
XmlElement nodeNewLevel = doc.CreateElement("level");
XmlAttribute xa = doc.CreateAttribute("levelNr");
xa.Value = level.LevelNr.ToString();
nodeNewLevel.Attributes.Append(xa);
XmlElement moves = doc.CreateElement("moves");
moves.InnerText = level.Moves.ToString();
XmlElement pushes = doc.CreateElement("pushes");
pushes.InnerText = level.Pushes.ToString();
nodeNewLevel.AppendChild(moves);
nodeNewLevel.AppendChild(pushes);
setName.AppendChild(nodeNewLevel);
}
else
{
XmlElement moves = nodeLevel["moves"];
XmlElement pushes = nodeLevel["pushes"];
int nrOfMoves = int.Parse(moves.InnerText);
int nrOfPushes = int.Parse(pushes.InnerText);
if (level.Pushes < nrOfPushes)
{
pushes.InnerText = level.Pushes.ToString();
moves.InnerText = level.Moves.ToString();
}
else if (level.Pushes == nrOfPushes && level.Moves < nrOfMoves)
moves.InnerText = level.Moves.ToString();
}
doc.Save(filename);
}
这是发生了什么:(Here’s what happens:) 我们利用XPath在XML文件中选择节点.这样,在找到要添加新元素或更新现有元素的正确元素之前,不必逐行读取XML.该行:(We make use of XPath to select nodes in an XML file. This way, we don’t have to read the XML line by line until we find the right element where we want to add a new element or update an existing one. The line:)
XmlNode setName = doc.SelectSingleNode("/savegame/levelSets/" +
"levelSet[@title = \"" + level.LevelSetName + "\"]");
选择我们当前正在播放的关卡的关卡设置节点. (请记住,Sokoban Pro支持多个级别集,因此XML中可能存在多个级别集).然后,该行:(selects the level set node of the level we’re currently playing. (Remember that Sokoban Pro supports multiple level sets, so there may be more than 1 level set in the XML). Then, the line:)
XmlNode nodeLevel = setName.SelectSingleNode("level[@levelNr = "
+ level.LevelNr + "]");
选择我们在当前级别集中播放的级别编号.(selects the level number we’re playing in the current level set.) 如果找不到当前的关卡节点,则意味着我们之前尚未完成关卡,并添加了一个新的关卡节点.如果确实找到了关卡节点,则意味着我们之前玩过关卡,并检查我们当前的成绩是否更好;如果是,请更新分数.(If we don’t find the current level node, it means that we haven’t finished the level before and we add a new level node. If we do find the level node, it means that we’ve played the level before and we check if our current score is better, and if yes, let’s update the score.) 该游戏大量使用读写XML文件的方式,如您所见,使用XPath是一个非常强大的工具.(The game makes heavy use of reading and writing XML files, and as you can see, using XPath is a very powerful tool.) 我想在这里显示的另一件事是如何加载关卡.如前所述,我们将级别存储在XML中.一个关卡由不同的项目组成;墙壁,地板,盒子等.在加载关卡时,我们读取XML中包含关卡数据的行.级别中的每个项目均由ASCII字符表示.读取级别数据时,我们将项目存储在二维数组中.(Another thing I want to show here is how I load the level. As I’ve said, we store the level in the XML. A level consists of different items; a wall, a floor, a box, etc.. When we load a level, we read the lines in the XML that contain the level data. Each item in a level is represented by an ASCII character. When we read the level data, we store the items in a 2-dimensional array.) 当我们想要绘制水平时,我们读取数组,我们可以如下绘制水平:(When we want to draw the level, we read the array and we can draw the level as follows:)
// Draw the level
for (int i = 0; i < width; i++)
{
for (int j = 0; j < height; j++)
{
Image image = GetLevelImage(levelMap[i, j], sokoDirection);
g.DrawImage(image, ITEM_SIZE + i * ITEM_SIZE, ITEM_SIZE
+ j * ITEM_SIZE, ITEM_SIZE, ITEM_SIZE);
// Set Sokoban's position
if (levelMap[i, j] == ItemType.Sokoban
|| levelMap[i, j] == ItemType.SokobanOnGoal)
{
sokoPosX = i;
sokoPosY = j;
}
}
}
我们逐行,逐字符读取数组.根据遇到的项目,我们会得到由(We read the array line by line, character by character. Depending on what item we encounter, we get an image returned by the) GetLevelImage
方法,该方法检查我们拥有的物品并返回相应的图像.最后,给定项目的位置,宽度和高度,我们绘制图像.尺寸存储在(method, which checks what item we have and returns the corresponding image. Lastly, we draw the image, given the position and the width and height of the items. The size is stored in the) ITEM_SIZE
变量.如果我们想将水平画得更小(也许对于分辨率较低的显示器),我们可以减小(variable. If we want to draw the level smaller (maybe for monitors with lower resolutions), we can decrease the value of) ITEM_SIZE
(默认值为30).((default is 30).)
另一个有趣的事情是检查是否允许推箱子.只有在他前面的项目是一个空白空间或后面是空白的盒子时,他才能移动.当他移动时,我们存储了推箱子的新位置,箱子和推箱子留下的空白空间分别位于三个不同的位置(Another interesting thing was checking if Sokoban is allowed to move. He can only move if the item in front of him is an empty space, or a box with an empty space behind it. When he moves, we store the new position of Sokoban and the box and the empty space Sokoban leaves behind in three separate) Item
对象,并且我们使用这些对象仅重绘关卡的这三个项目,而不重绘整个关卡.撤消最后一次推送也是如此.(objects, and we use these objects to only redraw these three items of the level instead of redrawing the entire level. Same goes for undoing the last push.)
请享用!(Enjoy!)
许可
本文以及所有相关的源代码和文件均已获得The Code Project Open License (CPOL)的许可。
XML C# Win2K WinXP Win2003 .NET1.1 Visual-Studio GDI+ VS.NET2003 Dev 新闻 翻译