XNA系列教程 2D 碰撞教程 1: 矩形检测

 
 
 
 
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.
© 2007 Vincent Zhang. 转载请注明 . 如果对翻译文章有疑问发送邮件至发送邮件至 vinile@163.com
 
 
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值