碰撞检测

在游戏中,你经常需要判断两个物体是否相互撞击。对于简单的游戏来说,通常用边界框碰撞检测来完成。

碰撞框是检查两个对象之间碰撞的标准方法。当两个多边形没有分开时,它们就会发生碰撞。

这里我们有两个没有碰撞的盒子。如你所见,它们的x投影在底部,y投影在左边:

在这里,你可以看到这些盒子沿着y轴相撞,但它们在x轴上是分开的:

这里的盒子在X轴上是相撞的,但在Y轴上是分开的:

当任何一个轴上没有分离时,就会发生碰撞:

这种形式的碰撞检测,我们试图找到一个物体分离的轴,称为分离轴测试。如果没有分离轴,那么物体就会发生碰撞。

//在屏幕上移动的点
class Dot
{public://点的尺寸static const int DOT_WIDTH = 20;static const int DOT_HEIGHT = 20;//点的最大轴速static const int DOT_VEL = 10;//Initializes the variablesDot();//Takes key presses and adjusts the dot's velocityvoid handleEvent( SDL_Event& e );//Moves the dot and checks collisionvoid move( SDL_Rect& wall );//Shows the dot on the screenvoid render();private://The X and Y offsets of the dotint mPosX, mPosY;//The velocity of the dotint mVelX, mVelY;//点的碰撞框SDL_Rect mCollider;
};

这是运动教程中带有一些新功能的点。 move函数接受一个矩形,该矩形是墙的碰撞框,而点具有一个名为mCollider的数据成员来表示碰撞框。

//启动SDL并创建窗口
bool init();//加载媒体
bool loadMedia();//释放媒体并关闭SDL
void close();//碰撞框检测器
bool checkCollision( SDL_Rect a, SDL_Rect b );

我们还声明了一个检查两个框之间碰撞的函数。

Dot::Dot()
{//Initialize the offsetsmPosX = 0;mPosY = 0;//设置碰撞框尺寸mCollider.w = DOT_WIDTH;mCollider.h = DOT_HEIGHT;//Initialize the velocitymVelX = 0;mVelY = 0;
}

在构造函数中,我们应确保设置了碰撞框的尺寸。

void Dot::move( SDL_Rect& wall ){//向左或向右移动点mPosX += mVelX;mCollider.x = mPosX;//如果点相撞或向左或向右走得太远的话if( ( mPosX < 0 ) || ( mPosX + DOT_WIDTH > SCREEN_WIDTH ) || checkCollision( mCollider, wall ) ){//退回mPosX -= mVelX;mCollider.x = mPosX;}//向上或向下移动点mPosY += mVelY;mCollider.y = mPosY;//如果点相撞或向上或向下走得太远。if( ( mPosY < 0 ) || ( mPosY + DOT_HEIGHT > SCREEN_HEIGHT ) || checkCollision( mCollider, wall ) ){//退回mPosY -= mVelY;mCollider.y = mPosY;}
}

这里是新的移动功能,现在检查我们是否撞墙。它的工作原理和以前很像,只是现在如果我们离开屏幕或撞到墙上,它就会让点移动回来。

首先,我们沿着x轴移动点,但我们也必须改变碰撞器的位置。每当我们改变点的位置,碰撞器的位置也要跟着改变。然后我们检查点是否离开了屏幕或撞到了墙上。如果有,我们就沿着x轴把点移动回来。最后,我们再做一次y轴上的运动。

bool checkCollision( SDL_Rect a, SDL_Rect b ){//矩形的边框int leftA, leftB;int rightA, rightB;int topA, topB;int bottomA, bottomB;//计算矩形A的边长leftA = a.x;rightA = a.x + a.w;topA = a.y;bottomA = a.y + a.h;//计算矩形B的边长leftB = b.x;rightB = b.x + b.w;topB = b.y;bottomB = b.y + b.h;//If any of the sides from A are outside of Bif( bottomA <= topB ){return false;}if( topA >= bottomB ){return false;}if( rightA <= leftB ){return false;}if( leftA >= rightB ){return false;}//If none of the sides from A are outside Breturn true;
}

这里是碰撞检测的地方。这段代码计算每个碰撞框的顶部/底部和左/右。

