代码改变世界

XNA飞跃的方块--简单的实现

2010-12-23 17:50  WangQiang  阅读(1816)  评论(3编辑  收藏  举报

  最近在博客园开了博客,这也是第一次开IT类博客,之所有选择博客园是觉得比较稳定,而且有很多大牛也在此写博。

  第一次写这类文章,写的不好请大家指出 。好了..不废话了。

------------

  半年前接触XNA,但是学习一直比较紧,一直都在做与学习有关的东西,所以只是了解了解。最近学习上的项目都忙完了,突然觉得比较闲,开始做个小游戏了,游戏比较简单,代码写的也比较浅显,只是想给初学者一个小小教程,顺便加深一下自己的印象(文中提示是我自己觉得初学者容易忘记的,再就是可能写的比较详细)。

  游戏素材:一个方块,若干跳板。

   (block.png)AND (board.png)

  预计效果:可以跳跃的方块,随机生成跳板,方块可以站在跳板上。

  接下来我们来实现吧(部分自动生成代码略过。此文代码在VS2010+XNA4.0下测试成功,其他版本环境需稍加修改。)

  1.首先我们需要定义的内容:

 

1 //2D图形
2   Texture2D blockTexture;
3 Texture2D boardTexture;
4
5 //
6 Vector2 blockPosition;//位置
7 const int blockSpeed = 10;//左右移动速度          
9
9
//跳板
10 List<Vector2> boardsPositions = new List<Vector2>();//跳板集合
11 const float boardSpawnOdds = 0.01f;//跳板产生的几率
12 const int boardSpeed = 3;//跳板移动速度

  (提示:const限定一个变量不允许被改变)

        在上面定义的boardsPositions是用来存取随机生产出来的各个跳板的坐标的集合(额.有点绕口)。

 

        2.再让我们在LoadContent()中把图片加载到blockTexture和boardTexture对象中去。

 

1 blockTexture = Content.Load<Texture2D>("ball");
2 boardTexture = Content.Load<Texture2D>("bat");
3
4 blockPosition = new Vector2((Window.ClientBounds.Width - blockTexture.Width) / 2,
5 Window.ClientBounds.Height - blockTexture.Height);  //居中方块
 (提示:Window.ClientBounds.Height/Width是游戏窗口的高度和宽度)

        3.准备工作已经做好,现在我们把方块和跳板画到游戏去吧!在Draw()键入以下代码。

 

1 spriteBatch.Begin();//准备画画
2  
3 spriteBatch.Draw(blockTexture, blockPosition, Color.White);//画方块
4   foreach (Vector2 blocksPosition in boardsPositions)
5 {
6 spriteBatch.Draw(boardTexture, blocksPosition, Color.White);
7 }//遍历boardsPositions集合,画出各个跳板
8  
9 spriteBatch.End();//结束画画

 

        好了!现在我们运行一下,

 

        4.咦?大家是不是发现方块不能移动哦,这怎么行呢,恩...我们先来实现左右移动吧!在Update中我们写上按键判断,并且改变方块的位置。

 

1 KeyboardState keyBoard = Keyboard.GetState();
2 //这里定义的是电脑键盘状态,
3 //如果考虑到XBOX360需要GamePadState gamePad = GamePad.GetState(PlayerIndex.One);
4  
5 if (keyBoard.IsKeyDown(Keys.Left))//按左
6   {
7 blockPosition.X -= blockSpeed;
8 }
9 if (keyBoard.IsKeyDown(Keys.Right))//按右
10   {
11 blockPosition.X += blockSpeed;
12 }
13
14 blockPosition.X = MathHelper.Clamp(blockPosition.X,
15 0, Window.ClientBounds.Width - blockTexture.Width);
16 //这里的意思是,把方块的X轴坐标限制在游戏屏幕之内

 

        blockSpeed是我们之前已经定义好了的速度,你可以根据需要修改,因为Update()方法是不断重复执行,所以只需累加即可。

 

        5.好了,我们的方块可以随意移动了!真是激动人心,但是我们的主题可不是只有左右移动那么简单,我们还要跳呢!

        在跳跃中,我们要想到如何使方块上下移动,并且能最好实现重力加速度。现在我们分析一下重力加速度,在方块跳跃的过程中,起跳时速度是由快到慢,落下时是由慢到快(还有其他许多情况未考虑,此文只实现简单效果)。自认为数学学的还是很差的,我想大家数学应该比我好的,各位可能已经想到了很多方法来实现了,这里我举出一个简单的算法。

        我们先定义三个全局变量:

 

1 bool jumpState = false;//此变量用来表示方块跳跃的状态  
2
int blockJumpSpeed = 20;//跳跃时加速度
3   int downSpeed = 0;//不在跳跃时下降加速度,在此不做具体解释,后文中将会讲到。

 

        接下来在Update()中键入如下内容:

 

1 if (keyBoard.IsKeyDown(Keys.Up))//按上
2 {
3 jumpState = true;
4 }
5
6 if (jumpState)//跳跃状态为true时
7 {
8 blockJumpSpeed = blockJumpSpeed - 1;
9 blockPosition.Y -= blockJumpSpeed;
10 }
11
12 if (blockPosition.Y > Window.ClientBounds.Height - blockTexture.Height)
13 {
14 blockPosition.Y = Window.ClientBounds.Height - blockTexture.Height;
15 blockJumpSpeed = 20;
16 jumpState = false;
17 downSpeed = 0;
18 }//当方块坠落到最下方时则停住,并且初始化跳跃加速度和非跳跃下降加速度

  (提示:只有JumpState为true时,跳跃整个动作才会执行。同样因为Update()不断执行的原因,只有掉落到最下方才会停止)

 

  看见了吗?我们重点关注第二个if中的内容,blockJumpSpeed是在不断变化的,我们可以知道blockJumpSpeed>0时方块是上升的,由于blockJumpSpeed数值越来越小,所有上升速也越来越慢,当blockJumpSpeed<0方块则会下降,而且速度是越来越快的,所以一个简单的重力加速度就完成了。

 

  现在你可以执行了,方块可以完成完整的动作了,操作方块快乐的跳跃!

 

  6.好了好了,我们别沉浸在欢乐中了,我们的目标还没完成,我们的跳板呢,光是方块跳来跳去,实在有些无趣。

  跳板是需要随机生成的,所以我们实例化一个Random对象:

 

1 Random random = new Random();

 

  然后在Update()中添加:

 

1 if (random.NextDouble() < boardSpawnOdds)
2 {
3 float y = (float)random.NextDouble() * (Window.ClientBounds.Height - boardTexture.Height);
4 boardsPositions.Add(new Vector2(-boardTexture.Width, y));
5 }//随机一个数如果符合则向boardsPositions中添加一个随机位置的方块
6  
7 for (int i = 0; i < boardsPositions.Count; i++)
8 {
9 boardsPositions[i] = new Vector2(boardsPositions[i].X + boardSpeed, boardsPositions[i].Y);
10 if (boardsPositions[i].X > Window.ClientBounds.Width)
11 {
12 boardsPositions.RemoveAt(i);
13 i--;
14 }//当跳板从屏幕移除时清除
15 }//移动boardsPositions集合中每个方块的位置

 

  (提示:当跳板移除屏幕并且不再显示时一定要从集合中清楚,否则会造成占用大量资源)

  这样,跳板就生成出来了,大家也可以适当的做一些修改,来改变跳板的方向和速度。

 

7.我们现在就只剩下最后一个问题了,也是整个游戏中最费脑细胞的问题,那就是如何让我们的方块站到跳板上。此处涉及到碰撞检测,在游戏中方块和每个跳板都是一个矩形图片,我们可以把每一个都转换为矩形来进行碰撞检测。

  我们先定义一个对象和全局变量:

 

Vector2 boardIntersects = Vector2.Zero;//与方块发生碰撞的跳板
bool hit = false;//是否发生碰撞

 

  在Update()中添加定义一个方块的矩形:

 

1 Rectangle blockRectangle = new Rectangle((int)blockPosition.X,
2 (int)blockPosition.Y, blockTexture.Width, blockTexture.Height);

 

  接下来修改前一步骤中的:

修改前的代码(忽略):

 

1 if (random.NextDouble() < boardSpawnOdds)
2 {
3 float y = (float)random.NextDouble() * (Window.ClientBounds.Height - boardTexture.Height);
4 boardsPositions.Add(new Vector2(-boardTexture.Width, y));
5 }//随机一个数如果符合则向boardsPositions中添加一个随机位置的方块
6  
7 for (int i = 0; i < boardsPositions.Count; i++)
8 {
9 boardsPositions[i] = new Vector2(boardsPositions[i].X + boardSpeed, boardsPositions[i].Y);
10 if (boardsPositions[i].X > Window.ClientBounds.Width)
11 {
12 boardsPositions.RemoveAt(i);
13 i--;
14 }//当跳板从屏幕移除时清除
15 }//移动boardsPositions集合中每个方块的位置

 

修改后(黑体部分是新添加的):

 

1 hit = false; //初始化碰撞,重新判断是否碰撞
2   for (int i = 0; i < boardsPositions.Count; i++)
3 {
4 boardsPositions[i] = new Vector2(boardsPositions[i].X + boardSpeed, boardsPositions[i].Y);
5 //移动boardsPositions集合中每个跳板的位置
6  
7 Rectangle boardRectangle = new Rectangle((int)boardsPositions[i].X,
8 (int
)boardsPositions[i].Y, boardTexture.Width, boardTexture.Height);
9 //实例化一个当前遍历到的跳板的矩形
10  
11 if (boardsPositions[i].X > Window.ClientBounds.Width)
12 {
13 boardsPositions.RemoveAt(i);
14 i--;
15 }//当矩形超出屏幕范围则从集合中清除
16  
17 if (blockRectangle.Intersects(boardRectangle))
18 {
19 boardIntersects = boardsPositions[i];
20 hit = true;
21 }
//当前遍历到的跳板与方块发生碰撞时取出跳板到boardsIntersects对象
22   }

 

  注意黑体中的blockRectangle.Intersects(boardRectangle)方法,当blockRectangleboardRectangle两个矩形发生碰撞时,此方法返回true,反之则返回false。


  现在我们没有对发生碰撞后做出任何反映,还需做进一步判断,现在在第6个步骤的代码的前面(就是随机生成跳板的代码前面)添加如下代码:

1 if (hit)//如果发生碰撞
2   {
3 if (keyBoard.IsKeyDown(Keys.Up) &&
4 blockPosition.Y == boardIntersects.Y - blockTexture.Height + 1)
5 {//只有方块落在跳板上之后按方向键“上”才会跳
6   blockJumpSpeed = 20;
7 jumpState = true;
8 }
9 else if (blockJumpSpeed < 0 || blockJumpSpeed == 20)
10 {//当向下落的时候才会掉到跳板上,防止向上跳时碰撞到即到了跳板上
11   blockPosition.Y = boardIntersects.Y - blockTexture.Height + 1;
12 blockPosition.X += boardSpeed;
13 blockJumpSpeed = 20;
14 jumpState = false;
15 }
16 }
17 else//未碰撞时
18   {
19 if (!jumpState)//未跳跃时
20   {
21 if (blockPosition.Y < Window.ClientBounds.Height - blockTexture.Height)
22 {//当方块位置高于地面时,向下加速度掉落
23   downSpeed = downSpeed - 1;
24 blockPosition.Y -= downSpeed;
25 }
26 }
27 }
上面的代码注释已经详尽,当发生碰撞时的内容需要实际操作进行理解。

  你是否还记得downSpeed变量,用来模拟非人为操作重力加速度的,比如当跳板移出屏幕时,方块在上面会自然下来。


  到此简单的一个方块跳跃游戏已经做好了(或许还不能算作游戏 = -),至于关卡之类的需要读者发挥自己的想象力了。最后,可能到此代码还有许多不理想的地方,希望各位大牛指出或加以修改,我会感激不尽。对了,如果你做出了更加好玩的游戏,别忘了发上来和大家分享哦!恩....第一篇,希望大家多多支持哦!

源码下载

转载别忘了注明出处:http://www.cnblogs.com/WangQ/archive/2010/12/23/xnajumpblock.html