SDL编程入门(27)碰撞检测
碰撞检测
在游戏中,你经常需要判断两个物体是否相互撞击。对于简单的游戏来说,通常用边界框碰撞检测来完成。
碰撞框是检查两个对象之间碰撞的标准方法。当两个多边形没有分开时,它们就会发生碰撞。
这里我们有两个没有碰撞的盒子。如你所见,它们的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)碰撞检测相关推荐
- SDL编程入门(28)每像素碰撞检测
每像素碰撞检测 一旦你知道如何检查两个矩形之间的碰撞,你可以检查任何两个图像之间的碰撞,因为所有的图像都是由矩形构成的. 在电子游戏中,所有的东西都可以用矩形来做,甚至这个点: 没看到?我们把它放大: ...
- 游戏编程入门之碰撞检测
在进行以下内容前我们需先做好准备,明白都要做什么 (1)编写碰撞函数(此时的函数不是完整的下面会对其修改): 我们首先需要创建两个矩形并且调用IntersetRect函数来检查他们是否碰撞的函数 ...
- SDL编程入门(20)触力反馈
触力反馈 我们知道了如何用SDL使用操纵杆,现在我们可以使用新的触觉API来使控制器震动. //带有触力反馈的游戏控制器1处理程序 SDL_Joystick* gGameController = NU ...
- SDL编程入门(19)游戏手柄和操纵杆
游戏手柄和操纵杆 就像鼠标输入和键盘输入一样,SDL也有能力读取来自操纵杆/游戏手柄/游戏控制器的输入.在本教程中,我们将根据操纵杆的输入使箭头旋转. //模拟手柄死区 const int JOYST ...
- SDL编程入门(8)几何图形渲染
几何图形渲染 除了新的纹理API,SDL还有新的基元渲染调用作为其渲染API的一部分.因此,如果你需要渲染一些基本的形状,而你又不想为它们创建额外的图形,SDL可以为你省力. bool loadMed ...
- 【SDL游戏编程入门第一卷】配置SDL环境
一.前言 这段时间正好使用 SDL,所以打算开一个新的系列,作为经验分享 -- SDL 游戏编程入门. 这也是 AnnihilateSword 在此站的第一个系列,文中可能有许多不足,还请多多包涵,如 ...
- Android 4游戏编程入门经典
<Android 4游戏编程入门经典> 基本信息 原书名:Beginning Android 4 Games evelopment 作者: (美)Mario Zechner Robert ...
- Pygame游戏编程入门笔记
目录 1. Python游戏编程入门 2. 建立开发环境 3. 简单示例 4. 绘制不同形状 5. 事件监听举例 6. 用pygame打印文本 7. 键盘事件 8. 鼠标事件 9. 轮询键盘 10. ...
- c#对象集合去重_《C#编程入门》概览
# [前言] # 01.[C#简介](<C#编程入门>01-C#简介) # 02.[集成开发环境](<C#编程入门> 02-C#集成开发环境) # 03.[初识C# 控制台输入 ...
最新文章
- 知方可补不足~SQL中的count命令的一些优化措施(百万以上数据明显)
- mysql多实例实现以及主从同步
- JDK1.6官方下载
- JMeter学习(六)集合点
- 前阿里资深运营王殿进:SaaS产品经理所面临的苦恼
- 時鐘,天氣預報--js
- 2篇CIKM详解阿里妈妈搜索广告CTR模型如何低碳瘦身
- 熊猫数据集_熊猫迈向数据科学的第三部分
- MetInfo 5.1 自动化getshell工具
- [转]一阶自回归模型和二阶自回归模型
- Active Directory证书服务
- edius裁剪快捷键_EDIUS 快捷键大全 edius常用快捷键大全
- SPSS教程——进行卡方检验的相关步骤
- 计算机多媒体技术广泛应用于各个领域,计算机多媒体技术的现状及发展前景
- CAD计算机辅助设计——文件管理和界面设置
- 手机蓝牙连接51单片机自动开门
- Linux远程拷贝文件命令 - scp
- CryEngine GameLaucher 和Editor
- 多目标人工秃鹫优化算法(MATLAB源码分享,智能优化算法) 提出了一种多目标版本的人工秃鹫优化算法(AVOA)
- 罗技M590优联和蓝牙连接的问题