这里也是我们做分离轴测试的地方。首先,我们检查矩形的顶部和底部,看看它们是否沿y轴分开。然后我们检查左/右,看它们是否在x轴上分开。如果有任何分离,那么就没有碰撞,我们返回false。如果我们找不到任何分离,那么就存在碰撞,我们返回true。

注意:SDL确实有一些内置的碰撞检测功能,但是对于本教程来说,我们将自己动手做。 主要是因为了解它们的工作原理很重要,其次是如果可以自己动手,则可以将碰撞检测与SDL渲染,OpenGL,Direct3D,Mantle,Metal或任何其他渲染API结合使用。

            //Main loop flagbool quit = false;//Event handlerSDL_Event e;//The dot that will be moving around on the screenDot dot;//设置墙面SDL_Rect wall;wall.x = 300;wall.y = 40;wall.w = 40;wall.h = 400;

在进入主循环之前,我们先声明点并定义墙的位置和尺寸。

            //While application is runningwhile( !quit ){//Handle events on queuewhile( SDL_PollEvent( &e ) != 0 ){//User requests quitif( e.type == SDL_QUIT ){quit = true;}//Handle input for the dotdot.handleEvent( e );}//移动点并检查碰撞dot.move( wall );//Clear screenSDL_SetRenderDrawColor( gRenderer, 0xFF, 0xFF, 0xFF, 0xFF );SDL_RenderClear( gRenderer );//Render wallSDL_SetRenderDrawColor( gRenderer, 0x00, 0x00, 0x00, 0xFF );        SDL_RenderDrawRect( gRenderer, &wall );//Render dotdot.render();//Update screenSDL_RenderPresent( gRenderer );}

这里是我们的主循环,其中包含点处理事件,移动的同时检查与墙的碰撞,最后将墙和点渲染到屏幕上。

接下来的这两节是供以后参考的。如果你正在阅读本教程,你可能是个初学者,而这些东西太高级了。当你需要使用更高级的碰撞检测时,这更适用于将来。

当你刚开始做一些像俄罗斯方块一样简单的东西时,这种碰撞检测是可以的。对于像物理模拟器这样的东西,事情就复杂多了。

对于像刚体(rigid body)模拟器这样的东西,我们让我们的逻辑在每一帧中都这样做。
1)对场景中的所有物体施加所有的力(重力、风、推进力等)。

2)通过对位置施加加速度和速度来移动物体。

3)检查所有物体的碰撞,并创建一组触点。接触点是一个数据结构,它通常包含碰撞的两个物体的指针,从第一个物体到第二个物体的法向量,以及物体的穿透量。

4)取生成的接触集,解析碰撞。这通常包括再次检查接触点(在一个限度内)并解析它们。

现在如果你勉强学习碰撞检测,这个暂时不在你的考虑范围之内。这需要一整套教程(我目前没有时间做)来解释。不仅如此,它还涉及到矢量数学和物理学,这已经超出了这些教程的范围。以后当你需要有大量碰撞物体的游戏,并且想知道物理引擎的总体结构是如何工作的时候,就记住这一点吧。

另一件事是,我们这里具有的框是AABB或轴对齐的边界框。 这意味着它们的侧面与x和y轴对齐。 如果要旋转框,则仍可以在OBB(定向边界框)上使用分离轴测试。你不是将角投影在x轴和y轴上,而是将每个方框的所有角投影在I轴和J轴上。然后你可以检查这些框是否沿每个轴分开。你可以进一步扩展这一点,对于任何类型的多边形,沿着多边形的每个轴投影每个轴的所有角,看看是否有任何分离形。 所有这些都涉及向量数学,并且如上所述,这超出了本教程的范围。

在 这里下载本教程的媒体和源代码。

原文链接

关注我的公众号:编程之路从0到1

