2D 碰撞教程 1: 矩形检测
本文详细的介绍了在
2D
中实现运动和碰撞检测的方法。
绪论
一个有趣的游戏不一定要特别复杂,躲避障碍游戏就是其中一个,这个游戏包括了游戏角色和从空中落下的物体,而游戏角色必须要躲避开从空中落下的物体。
下图就是游戏角色成功躲避开落体的例子:
而下图则是玩家没有躲避开落体的情况:
当你完成此教程后,你将学会建立这样一个游戏所需要的全部技术。
第一步:建立新工程并加载资源文件
在开始编码之前你需要为你的游戏角色和落下的物体建立纹理贴图。这些纹理可以是任意大小,但应该使用洋红色(
100%
红
, 0%
绿
, and 100%
蓝)等可以使之成为透明色的颜色。纹理贴图应当存储为
.bmp
或
.png
格式
,
而
.gif
或
.jpg
格式会因为图像压缩而丢失颜色。
以下是本例子中所要用到的两个纹理贴图
:
注意
|
洋红色是纹理处理器中所定义的默认关键色,在进行显示的时候洋红色会自动转换为透明色。
|
Next, you need to create a new Windows Game project and add the textures.
接下来,就需要你建立一个
Window Game project
并且添加纹理贴图。
建立一个新的文件
1.
打开
XNA Game Studio Express.
2.
单击
File,
之后单击
New Project
建立一个新工程
.
3.
从模板列表中选择
Windows Game
或
Xbox 360 Game
.
4.
在
Name
中键入游戏名
,
在
Location
中键入工程所存放的地址
.
5.
单击
OK.
你新建的工程中已经有自动生成的代码,这些代码是游戏开始和运行所必须的代码。而现在,你只需要加载资源文件,那么下面的步骤将帮助你。
将资源文件加载到工程当中
1.
首先,你要确定在项目界面的右侧可以看到
Solution Explorer
。如果你无法看到的话,单击
View
按钮,选择
Solution Explorer
的选项就可以了。打开之后你可以看到项目相关的树型结构。
2.
在
Solution Explorer
中
,
右击
Project
图标
,
单击
Add,
之后单击
New Folder
.
将文件夹命名为
Content.
这个文件将是你的美术资源文件的根目录
.
3.
在
Solution Explorer
中单击
Content
文件夹
,
单击
Add
,
然后选择
Existing Item.
在弹出的对话框当中选择你放置美术资源的路径,并且选择你所需要的两个纹理贴图即可。
你的工程结构图应该类似于下面这幅图片:
现在,我们开始编码了。
第二步:初始化和绘图
让我们来看看文件
Game1.cs.
第一件事情就是在代码当中添加绘图代码。也就是说你需要加载并存储游戏角色和下落物体的纹理贴图,在这里你需要首先声明
SpriteBatch
。
1.
在
Solution Explorer
中双击
Game1.cs
文件。
2.
在已经生成的代码中间添加一下代码。
|
// The images to draw Texture2D personTexture; Texture2D blockTexture; // The images will be drawn with this SpriteBatch SpriteBatch spriteBatch; // Person Vector2 personPosition; // Blocks List<Vector2> blockPositions = new List<Vector2>(); |
3.
You must properly initialize these variables
你必须正确的初始化这些变量
.
纹理贴图应当在
LoadGraphicsContent
方法中加载,而剩余的初始化逻辑则应当在
Initialize
方法中
.
添加以下代码:
| ||
protected override void Initialize() { base.Initialize(); // Start the player in the center along the bottom of the screen personPosition.X = (Window.ClientBounds.Width - personTexture.Width) / 2; personPosition.Y = Window.ClientBounds.Height - personTexture.Height; } protected override void LoadGraphicsContent(bool loadAllContent) { if (loadAllContent) { // Load textures blockTexture = content.Load<Texture2D>("Content/Block"); personTexture = content.Load<Texture2D>("Content/Person"); // Create a sprite batch to draw those textures spriteBatch = new SpriteBatch(graphics.GraphicsDevice); } } | ||
注意
| ||
在这个例子当中,图像的位置是从显示区域的左上角进行计算的,正因为如此所以必须考虑到纹理贴图本身的宽度。
|
4.
现在,你已经拥有了纹理贴图和其他精灵数据,想要将他们绘制在屏幕上,就要在
Draw
方法中修改以下代码。
|
protected override void Draw(GameTime gameTime) { graphics.GraphicsDevice.Clear(Color.CornflowerBlue); spriteBatch.Begin(); // Draw person spriteBatch.Draw(personTexture, personPosition, Color.White); // Draw blocks foreach (Vector2 blockPosition in blockPositions) spriteBatch.Draw(blockTexture, blockPosition, Color.White); spriteBatch.End(); base.Draw(gameTime); } |
5.
现在,你就可以编译并运行你的工程了,按下
F5
键或者单击
Start Debugging
。你可以看到你的游戏角色了。
注意
|
如果你建立的是
Xbox360
的游戏的话,也许你会看不到游戏角色。这是因为他可能灰之在电视的安全区域之外。解决的办法就是手动的去修改角色的位置值。具体方法参加
safeBounds
方法。
|
Step 3: 实现物体的运动
因为存储
blocks
的数组是空的,所以无法显示他们。你现在所要做的就是为下来的物体添加动画和逻辑,当然还要添加对游戏角色移动的功能。
1.
简单期间,下落的物体和游戏角色将以一个固定的速率运动,而下落物体的数量则是随机的,为了实现上述功能,你需要在
Game
类的开始添加一下声明。
|
// Person Vector2 personPosition; const int PersonMoveSpeed = 5; // Blocks List<Vector2> blockPositions = new List<Vector2>(); float BlockSpawnOdds = 0.01f; const int BlockFallSpeed = 2; Random random = new Random(); |
2.
他们的值都是随意的,可以根据你的喜好来确定
.
3.
下面我们需要修改
Update
方法:
|
protected override void Update(GameTime gameTime) { // Get input KeyboardState keyboard = Keyboard.GetState(); GamePadState gamePad = GamePad.GetState(PlayerIndex.One); // Allows the game to exit if (gamePad.Buttons.Back == ButtonState.Pressed) this.Exit(); // Move the player left and right with arrow keys or d-pad if (keyboard.IsKeyDown(Keys.Left) || gamePad.DPad.Left == ButtonState.Pressed) { personPosition.X -= PersonMoveSpeed; } if (keyboard.IsKeyDown(Keys.Right) || gamePad.DPad.Right == ButtonState.Pressed) { personPosition.X += PersonMoveSpeed; } // Spawn new falling blocks if (random.NextDouble() < BlockSpawnOdds) { float x = (float)random.NextDouble() * (Window.ClientBounds.Width - blockTexture.Width); blockPositions.Add(new Vector2(x, -blockTexture.Height)); } // Update each block for (int i = 0; i < blockPositions.Count; i++) { // Animate this block falling blockPositions[i] = new Vector2(blockPositions[i].X, blockPositions[i].Y + BlockFallSpeed); } base.Update(gameTime); } |
4.
在继续下面内容之前,你必须要仔细的阅读上面的代码,他们分别实现了以下功能:
a.
收集用户输入
.
b.
根据输入确定游戏角色的位置
.
c.
以一定的时间比率创建新的下落下落
.
d.
为创建的下落物体选择一个随机位置出现
.
e.
实现物体下落的动作
.
现在,你就可以编译并运行你的工程了,按下
F5
键或者单击
Start Debugging
。你可以看到下落的物体并且可以移动自己的游戏角色了。
Step 4: Boundary Collision第四步:边界碰撞检测
现在会发现你的人物可以轻易的移到屏幕以外,也许你没有发现下落的物体从来就没有被删除,而游戏长时间的运行会消耗掉系统的所有内存。
为了解决以上两个问题我们就来添加对游戏角色的运动约束以及删除下落物体。
1.
修改
Update
方法,添加下面黑体的内容:
|
protected override void Update(GameTime gameTime) { // Get input KeyboardState keyboard = Keyboard.GetState(); GamePadState gamePad = GamePad.GetState(PlayerIndex.One); // Allows the game to exit if (gamePad.Buttons.Back == ButtonState.Pressed) this.Exit(); // Move the player left and right with arrow keys or d-pad if (keyboard.IsKeyDown(Keys.Left) || gamePad.DPad.Left == ButtonState.Pressed) { personPosition.X -= PersonMoveSpeed; } if (keyboard.IsKeyDown(Keys.Right) || gamePad.DPad.Right == ButtonState.Pressed) { personPosition.X += PersonMoveSpeed; } // Prevent the person from moving off of the screen personPosition.X = MathHelper.Clamp(personPosition.X, 0, Window.ClientBounds.Width - personTexture.Width); // Spawn new falling blocks if (random.NextDouble() < BlockSpawnOdds) { float x = (float)random.NextDouble() * (Window.ClientBounds.Width - blockTexture.Width); blockPositions.Add(new Vector2(x, -blockTexture.Height)); } // Update each block for (int i = 0; i < blockPositions.Count; i++) { // Animate this block falling blockPositions[i] = new Vector2(blockPositions[i].X, blockPositions[i].Y + BlockFallSpeed); // Remove this block if it have fallen off the screen if (blockPositions[i].Y > Window.ClientBounds.Height) { blockPositions.RemoveAt(i); // When removing a block, the next block will have the same index // as the current block. Decrement i to prevent skipping a block. i--; } } base.Update(gameTime); } |
2.
第一组黑体代码实现了对游戏角色添加边界,使之不能运行到屏幕之外,第二组黑体代码定义了下落物体的的下边界,当期超越边界的时候,则删除他们。
3.
这两组代码依照游戏规则实现了简单的碰撞检测以及响应机制。
4.
现在,你就可以编译并运行你的工程了,按下
F5
键或者单击
Start Debugging
。这时你的游戏角色将不能移除边界,内存泄漏的问题也已经解决。
第五步:矩形碰撞
到现在为止,我们完成了一个游戏的大部分工作。但是这个游戏的关键还没有实现,就是游戏角色如何被击中。作为一个教程,我们简单的用背景颜色的改变来表示是否击中。
1.
在
Game
类中添加以下声明。
|
// For when a collision is detected bool personHit = false; |
2.
在
Draw
方法中添加一下代码
:
|
protected override void Draw(GameTime gameTime) { GraphicsDevice device = graphics.GraphicsDevice; // Change the background to red when the person was hit by a block if (personHit) device.Clear(Color.Red); else device.Clear(Color.CornflowerBlue); |
3.
Now, you need to determine whether any of the falling blocks collide with the player. One simple way to do this is to determine whether the bounding rectangles of their sprites intersect. The XNA Framework provides a simplemethod for just this purpose.
现在你需要知道如何判断下落物体是否击中游戏角色,一个简单的办法就是使用一个包围该物体的矩形来进行判断。
XNA Framework
提供了一个
Rectangle.Intersects
方法用来实现这个功能。
我们在
Update
这段代码中添加以下内容
:
|
// Get the bounding rectangle of the person Rectangle personRectangle = new Rectangle((int)personPosition.X, (int)personPosition.Y, personTexture.Width, personTexture.Height); // Update each block personHit = false; for (int i = 0; i < blockPositions.Count; i++) { // Animate this block falling blockPositions[i] = new Vector2(blockPositions[i].X, blockPositions[i].Y + BlockFallSpeed); // Get the bounding rectangle of this block Rectangle blockRectangle = new Rectangle((int)blockPositions[i].X, (int)blockPositions[i].Y, blockTexture.Width, blockTexture.Height); // Check collision with person if (personRectangle.Intersects(blockRectangle)) personHit = true; // Remove this block if it have fallen off the screen if (blockPositions[i].Y > Window.ClientBounds.Height) blockPositions.RemoveAt(i); } |
This code determines the bounding rectangles for the player character and for each sprite. Each block's bounding rectangle is tested for intersection with the player character's bounding rectangle.
这些代码为游戏角色和下落的物体定义了一个包围矩形,而每一个下落物体的矩形都和游戏角色的矩形进行碰撞检测。
4.
现在,你就可以编译并运行你的工程了,按下
F5
键或者单击
Start Debugging
。
.
恭喜你!
l
你完成了这个教程,下面是
2D
碰撞教程
2
,像素检测。
扩展
Got the urge to tinker with the project a bit? Try these ideas.
你是否还想把这个游戏做的更精彩一些呢?你可以采用一下方法:
·
为躲避开的下落物体添加计数
.
·
随着游戏的进行增加游戏难度
.
·
尝试增加奖励落体
.
© 2007 Microsoft Corporation. All rights reserved.
Send feedback to xna@microsoft.com.
Send feedback to xna@microsoft.com.