PS:自己翻译的,转载请著明出处
简单的样例游戏
在这个样例中,我们通过源代码知道这是一个掉字母的简单的代码。
首先我们需要知道游戏当前是什么状态。所以我创建一个枚举,它可以保存当前的游戏状态。
1 public enum GameState
2 {
3 StateMainMenu,
4 StatePlaying,
5 StateGameOver,
6 StateHelp,
7 }
现在我们需要在某处去保存关于字母的信息,这些字母是在屏幕中下落的。2 {
3 StateMainMenu,
4 StatePlaying,
5 StateGameOver,
6 StateHelp,
7 }
这个类将需要保存字母的位置在屏幕上(x,y坐标)以及它所表示的字母(A到Z)。
我们同样添加一个颜色变量,所以这个文本可以改变颜色去使它看起来更酷。
1 public class FallingCharacter
2 {
3 public float X, Y;
4 Color color;
5 public char character;
6 }
里面的结构成员变量应该被设置:
2 {
3 public float X, Y;
4 Color color;
5 public char character;
6 }
1 public FallingCharacter(float x, float y, Color c,char character)
2 {
3 this.X = x;
4 this.Y = y;
5 this.color = c;
6 this.character = character;
7 }
现在我们需要绘制字母在屏幕上。我们将使用XNAFont类去绘制字母到屏幕上。
2 {
3 this.X = x;
4 this.Y = y;
5 this.color = c;
6 this.character = character;
7 }
1 public void Render(XNAFont f)
2 {
3 f.OutputText(character.ToString(), (int)X, (int)Y, color);
4 }
现在为了这个游戏去工作,我们需要创建某些变量去保存当前的游戏状态。
2 {
3 f.OutputText(character.ToString(), (int)X, (int)Y, color);
4 }
1 GameState currentState = GameState.StateMainMenu; //游戏的当前状态
2 XNAFont textWriter; //文本绘制器
3 string WorkingDirectory; //当前调试目的的目录
4 KeyboardState kbState; //保存键盘的输入状态
5 Keys[] pressedKeys; //当前压下键盘上的键的数组
6 Queue<FallingCharacter> Letters = new Queue<FallingCharacter>(); //下落字母的表单
7 Random rand = new Random();//产生随机数
8 float nextLetterTime = 0.6f; //下一个字母多久后开始
9 int NextSpeedup = 20; //每回答正确20个速度增加20
10 int iSpeed = 2; //字母的下落速度
11 int Score=0; //当前玩家的分数
我们将研究如何使用这些变量。2 XNAFont textWriter; //文本绘制器
3 string WorkingDirectory; //当前调试目的的目录
4 KeyboardState kbState; //保存键盘的输入状态
5 Keys[] pressedKeys; //当前压下键盘上的键的数组
6 Queue<FallingCharacter> Letters = new Queue<FallingCharacter>(); //下落字母的表单
7 Random rand = new Random();//产生随机数
8 float nextLetterTime = 0.6f; //下一个字母多久后开始
9 int NextSpeedup = 20; //每回答正确20个速度增加20
10 int iSpeed = 2; //字母的下落速度
11 int Score=0; //当前玩家的分数
我已经改变了类的结构,这个结构是通过样本的向导产生的。在这种情况下,这样我可以传入命令行参数,以防它们需要:
这同样是一个好地方去获得当前的目录。
1 public Game1(string[] args)
2 {
3 WorkingDirectory = System.IO.Directory.GetCurrentDirectory();
4 InitializeComponent();
5 }
不要忘记去执行释放对象的操作。
2 {
3 WorkingDirectory = System.IO.Directory.GetCurrentDirectory();
4 InitializeComponent();
5 }
1 void WindowsGame_Exiting(object sender, GameEventArgs e)
2 {
3 textWriter.Dispose();
4 }
当游戏开始,让我们设置屏幕为800*600象素
2 {
3 textWriter.Dispose();
4 }
1 void WindowsGame_Starting(object sender, GameEventArgs e)
2 {
3 graphics.BackBufferWidth = 800;
4 graphics.BackBufferHeight = 600;
5 graphics.ApplyChanges();
6 }
创建一个文本渲染,这样我们可以显示字母在屏幕上,以及玩家的分数。
2 {
3 graphics.BackBufferWidth = 800;
4 graphics.BackBufferHeight = 600;
5 graphics.ApplyChanges();
6 }
1 textWriter = XNAFont.LoadFont(this.graphics.GraphicsDevice,WorkingDirectory + "\\Textures\\Lucidia_Console_40.dds.xml", WorkingDirectory + "\\Textures\\Lucidia_Console_40.dds");
让我们继续,并且得到当前的键盘状态。
1 kbState = Keyboard.GetState();
下一步是更新功能。我们将需要检查当前的键盘的状态,响应键盘的压下和移动下落的字母。
1 protected override void Update()
2 {
3 // The time since Update was called last
4 float elapsed = (float)ElapsedTime.TotalSeconds;
5 }
让我们得到键盘的状态。这个Keyboard类是一个XNA类。这个类有一个公开的属性功能GetState(),它返回当前的键盘状态。我们可以在这里检查错误,然而这是留给breivity.2 {
3 // The time since Update was called last
4 float elapsed = (float)ElapsedTime.TotalSeconds;
5 }
GetPressedKeys()返回一个Keys的数组(一个键盘键的枚举)
1 Keys[] newKeys = (Keys[])kbState.GetPressedKeys();
让我检查键,看看是否是刚压下的。这样可以通过用之前压下的键和刚接收到压下的键相比较得出。如果新键与旧键不一样,则新压下的键将触发一个事件。
1 if (pressedKeys != null)
2 {
3 foreach (Keys k in newKeys)
4 {
5 bool bFound = false;
6 foreach (Keys k2 in pressedKeys)
7 {
8 if (k == k2)
9 {
10 bFound = true;
11 break;
12 }
13 }
14 if (!bFound)
15 {
16 OnKeyPressed(k); //handle this key press
17 }
18 }
19 }
现在,让我们保存这个被压下的键,这样我们可以拿它与下一时间压下的结果相比较,看看是否有新键被压下。
2 {
3 foreach (Keys k in newKeys)
4 {
5 bool bFound = false;
6 foreach (Keys k2 in pressedKeys)
7 {
8 if (k == k2)
9 {
10 bFound = true;
11 break;
12 }
13 }
14 if (!bFound)
15 {
16 OnKeyPressed(k); //handle this key press
17 }
18 }
19 }
1 pressedKeys = newKeys;
经管游戏已经开始了,让我们更新下落字母的位置。
1 if (currentState == GameState.StatePlaying)
2 {
3 foreach (FallingCharacter fc in Letters)
4 {
更新字母的Y坐标。这个数一直增加直到Y被计算从窗口的顶部到窗口的底部。
2 {
3 foreach (FallingCharacter fc in Letters)
4 {
1 fc.Y += (elapsed * (float)(iSpeed * 40));
如果这个字母已经到了屏幕的底部,这个游戏就结束了。
1 if (fc.Y + 50 > graphics.BackBufferHeight)
2 {
3 currentState = GameState.StateGameOver;
4 Letters.Clear();
5 break;
6 }
虽然游戏已经开始了,经过一小段时间,我们需要抛出一个新的字母来从屏幕上下落。
2 {
3 currentState = GameState.StateGameOver;
4 Letters.Clear();
5 break;
6 }
1 nextLetterTime -= elapsed;
2 if (nextLetterTime <= 0 && currentState != GameState.StateGameOver)
让我们设置下一个字母出现的时间。这是基于当前游戏的速度,通过一组数字去产生一些很好的效果。
2 if (nextLetterTime <= 0 && currentState != GameState.StateGameOver)
1 nextLetterTime = 0.75f - (iSpeed * .03f);
让我们设置新的字母沿着屏幕的宽度在一个随机的地方,减去一个fudge数,这样字母就不能跑到屏幕的右侧去了。字母同样应该一开始在屏幕上是可见的。
让我们继续并且使文本是亮绿色,给它一个随机的字母。
1 Letters.Enqueue(new FallingCharacter(rand.Next(graphics.BackBufferWidth - 30), -30, Color.LightGreen, (char)((int)'A' + rand.Next(25))));
2 }
3 }
4 // Let the GameComponents update
5 UpdateComponents();
6 }
绘制这个游戏是相当的简单和迅速的。
2 }
3 }
4 // Let the GameComponents update
5 UpdateComponents();
6 }
1 protected override void Draw()
2 {
3 // Make sure we have a valid device
4 if (!graphics.EnsureDevice())
5 return;
6 graphics.GraphicsDevice.Clear(Color.CornflowerBlue);
7 graphics.GraphicsDevice.BeginScene();
8 switch (currentState)
9 {
在主菜单上让我们显示某些文本给用户,让他们知道如何开始游戏。
2 {
3 // Make sure we have a valid device
4 if (!graphics.EnsureDevice())
5 return;
6 graphics.GraphicsDevice.Clear(Color.CornflowerBlue);
7 graphics.GraphicsDevice.BeginScene();
8 switch (currentState)
9 {
1 case GameState.StateMainMenu:
2 {
3 textWriter.OutputText("Press Enter to begin", graphics.BackBufferWidth / 4, graphics.BackBufferHeight / 2, Color.White);
4 }
5 break;
当游戏开始时,分数和字母必须被绘制。
2 {
3 textWriter.OutputText("Press Enter to begin", graphics.BackBufferWidth / 4, graphics.BackBufferHeight / 2, Color.White);
4 }
5 break;
1 case GameState.StatePlaying:
2 {
3 textWriter.OutputText("Score: " + Score.ToString(), 10, 10, Color.White);
4 foreach (FallingCharacter fc in Letters)
5 {
6 fc.Render(textWriter);
7 }
8 }
9 break;
如果游戏结束,让我们显示"Game Over"画面给用户。
2 {
3 textWriter.OutputText("Score: " + Score.ToString(), 10, 10, Color.White);
4 foreach (FallingCharacter fc in Letters)
5 {
6 fc.Render(textWriter);
7 }
8 }
9 break;
1 case GameState.StateGameOver:
2 {
3 textWriter.OutputText("Score: " + Score.ToString(), 10, 10, Color.White);
4 textWriter.OutputText("Game Over", graphics.BackBufferWidth / 3, graphics.BackBufferHeight / 2,Color.LightBlue);
5 textWriter.OutputText("Press Return to Continue", graphics.BackBufferWidth / 6, graphics.BackBufferHeight / 2 + 50, Color.LightBlue);
6 }
7 break;
现在让XNA创造奇迹吧!
2 {
3 textWriter.OutputText("Score: " + Score.ToString(), 10, 10, Color.White);
4 textWriter.OutputText("Game Over", graphics.BackBufferWidth / 3, graphics.BackBufferHeight / 2,Color.LightBlue);
5 textWriter.OutputText("Press Return to Continue", graphics.BackBufferWidth / 6, graphics.BackBufferHeight / 2 + 50, Color.LightBlue);
6 }
7 break;
1 // Let the GameComponents draw
2 DrawComponents();
3 graphics.GraphicsDevice.EndScene();
4 graphics.GraphicsDevice.Present();
让我们看下键压下的事件
2 DrawComponents();
3 graphics.GraphicsDevice.EndScene();
4 graphics.GraphicsDevice.Present();
1 public void OnKeyPressed(Keys k)
如果用户在主要的菜单或者在游戏结束画面时,让我们提示他们去压下Enter键当他们想要开始玩。
1 if ((currentState == GameState.StateMainMenu ||currentState == GameState.StateGameOver)&& k == Keys.Enter)
2 {
3 //Reset the state of the game
4 currentState = GameState.StatePlaying;
5 nextLetterTime = 0.0f;
6 NextSpeedup = 20;
7 iSpeed = 1;
8 Score = 0;
9 }
如果玩家当前正在玩这个游戏,让我检查去看看压下的键是否与屏幕上最低的字母相同。如果它是,然后我们可以删除这个字母并且增加玩家的分数:
2 {
3 //Reset the state of the game
4 currentState = GameState.StatePlaying;
5 nextLetterTime = 0.0f;
6 NextSpeedup = 20;
7 iSpeed = 1;
8 Score = 0;
9 }
1 else if (currentState == GameState.StatePlaying)
2 {
3 string sName = Enum.GetName(typeof(Keys),k);
4 if (Letters.Count > 0 &&String.Compare(Letters.Peek().character.ToString(), sName) == 0)
5 {
6 Score += 100;
7 Letters.Dequeue();
8 NextSpeedup--;
9 if (NextSpeedup <= 0)
10 {
11 iSpeed++;
12 NextSpeedup = 20;
13 }
14 }
15 }
最后如果用户压下escape退出游戏,不管屏幕上有什么。
2 {
3 string sName = Enum.GetName(typeof(Keys),k);
4 if (Letters.Count > 0 &&String.Compare(Letters.Peek().character.ToString(), sName) == 0)
5 {
6 Score += 100;
7 Letters.Dequeue();
8 NextSpeedup--;
9 if (NextSpeedup <= 0)
10 {
11 iSpeed++;
12 NextSpeedup = 20;
13 }
14 }
15 }
1 if (k == Keys.Escape)
2 {
3 this.Exit();
4 }
2 {
3 this.Exit();
4 }
源代码:http://www.ziggyware.com/readarticle.php?article_id=49
(完)