面向初学者的" XNA示例游戏"(译文)
By robot-v1.0
本文链接 https://www.kyfws.com/games/xna-sample-game-for-beginners-zh/
版权声明 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
- 8 分钟阅读 - 3516 个词 阅读量 0面向初学者的" XNA示例游戏"(译文)
原文地址:https://www.codeproject.com/Articles/1072080/XNA-Sample-Game-for-Beginners
原文作者:Harsha Wansooriya
译文由本站 robot-v1.0 翻译
前言
Sample Game using XNA
使用XNA的示例游戏
介绍(Introduction)
C#.NET/XNA(C#.NET/XNA)是一项不断下降的技术,但基本上支持XBox 360.(is a technology which is descending yet supports basically the XBox 360.) 这个样本游戏(This Sample game)安妮的洗衣(Annie’s Laundry)本文是我几个月前使用XNA开发的,目的只是为了重新了解(in this article was developed by me several month ago using XNA, Just to refresh understanding about)**游戏开发基础(Game Development Fundamentals)**我想为大众提供同样的好处.(and I thought to provide hte same benefits to the multitudes.)
背景(Background)
在本文中,我提供了该游戏的源代码以及该游戏的详细说明(In this article, I’ve provided the source code for the Game and also detailed description of the)**对象移动,碰撞,得分,用户控制以及游戏的开始/结束.(Object Movement, Collision, Scores, User Controls and Start/End of the Game.)**本文提供了有关编码和执行上述目标的详细说明.(The article provides detailed description about the coding and performing the above mentioned objectives.)
" Annie’s Laundry"是使用XNA为单人游戏开发的2D游戏.游戏的目的是让玩家抓住恶劣天气导致的安妮洗衣店掉落的衣服,尽可能多地得分.掉落的衣服有手帕和衬衫.玩家必须面对的问题是猴子便便从绳子上掉下来,以及仇敌抛出的炸弹.因此,在抓衣服时,玩家必须避免Poo和Bombs碰到两个篮子,用户可以同时使用键盘的不同控件来进行游戏.当篮子变得越来越重时,将很难移动它们,并且当任何衣服掉下来而没有被抓住时,老安妮的健康水平就会下降一个百分点.玩家确实需要保持安妮的身体健康,避免大便和炸弹并得分.(The ‘Annie’s Laundry’ is a 2D Game developed using XNA for single player. The objective of the Game is for the player is to score marks as much as he/she could by catching the falling clothes of Annie’s Laundry due to bad weather. The types of Clothes falling are handkerchief and Shirts. The problems that the player has to deal with are Monkey Poo falling from the ropes and Bombs thrown by haters. So, when catching the Clothes, player has to avoid Poo and Bombs hitting the two baskets which user gets to play with using different controls of the Keyboard simultaneously. When Baskets are getting heavier it becomes difficult to move them and also when any of the clothes fall down without being caught the health level of Old Annie goes down by single Point. Player do need to keep Annie’s health at a good rate, avoid Poo and Bombs and score Marks.)
代码说明(Code Explanations)
XNA游戏开始执行(The XNA Game starts execution with)**Program.cs(Program.cs)**其中包括Main方法,并且在该方法内创建了游戏类的对象.(which includes the Main method and within the method an object for the game class is created.)**跑()(Run())**方法用于初始化游戏.(method is used to initilize the game.)
using System;
namespace WindowsGame2
{
#if WINDOWS || XBOX
static class Program
{
static void Main(string[] args)
{
using (AnnieLaundary game = new AnnieLaundary())
{
game.Run();
}
}
}
#endif
}
AnnieLaundary的游戏类扩展了Microsoft.Xna.Framework.Game.必要的资源,例如(The game class which is AnnieLaundary extends Microsoft.Xna.Framework.Game. The necessary resources such as)声音效果,声音效果实例,精灵字体,2D纹理和类类型的Object初始化都在类中提供.(sound effects, sound effect instances, sprite fonts, 2D Textures and Object initialization of class types are there with in the class.)
public class AnnieLaundary : Microsoft.Xna.Framework.Game
{
SoundEffect background_sound;
SoundEffectInstance intro_sound_instance;
SpriteFont font;
Bucket bucketObj;
Rectangle screenRectangle;
Texture2D shirt; // shortened code as for the example
}
LoadContent()方法将游戏根目录的WindowsGame2Content目录中的每个纹理和声音文件加载到游戏类中.这是重要的编码部分,您必须在其中仔细查看每一个(LoadContent() method loads each and every texture and sound files within the WindowsGame2Content Directory of the Game’s root directory into the Game Class. This is an important coding section where you’ve to closely look at each and every)**.wav,.png和.jpeg(.wav,.png and .jpeg)**资源及其名称.(resources and their names precisely.)
protected override void LoadContent()
{
bomb_sound = Content.Load<SoundEffect>("Audio\\Waves\\bomb");
bomb_sound_instance = bomb_sound.CreateInstance();
mainMenu = Content.Load<Texture2D>("mainbkg");
help = Content.Load<Texture2D>("selectamapwithbckgrnd");
shirt = Content.Load<Texture2D>("shirt");
poo = Content.Load<Texture2D>("poo");
Mybombimg = Content.Load<Texture2D>("bomb");
monkey = Content.Load<Texture2D>("monkey");
shirtObj = new Shirt(shirt,screenRectangle);
bombObj = new Bomb(Mybombimg, screenRectangle);
pooObj = new Poo(poo, screenRectangle);
monkeyObj = new Monkey(monkey, screenRectangle, this.Content);
pheObj = new PlayHelpExitBtns
(playNorm, playNeon, helpNorm, helpNeon,
exitNorm, exitNeon, help, mainMenu, screenRectangle, this.Content);
spriteBatch = new SpriteBatch(GraphicsDevice);
font = Content.Load<SpriteFont>("SpriteFont1");
serviet = Content.Load<Texture2D>("serviet"); //shortened code as for example
}
update(GameTime gametime)方法是主类中的一种重要方法,因为它不断更新游戏逻辑.自上次更新调用以来的时间作为参数传递给方法.(update(GameTime gametime) method is an important method with in the main class because it contantly updates the game logic. The time since the last update call is passed as parameters to the method.) 屏幕状态枚举列表包括两个常量,即(The screen state enumeration list includes two constants namely)**controllerDetect(controllerDetect)**和(and)**标题(title)其中用于controllerDetect(among which for the controllerDetect),(,)updateControllerDetectScreen()方法查找(updateControllerDetectScreen() method looks for the)‘输入’(‘Enter’)**按下以将currentScreenState设置为title.这与游戏的"启动画面"有关,在该画面中您必须按" Enter"键才能继续.(key down to set the currentScreenState to title. This relates to the Splash Screen of the game in which you’ve to ‘Enter’ to continue.)
enum screenState
{
controllerDetect,
title
}
screenState currentScreenState;
private void updateControllerDetectScreen()
{
if (Keyboard.GetState().IsKeyDown(Keys.Enter) == true)
currentScreenState = screenState.title;
}
protected override void Update(GameTime gameTime)
{
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
{
this.Exit();
}
switch (currentScreenState)
{
case screenState.controllerDetect:
{
updateControllerDetectScreen();
break;
}
case screenState.title:
{
if (PlayHelpExitBtns.selectedKeyState == "play" && playState == false)
{
StartGame();
playState = true;
intro_sound_instance.Stop();
/* stops the intro sound play when the playe begins */
}
if (PlayHelpExitBtns.selectedKeyState == "play" && !Serviet.gameover)
{
intro_sound_instance.Stop();
/* stops the intro sound play when the playe begins */
background_sound_instance.Play();
/* starts background music */
if (Serviet.level >= 2) /* level static variable is declared in serviet */
{
shirtObj.Updateshirt();
}
if (Serviet.level >= 3)
{
secondbucketObj.UpdateSecondBucket();
}
if (Serviet.level >= 4)
{
pooObj.UpdatePoo();
}
if (Serviet.level >= 5)
{
bombObj.UpdateBomb();
}
servietObj.UpdateServiet();
monkeyObj.UpdateMonkey();
bucketObj.UpdateBucket();
}
else
{
pheObj.update();
if (pheObj.exitGame())
{
this.Exit();
}
}
break;
}
}
/* serviet collision with bucket */
if (servietObj.Collision(bucketObj.GetBounds()))
{
if (clothfall_sound_instance.State == SoundState.Stopped)
{
clothfall_sound_instance.Volume = 0.75f; /* Play sounds */
clothfall_sound_instance.Play();
}
}
/* second bucket comes after level 3 */
if (Serviet.level >= 3)
{
if (servietObj.Collision(secondbucketObj.GetBounds()))
{
if (clothfall_sound_instance.State == SoundState.Stopped)
{
clothfall_sound_instance.Volume = 0.75f /* Play Sounds */
clothfall_sound_instance.Play();
}
}
}
if (shirtObj.Collision(bucketObj.GetBounds()))
{
if (clothfall_sound_instance.State == SoundState.Stopped)
{
clothfall_sound_instance.Volume = 0.75f; /* Play Sounds */
clothfall_sound_instance.Play();
}
}
if (Serviet.level >= 3) // second bucket comes after level 3
{
if (shirtObj.Collision(secondbucketObj.GetBounds()))
{
if (clothfall_sound_instance.State == SoundState.Stopped)
{
clothfall_sound_instance.Volume = 0.75f;
clothfall_sound_instance.Play();
}
}
}
/* second bucket comes after level 3 but poop comes after 4 */
if (Serviet.level >= 4)
{
if (pooObj.Collision(bucketObj.GetBounds())) /* collision with first bucket*/
{
if (poop_sound_instance.State == SoundState.Stopped)
{
poop_sound_instance.Volume = 0.75f;
poop_sound_instance.Play();
}
}
if (pooObj.Collision(secondbucketObj.GetBounds())) /* collision with second */
{
if (poop_sound_instance.State == SoundState.Stopped)
{
poop_sound_instance.Volume = 0.75f;
poop_sound_instance.Play();
}
}
}
if (Serviet.level >= 5) // second bucket comes after level 3 but bomb comes after 5
{
/* checks the collision of first bucket with bomb */
if (bombObj.Collision(bucketObj.GetBounds()))
{
if (bomb_sound_instance.State == SoundState.Stopped)
{
bomb_sound_instance.Volume = 0.75f;
bomb_sound_instance.Play();
crying_sound_instance.Play();
}
}
/* checks the collision of second bucket with bomb */
if (bombObj.Collision(secondbucketObj.GetBounds()))
{
if (bomb_sound_instance.State == SoundState.Stopped)
{
bomb_sound_instance.Volume = 0.50f;
bomb_sound_instance.Play();
crying_sound_instance.Play();
}
}
}
base.Update(gameTime);
}
游戏中的级别在中被声明为静态变量(Levels of the game are declared as static variable in)**塞尔维特(Serviet)**类,并在update()方法中使用它们.(class and they’re used in the update() method.)
/* second bucket comes after level 3 but bomb comes after 5 */
if (Serviet.level >= 5)
{
// collision conditions
}
像每个类中的Collision()方法一样(Collision() method is in each of the Classes like)**服,衬衫,便便和炸弹(Serviet, Shirt, Poo & Bomb)**检查对象之间的碰撞.(which checks for the collision among objects.)
/* checks the collision of second bucket with bomb */
if (bombObj.Collision(secondbucketObj.GetBounds()))
{
// sounds files
}
Draw()方法将所有精灵绘制为精灵.通常,精灵用于将对象渲染到游戏屏幕中.(Draw() method draws all the sprites as spritebatches. Sprites in general are used to render objects into the game screen.) PlayHelpExitBtns类为游戏提供了菜单屏幕,玩家可以在其中选择(PlayHelpExitBtns class provides the Menu screen to the Game, where the player is able to choose either)播放,帮助或退出.(Play, Help or Exit.)
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.Black);
spriteBatch.Begin();
if (currentScreenState == screenState.controllerDetect)
{
spriteBatch.Draw(splashScreen, Vector2.Zero, Color.White);
}
if (PlayHelpExitBtns.selectedKeyState == "play")
{
// if the game overs with the annies low health the condition is passed here
if (Serviet.gameover && Serviet.anniesmiles == 0)
{
spriteBatch.Draw(Gameover, gameoverposition, Color.White);
spriteBatch.Draw(levelimage, leveluppossition, Color.White);
spriteBatch.DrawString
(font, "Score : " + Serviet.final_score,
new Vector2(1050, 20), Color.Chocolate);
crying_sound_instance.Play();
bomb_sound_instance.Stop();
background_sound_instance.Stop();
clothfall_sound_instance.Stop();
poop_sound_instance.Stop();
}
if (Serviet.gameover)
{
// if the game overs with the hitting of a bomb then it is passed here
spriteBatch.Draw(Gameover, gameoverposition, Color.White);
spriteBatch.Draw(levelimage, leveluppossition, Color.White);
spriteBatch.DrawString
(font, "Score : " + Serviet.final_score,
new Vector2(1050, 20), Color.Chocolate);
poop_sound_instance.Stop();
clothfall_sound_instance.Stop();
background_sound_instance.Stop();
levelup_sound_instance.Stop();
}
else
{
spriteBatch.Draw(background, backgrounposition, Color.White);
bucketObj.Draw(spriteBatch);
servietObj.Draw(spriteBatch);
monkeyObj.DrawMonkey(spriteBatch);
DrawText();
spriteBatch.Draw(myTexture, spritePosition, Color.White);
spriteBatch.Draw
(annhealth_icon, new Rectangle
(530 , 15, annhealth_icon.Width, 44),
new Rectangle
(0, 0, annhealth_icon.Width, 44),
Color.White); // health bag icon
if(Serviet.anniesmiles < 7)
{
healthbar_color = Color.Yellow;
}
if (Serviet.anniesmiles < 4)
{
healthbar_color = Color.Red;
}
spriteBatch.Draw(healthbar,
new Rectangle(600, 25,
(int)(healthbar.Width * ((double)Serviet.anniesmiles / 10)),
44), new Rectangle
(0, 45, healthbar.Width, 44), healthbar_color);
// draw red line indicating health
spriteBatch.Draw(healthbar,
new Rectangle(600, 10, healthbar.Width, 44),
new Rectangle(0, 0, healthbar.Width, 44), Color.White);
if (Serviet.level >= 2) // shirt on and after the level 2
{
shirtObj.DrawShirt(spriteBatch);
}
if (Serviet.level >= 3)
{
secondbucketObj.DrawSecondBucket(spriteBatch);
}
if (Serviet.level >= 4)
{
pooObj.DrawPoo(spriteBatch);
}
if (Serviet.level >= 5)
{
bombObj.DrawBomb(spriteBatch);
}
}
if ((Serviet.total >= 100 && Serviet.total <= 120)
|| (Serviet.total >= 200 && Serviet.total <= 220)
|| (Serviet.total >= 300 && Serviet.total <= 320)
|| (Serviet.total >= 400 && Serviet.total <= 420)
|| (Serviet.total >= 500 && Serviet.total <= 520))
{
spriteBatch.Draw(Levelup, leveluppossition, Color.White);
if (Serviet.total == 100
|| Serviet.total == 200
|| Serviet.total == 300
|| Serviet.total == 400
|| Serviet.total == 500)
{
levelup_sound_instance.Play();
}
}
}
else if (currentScreenState == screenState.title)
{
pheObj.draw(spriteBatch);
}
spriteBatch.End();
base.Draw(gameTime);
}
**selectedKeyState(selectedKeyState)**在Draw()方法中调用了静态字符串变量,以从菜单中检查Player的选择.(static string variable is called within the Draw() method to check the selection of the Player from the Menu.)
if (PlayHelpExitBtns.selectedKeyState == "play")
{
// code
}
**Anniesmiles(anniesmiles)**静态int变量(static int variable in)**塞尔维特(Serviet)**初始化为10的class用于计算任何给定点的Annie的健康状况.当衣服掉到地上时,该值减一.(class which is initialized to 10 is used to calculate the health of Annie’s at any given point. This values is reduced by one when clothes hit the ground.) 下图显示了游戏画面.你可以看到(The following figure shows the game play screen. You can see the)**分数,等级与健康(Score, Level & Health)**游乐区中的指示器.(Indicators in the play area.)
游戏结束屏幕显示最终得分.(The Game Over screen is shown with the Final Score.)
从此处下载源代码(Download the Source Code From here) .(.)
许可
本文以及所有相关的源代码和文件均已获得The Code Project Open License (CPOL)的许可。
.NET4 .NET Dev 新闻 翻译