SDL编程入门(27)碰撞检测相关推荐

  1. SDL编程入门(28)每像素碰撞检测

    每像素碰撞检测 一旦你知道如何检查两个矩形之间的碰撞,你可以检查任何两个图像之间的碰撞,因为所有的图像都是由矩形构成的. 在电子游戏中,所有的东西都可以用矩形来做,甚至这个点: 没看到?我们把它放大: ...

  2. 游戏编程入门之碰撞检测

    在进行以下内容前我们需先做好准备,明白都要做什么 (1)编写碰撞函数(此时的函数不是完整的下面会对其修改):    我们首先需要创建两个矩形并且调用IntersetRect函数来检查他们是否碰撞的函数 ...

  3. SDL编程入门(20)触力反馈

    触力反馈 我们知道了如何用SDL使用操纵杆,现在我们可以使用新的触觉API来使控制器震动. //带有触力反馈的游戏控制器1处理程序 SDL_Joystick* gGameController = NU ...

  4. SDL编程入门(19)游戏手柄和操纵杆

    游戏手柄和操纵杆 就像鼠标输入和键盘输入一样,SDL也有能力读取来自操纵杆/游戏手柄/游戏控制器的输入.在本教程中,我们将根据操纵杆的输入使箭头旋转. //模拟手柄死区 const int JOYST ...

  5. SDL编程入门(8)几何图形渲染

    几何图形渲染 除了新的纹理API,SDL还有新的基元渲染调用作为其渲染API的一部分.因此,如果你需要渲染一些基本的形状,而你又不想为它们创建额外的图形,SDL可以为你省力. bool loadMed ...

  6. 【SDL游戏编程入门第一卷】配置SDL环境

    一.前言 这段时间正好使用 SDL,所以打算开一个新的系列,作为经验分享 -- SDL 游戏编程入门. 这也是 AnnihilateSword 在此站的第一个系列,文中可能有许多不足,还请多多包涵,如 ...

  7. Android 4游戏编程入门经典

    <Android 4游戏编程入门经典> 基本信息 原书名:Beginning Android 4 Games evelopment 作者: (美)Mario Zechner Robert ...

  8. Pygame游戏编程入门笔记

    目录 1. Python游戏编程入门 2. 建立开发环境 3. 简单示例 4. 绘制不同形状 5. 事件监听举例 6. 用pygame打印文本 7. 键盘事件 8. 鼠标事件 9. 轮询键盘 10. ...

  9. c#对象集合去重_《C#编程入门》概览

    # [前言] # 01.[C#简介](<C#编程入门>01-C#简介) # 02.[集成开发环境](<C#编程入门> 02-C#集成开发环境) # 03.[初识C# 控制台输入 ...

最新文章

  1. 知方可补不足~SQL中的count命令的一些优化措施(百万以上数据明显)
  2. mysql多实例实现以及主从同步
  3. JDK1.6官方下载
  4. JMeter学习(六)集合点
  5. 前阿里资深运营王殿进:SaaS产品经理所面临的苦恼
  6. 時鐘,天氣預報--js
  7. 2篇CIKM详解阿里妈妈搜索广告CTR模型如何低碳瘦身
  8. 熊猫数据集_熊猫迈向数据科学的第三部分
  9. MetInfo 5.1 自动化getshell工具
  10. [转]一阶自回归模型和二阶自回归模型
  11. Active Directory证书服务
  12. edius裁剪快捷键_EDIUS 快捷键大全 edius常用快捷键大全
  13. SPSS教程——进行卡方检验的相关步骤
  14. 计算机多媒体技术广泛应用于各个领域,计算机多媒体技术的现状及发展前景
  15. CAD计算机辅助设计——文件管理和界面设置
  16. 手机蓝牙连接51单片机自动开门
  17. Linux远程拷贝文件命令 - scp
  18. CryEngine GameLaucher 和Editor
  19. 多目标人工秃鹫优化算法(MATLAB源码分享,智能优化算法) 提出了一种多目标版本的人工秃鹫优化算法(AVOA)
  20. 罗技M590优联和蓝牙连接的问题

热门文章

  1. C# 多线程 Invoke BeginInvoke
  2. 7-1 找第k小的数(反思),a++和++a的区别,运算符优先级,递归分制思想
  3. windows提权常用系统漏洞与对应的补丁编号
  4. vector内存机制和性能分析
  5. 应用示例:图像文字识别
  6. 交通模拟仿真平台指南(含数据说明)
  7. TEB局部轨迹规划代码解读
  8. 判断当前时间段是否在某个时间段内(当前小时是否在当日某个时间段)
  9. jQuery给元素增加属性
  10. 星星机实测,高清打印的口袋打印小精灵