PacSnake(译文)
By robot-v1.0
本文链接 https://www.kyfws.com/games/pacsnake-zh/
版权声明 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
- 7 分钟阅读 - 3483 个词 阅读量 0PacSnake(译文)
原文地址:https://www.codeproject.com/Articles/10717/PacSnake
原文作者:JasperB
译文由本站 robot-v1.0 翻译
前言
PacSnake is a mix of the classic PacMan game and the classic Snake game.
PacSnake是经典PacMan游戏和经典Snake游戏的结合.
介绍(Introduction)
首先,(First of all,) PacSnake(PacSnake) 现在可以作为Android游戏在(is now available as an Android game in the) Google Play商店(Google Play Store) .它使用与本文所述相同的技术,但具有更多功能,例如平滑的蛇移动,多个级别等.我将很快写一篇新文章来描述蛇的移动以及我遇到的更多Android特定问题.(. It uses the same techniques as described in this article, but has many more features, like smooth snake movement, many levels, etc. I will soon write a new article describing the snake movement and more Android specific issues that I’ve come across.) 点击这里(Click here) .(.)
PacSnake是一款受PacMan和Snake游戏启发的游戏.游戏的目的是使蛇穿过迷宫并吃掉所有食物.当蛇撞到自己的身体时,它就死了.(PacSnake is a game that is inspired by PacMan and the Snake game. The object of the game is to move the snake through the maze and eat all the food. When the snake hits his own body, it dies.) 这款游戏的编写非常有趣,因为它使用了许多不同的技术(稍后将对此进行详细说明).(The game was very interesting to write because it uses a lot of different techniques (which are explained in more detail later).)
-
XML格式(XML):游戏使用XML读取不同级别.它还将XML文件用于外观以及用于存储/读取用户首选项.(: The game uses XML to read the different levels. It also uses XML file for skins and for storing/reading user preferences.)
-
图形,(Graphics,)明显.它使用后缓冲将图形写入屏幕,因此屏幕不会在每次重新绘制时闪烁.(obviously. It uses a backbuffer to write graphics to screen, so the screen doesn’t flicker each time it’s repainted.)
-
面向对象(Object oriented):我尝试在开发游戏时使用面向对象的方法.(: I tried to use an object oriented approach while developing the game.)
-
声音(Sounds):游戏使用声音.(: The game uses sounds.) 游戏使用关卡和皮肤:(The game uses level sets and skins:)
-
水平集(Level sets):一个级别集包含一个或多个级别.您可以创建自己的关卡,将它们放入关卡设置文件中,然后可以播放新关卡.(: A level set consists of one or more levels. You can create you own levels, put them in a level set file and that you can play the new levels.)
-
皮肤(Skins):您还可以创建自己的皮肤并将其放入游戏中.外观是决定游戏外观的一组图形.例如,您可以制作"火"皮或"金属"皮.(: You can also create your own skins and put them in the game. A skin is a collection of graphics that decide how the game looks. You can for example make a ‘fire’ skin or a ‘metal’ skin.)
班级(The Classes)
我将在这里详细解释游戏使用的每个类(对象):(I’ll explain each class (object) that the game uses here in detail:)
蛇(Snake)
的(The) Snake
对象负责移动蛇,检查方向和碰撞并获取蛇图像.(object is responsible for moving the snake, checking for directions and collisions and for getting the snake images.)
的(The) Snake
由矩形数组组成.每个矩形代表蛇的身体部位(头部,身体或尾巴).每个矩形都有一个位置和一个方向.这样,每个身体部位都可能朝不同的方向移动(当蛇转弯时).使用矩形,很容易检测到蛇撞进去并死亡.这是检查冲突的代码:(consists of an array of rectangles. Each rectangle represents a body part of the snake (head, body or tail). Each rectangle has a position and a direction. This way, it’s possible for each body part to move in a different direction (when the snake turns in corners). Using rectangles, it’s easy to detect is the snake bumps into itself and dies. Here’s the piece of code that checks for collisions:)
/// <summary>
/// Check if the head of the snake crashed into a body part
/// </summary>
/// <returns>True if snake bumps into itself, otherwise false</returns>
public bool CheckCollision()
{
for (int i = 1; i < length; i++)
if (body[i].IntersectsWith(body[0]))
{
isDead = true;
return true;
}
return false;
}
代码采用代表蛇头的矩形(数组中的第一个矩形),并检查它是否与其他身体部位重叠.如果是这样,游戏结束!(The code takes the rectangle that represents the snake’s head (which is the first in the array) and checks if it overlaps with any of the other body parts. If so, game over!)
游戏数据(GameData)
这是一个相当简单的类,它跟踪当前级别,记住用户的喜好,例如是否播放声音,以及将设置更新/读取到磁盘上的XML文件.最后一点值得在这里显示:(This is a fairly simple class which keeps track of the current level, remembers the user’s preferences like playing sounds or not, and updating/reading the setting to an XML file on disk. The last point is worth showing here:)
/// <summary>
/// Reads the game variables from the savegame. If there's no savegame
/// we use default values.
/// </summary>
public void ReadSavegame()
{
string filename = path + "\\savegame.xml";
XmlDocument doc = new XmlDocument();
if (File.Exists(filename))
{
doc.Load(filename);
skinFilename = doc.SelectSingleNode("//Skin").InnerText;
}
else
{
skinFilename = path + "\\skins\\ice.xml";
// Create new file savegame.xml
XmlTextWriter writer = new XmlTextWriter(filename, null);
writer.Formatting = Formatting.Indented;
writer.Indentation = 2;
writer.WriteProcessingInstruction("xml",
"version='1.0' encoding='ISO-8859-1'");
writer.WriteStartElement("savegame");
writer.Close();
// Load XML document and create all elements
doc.Load(filename);
XmlNode root = doc.DocumentElement;
XmlElement skin = doc.CreateElement("Skin");
skin.InnerText = path + "\\skins\\ice.xml";
// Add all elements to the root element
root.AppendChild(skin);
// Save file
doc.Save(filename);
}
}
首先,我们检查保存游戏是否存在.首次启动游戏时,不存在保存游戏.在这种情况下,我们创建一个XML文件并存储用户首选项.在这种情况下,我们只有一个设置,但是随着游戏变得更大,将来可能会有更多设置.它使用XML名称空间,当您检查代码时,您会发现它非常简单.(First, we check if a savegame exists. A savegame doesn’t exist when the game is started for the first time. In this case, we create an XML file and store the users preferences. In this case, we only have one setting, but there may come more settings in the future as the game gets bigger. It uses the XML namespace, and when you examine the code, you can see it’s pretty straightforward.)
水平(Level)
的重要组成部分(An important part of the) Level
课正在画水平.这是负责此操作的代码段:(class is drawing the level. Here’s the piece of code responsible for that:)
/// <summary>
/// This method draws the level. It takes each item in the level and
/// draws the correspoding image.
/// </summary>
public Bitmap Draw(int levelWidth, int levelHeight, Skin skin)
{
img = new Bitmap(levelWidth, levelHeight);
g = Graphics.FromImage(img);
g.DrawImage(skin.Background, 0, 0);
// Draw the level
for (int i = 0; i < width; i++)
{
for (int j = 0; j < height; j++)
{
Image image = GetLevelImage(itemsInLevel[i, j], skin);
// No free space
if (image != null)
g.DrawImage(image, mazeOffsetX + i * 20,
mazeOffsetY + j * 20, 20, 20);
Item item = itemsInLevel[i, j];
if (item.IsCandy && !item.IsCandyEaten)
g.DrawImage(skin.Food, item.Rect.X, item.Rect.Y);
}
}
return img;
}
首先,我们绘制一个背景,该背景存储在(First, we draw a background, which is stored in the) Skin
类.级别存储在二维数组中.该数组包括(class. The level is stored in a two-dimensional array. This array consists of) Item
对象.一个(objects. An) item
对象告诉我们它所持有的水平物品(例如不同的墙壁或一块食物).逐行,逐列读取数组,对于每个数组(object tells us which item of the level it holds (like a different wall or a piece of food). The array is read row by row, column by column, and for every) item
绘制相应的图像.您在代码中看到的迷宫偏移量是用于在屏幕中央绘制水平线的情况,以防水平线小于屏幕尺寸.(a corresponding image is drawn. The maze offsets you see in the code are for drawing the level in the center of the screen in case the level is smaller than the screen size.)
LevelSetInfo(LevelSetInfo)
的(The) LevelSetInfo
类保存有关特定级别集的所有信息.一个级别集由存储在XML文件中的不同级别组成.这样,您可以通过将自己的关卡放入XML文件并将其复制到文件中来创建自己的关卡.(class holds all the information about a certain level set. A level set consists of different levels that are stored in an XML file. This way, you can create your own levels by putting them in an XML file and simply copying this file in the)**等级(levels)**目录.(directory.)
水平集(LevelSet)
LevelSet
继承自(inherits from) LevelSetInfo
在这一节课中,我们还添加了关卡.当我们使用(and in this class, we also add the levels. While we use the) LevelSetInfo
用于在屏幕上显示级别设置信息的类(我们不需要知道级别的外观),我们使用(class for displaying the level set information on screen (we don’t need to know how the levels look), we use the) LevelSet
在我们真正想玩游戏时阅读关卡.(for reading the levels when we actually want to play the game.)
LevelSetInfoCollection(LevelSetInfoCollection)
此类仅包含(This class simply holds a collection of) LevelSetInfo
对象.(objects.)
皮肤(Skin)
游戏使用皮肤作为图形.这意味着您可以根据需要创建自己的图形.的(The game uses skins for graphics. This means that you can create your own graphics if you wish. The) Skin
类从加载这些图形(class loads these graphics from the)**皮肤(skin)**目录.这些图形文件的位置存储在XML文件中.该类从XML文件读取位置,并从光盘检索图形.(directory. The location of these graphic files are stored in an XML file. The class reads the location from the XML files and retrieves the graphics from disc.)
皮肤收集(SkinCollection)
拥有在(Holds a collection of skins that are found in the)**皮肤(skins)**目录.(directory.)
WinMM(WinMM)
这是播放声音的辅助类.这是我在网上找到的一门课,有关播放声音的更多详细信息,请访问该课源中提到的网站.(This is a helper class for playing sounds. It is a class I found on the web and for more details about playing the sounds, check the website mentioned in the source of this class.)
板(Board)
Board
是游戏的主要形式.它绘制水平,蛇等.它还使用计时器移动蛇,并响应按键.通过以下方法显示:(is the main form of the game. It draws the level, snake, etc.. It also uses a timer to move the snake and it responds to key presses. This is shown in the following method:)
/// <summary>
/// Handles the key presses. When the game is running it controls the
/// snake. When the game is not running it controls the other keys to
/// start the game, etc...
/// </summary>
private void AKeyDown(object sender, KeyEventArgs e)
{
switch (gameData.GameStatus)
{
// If the game is in progress, we control the snake
case GameStatus.InProgress:
switch (e.KeyData.ToString())
{
case "Left":
snake.DesiredDirection = MoveDirection.Left;
break;
case "Right":
snake.DesiredDirection = MoveDirection.Right;
break;
case "Up":
snake.DesiredDirection = MoveDirection.Up;
break;
case "Down":
snake.DesiredDirection = MoveDirection.Down;
break;
default:
// Don't respond on other key presses
break;
}
break;
// If the snake has died we press a random key to restart
case GameStatus.SnakeDied:
InitializeGame();
break;
// If the level is finished we press a key to start next
case GameStatus.LevelFinished:
// If this wasn't the last level, start next level
if (gameData.CurrentLevel < levelSet.NrOfLevelsInSet)
{
gameData.CurrentLevel++;
level = levelSet[gameData.CurrentLevel - 1];
InitializeGame();
}
else
gameData.GameStatus = GameStatus.WaitingForKey;
break;
// Level is ready to start, let's wait for a key
case GameStatus.WaitingForKey:
gameData.GameStatus = GameStatus.InProgress;
gameTicker.Interval = level.Speed;
gameTicker.Enabled = true;
mnuSkin.Enabled = false;
break;
}
}
FormLevelSet(FormLevelSet)
在开始游戏之前,我们必须选择我们要玩的关卡.这是通过此表格完成的.(Before we start the game, we have to choose which level set we want to play. This is done by this form.)
FormSkins(FormSkins)
一种简单的形式,我们可以选择要在游戏中使用的皮肤.(A simple form where we can choose which skin we want to use in the game.) 请享用!(Enjoy!)
历史(History)
- 17(17)日(th)2005年6月:初始版本(June, 2005: Initial version)
许可
本文以及所有相关的源代码和文件均已获得The Code Project Open License (CPOL)的许可。
XML C# Windows .NET Mobile Android .NET1.1 Visual-Studio VS.NET2003 Dev 新闻 翻译