




已阅读5页,还剩12页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
2D游戏中的碰撞检测:圆形与矩形碰撞检测(Javascript&C+版) 分类: 【游戏算法】【Html5&Javascript】【C/C+】2014-01-13 16:265491人阅读评论(33)收藏举报JavaScriptHtml5C+算法目录(?)+1. 一原理介绍1. 情况一矩形全部都在一个象限内如图2. 情况二矩形跨度两个象限或者两个象限以上2. 二Javascript版算法测试代码3. 三C版这几天放寒假了,时间也多了起来,当然又有时间搞搞程序了。哈哈昨天在开发我的塔防游戏时突然发现人物实际攻击范围比规定的范围小,按理说应该是一样大的,但偏偏不是,我被这个问题搞得糊里糊涂的,一直没想出问题所在。最后询问了一个程序高手我哥哥。他虽然是搞C+的,但听了我代码解释中有检测圆形碰撞时,他立刻就发现了问题,他告诉我,敌人可以看作是方块,而攻击范围是圆的,如果把敌人弄成圆形进行碰撞检测那必然不准,应该检测矩形和圆形碰撞才行。我听了之后恍然大悟,但是lufylegend中没有这个功能,怎么办呢?我第一想法是对lufy说说,让他老人家实现吧。当我点开Google Talk准备发起对话时,突然又想到一来要是lufy老人家去实现,那要等到猴年马月去了,况且lufy前辈琐事缠身,要是我总是给他提意见不帮忙解决,他老人家是不是想打我啊最后我还是决定自己来实现吧。但是我没搞过这方面的,没有经验,所以一开始有点懵,于是就去Google了一下,发现还真有人讲过,于是就点开看了,不知道是我理解能力不好还是文章写得差(估计都是我理解能力不好)我看了半晌没看懂,呜呼,无法可想,我当时就失望了。但是文章下面有段C代码,于是我把它移植到js上来,运行了一下,感觉效果还不错,于是就马上跑到github上把代码上传给lufy了,并做了一个demo,并在Google Talk上提醒了lufy叫他老人家测试,结果lufy拿到代码一测试就发现了bug。我X,不愧是大神啊没有办法,只有另谋出路了。今早起来,哎呀,天气不错啊,成都好久没有这么爽的天气了。只见空气清新,阳光和煦,真是外出骑车的好机会啊!于是我便和家人一块儿跑到外面溜达了一圈。边走边想矩形和圆形碰撞的事。半天想不明白,呜呼,我只好在路上问了问哥哥。哥哥果然是高手,他想了一会儿便说出了重点,给了我启发。于是回到家,我便马上打开电脑,进行了实验,结果还成功了。当然,按照以往我的习惯,这次小小“发明”也当然也要分享给大家啦(以上事情均发生在1月11日和1月12日,所以lufy看到文章开头不要以为走错家门了)上面说到了我的塔防游戏,现在已经完工得差不多了大家可以看看它的一些介绍:/yorhom/p/sanguotd.html ,顺便发几张截图,给大伙提提兴趣。废话写了一大堆,接下来还是来看看矩形和圆形碰撞实现过程吧。一,原理介绍这回有点复杂,不过看懂了还是很好理解的。当然,我不敢保证这种算法在任何情况下都会起效果,如果有同学测试时,发现出现错误,请及时联系我。我们首先来建立一个以圆心为原点的坐标系:然后要检测碰撞就只有两种情况了。情况一,矩形全部都在一个象限内,如图:当然,图中只是举个例子,不一定是只在第二象限,任何一个象限都行,只要是矩形全在该象限。这种情况比较好解决,首先,我们计算出矩形每个角的坐标,然后用勾股定律依次算出这个角到圆心的距离是否小于或者等于半径。设这个角与圆心横坐标之差为d1,纵坐标之差为d2,半径为r,公式表达如下:如果有一个角满足要求说明产生碰撞,返回true。但是有朋友懵了,怎么判断矩形是不是在一个象限内呢?很简单,只要判断这个矩形左上角和右下角是否在同一个象限内就可以了。于是我们得写个函数来实现判断某两个角是否在同一象限。函数代码如下:javascript view plaincopyprint?1. function isSameQuadrant(cood,objA,objB) 2. var coodX = cood.x; 3. var coodY = cood.y; 4. var xoA = objA.x 5. ,yoA = objA.y 6. ,xoB = objB.x 7. ,yoB = objB.y; 8.9. if(xoA-coodX0 & xoB-coodX0) 10. if(yoA-coodY0 & yoB-coodY0) | (yoA-coodY0 & yoB-coodY0) 11. return true; 12. 13. return false; 14. else if(xoA-coodX0 & xoB-coodX0 & yoB-coodY0) | (yoA-coodY0 & yoB-coodY0 & xoB-coodX0)if(yoA-coodY0 & yoB-coodY0) | (yoA-coodY0 & yoB-coodY0)return true;return false;else if(xoA-coodX0 & xoB-coodX0 & yoB-coodY0) | (yoA-coodY0 & yoB-coodY0)return true;return false;elsereturn false;这个函数原本是准备写到lufylegend中LMath静态类中的,参数原本是LPoint对象,但是这里可以用json,因为LPoint里的x,y属性可以写到json里,函数也就同样取得出值了。函数参数介绍:cood创建的坐标系原点坐标, objA第一个点坐标, objB第二个点坐标 这几个参数均为json对象,格式为:javascript view plaincopyprint?1. x:点的x坐标, y:点的y坐标 x:点的x坐标, y:点的y坐标函数中的代码还是很好理解的,就是判断一下两个点的x坐标都分别减去原点x坐标,看得出的数正负符号是否相同,然后又用同样的办法算出y轴上的符号是否相同,如果都相同就在同一象限。有了这个函数,剩下得就好办了,直接代入开头给出的公式进行计算即可。情况二,矩形跨度两个象限或者两个象限以上这种情况更好办,我们就可以直接把圆看作一个边长为2r正方形,然后用矩形碰撞算法检测正方形和矩形的碰撞,如下图所示:矩形碰撞的算法是什么呢?很easy,如图:如果要横向判断碰撞的话,判断(x1-x2)的绝对值是否小于w1/2+w2/2,如果是则横向则有碰撞。纵向判断是一样的,判断(y1-y2)的绝对值是否小于h1/2+h2/2即可。有了这些算法,我们就可以实现情况2了。二,Javascript版算法&测试代码先上代码吧:javascript view plaincopyprint?1. function hitTestRectArc(rectObj,arcObj,rectVec,arcR) 2. var rw = rectObj.getWidth() 3. ,rh = rectObj.getHeight() 4. ,ar = arcObj.getWidth()*0.5 5. ,rx = rectObj.x 6. ,ry = rectObj.y 7. ,ax = arcObj.x 8. ,ay = arcObj.y; 9.10. if(typeof rectVec != UNDEFINED) 11. rx += (rw - rectVec0)*0.5; 12. ry += (rh - rectVec1)*0.5; 13. rw = rectVec0; 14. rh = rectVec1; 15. 16. if(typeof arcR != UNDEFINED) 17. ax += (ar - arcR); 18. ay += (ar - arcR); 19. ar = arcR; 20. 21.22. var rcx = rx+rw*0.5,rcy = ry+rh*0.5; 23. var rltx = rx 24. ,rlty = ry 25. ,rlbx = rx 26. ,rlby = ry+rh 27. ,rrtx = rx+rw 28. ,rrty = ry 29. ,rrbx = rx+rw 30. ,rrby = ry+rh; 31.32. if( 33. isSameQuadrant( 34. x:ax,y:ay, 35. x:rltx,y:rlty, 36. x:rrbx,y:rrby 37. ) 38. ) 39. var dX1 = Math.abs(ax-rltx),dY1 = Math.abs(ay-rlty); 40. var dX2 = Math.abs(ax-rlbx),dY2 = Math.abs(ay-rlby); 41. var dX3 = Math.abs(ax-rrtx),dY3 = Math.abs(ay-rrty); 42. var dX4 = Math.abs(ax-rrbx),dY4 = Math.abs(ay-rrby); 43.44. if( 45. (dX1*dX1) + (dY1*dY1) = (ar*ar) 46. |(dX2*dX2) + (dY2*dY2) = (ar*ar) 47. |(dX3*dX3) + (dY3*dY3) = (ar*ar) 48. |(dX4*dX4) + (dY4*dY4) = (ar*ar) 49. ) 50. return true; 51. 52. return false; 53. else 54. var result = false; 55. var squareX = ax 56. ,squareY = ay 57. ,squareW = ar*2 58. ,squareH = squareW; 59. if( 60. (Math.abs(squareX-rcx) = (squareW+rw)*0.5) 61. &(Math.abs(squareY-rcy) = (squareH+rh)*0.5) 62. ) 63. result = true; 64. 65. return result; 66. 67. function hitTestRectArc(rectObj,arcObj,rectVec,arcR)var rw = rectObj.getWidth(),rh = rectObj.getHeight(),ar = arcObj.getWidth()*0.5,rx = rectObj.x,ry = rectObj.y,ax = arcObj.x,ay = arcObj.y;if(typeof rectVec != UNDEFINED)rx += (rw - rectVec0)*0.5;ry += (rh - rectVec1)*0.5;rw = rectVec0;rh = rectVec1;if(typeof arcR != UNDEFINED)ax += (ar - arcR);ay += (ar - arcR);ar = arcR;var rcx = rx+rw*0.5,rcy = ry+rh*0.5;var rltx = rx,rlty = ry,rlbx = rx,rlby = ry+rh,rrtx = rx+rw,rrty = ry,rrbx = rx+rw,rrby = ry+rh;if(isSameQuadrant(x:ax,y:ay,x:rltx,y:rlty,x:rrbx,y:rrby)var dX1 = Math.abs(ax-rltx),dY1 = Math.abs(ay-rlty);var dX2 = Math.abs(ax-rlbx),dY2 = Math.abs(ay-rlby);var dX3 = Math.abs(ax-rrtx),dY3 = Math.abs(ay-rrty);var dX4 = Math.abs(ax-rrbx),dY4 = Math.abs(ay-rrby);if(dX1*dX1) + (dY1*dY1) = (ar*ar)|(dX2*dX2) + (dY2*dY2) = (ar*ar)|(dX3*dX3) + (dY3*dY3) = (ar*ar)|(dX4*dX4) + (dY4*dY4) = (ar*ar)return true;return false;elsevar result = false;var squareX = ax,squareY = ay,squareW = ar*2,squareH = squareW;if(Math.abs(squareX-rcx) = (squareW+rw)*0.5)&(Math.abs(squareY-rcy) = (squareH+rh)*0.5)result = true;return result;由于是为lufylegend设计的函数,所以参数为rectObj矩形对象(LSprite或者LShape对象), arcObj圆形对象(LSprite或者LShape对象), rectVec矩形规定大小(可不填), arcR圆形半径(可不填) 当然,或许些朋友不懂这几行代码:javascript view plaincopyprint?1. var rw = rectObj.getWidth() 2. ,rh = rectObj.getHeight() 3. ,ar = arcObj.getWidth()*0.5 4. ,rx = rectObj.x 5. ,ry = rectObj.y 6. ,ax = arcObj.x 7. ,ay = arcObj.y; var rw = rectObj.getWidth(),rh = rectObj.getHeight(),ar = arcObj.getWidth()*0.5,rx = rectObj.x,ry = rectObj.y,ax = arcObj.x,ay = arcObj.y;好吧,我告诉你,这里用到的是lufylegend中LSprite和LShape,这两个类有x、y属性,还有获取宽度和高度的getWidth()和getHeight(),这里看不懂没关系,你知道是取高度和宽度还有x,y坐标的就行了。当然你要深究,那就看看lufylegend.js的API文档吧:/lufylegend/api ,以下测试代码也用到了lufylegend.js,据说这个引擎是个不错的引擎,想了解的同学,去官方网站看看吧:/lufylegend/ 或者看看我的文章,大多数是讲解有关lufylegend开发的。示例代码:javascript view plaincopyprint?1. init(50,mylegend,500,250,main); 2.3. function main() 4. LGlobal.setDebug(true); 5.6. var back = new LSprite(); 7. back.graphics.drawRect(5,green,0,0,LStage.width,LStage.height,true,lightblue); 8. addChild(back); 9.10. var cObj = new LSprite(); 11. cObj.x = 200; 12. cObj.y = 120; 13. cObj.graphics.drawArc(0,0,0,50,0,2*Math.PI,true,red); 14. back.addChild(cObj); 15.16. var rObj = new LSprite(); 17. rObj.x = 250; 18. rObj.y = 70; 19. rObj.alpha = 0.8; 20. rObj.graphics.drawRect(0,0,0,100,100,true,green); 21. back.addChild(rObj); 22.23. trace(hitTestRectArc(rObj,cObj); 24.25. back.addEventListener(LMouseEvent.MOUSE_DOWN,function(e) 26. rObj.x = e.offsetX-rObj.getWidth()*0.5; 27. rObj.y = e.offsetY-rObj.getHeight()*0.5; 28. trace(hitTestRectArc(rObj,cObj); 29. ); 30. init(50,mylegend,500,250,main);function main()LGlobal.setDebug(true);var back = new LSprite();back.graphics.drawRect(5,green,0,0,LStage.width,LStage.height,true,lightblue);addChild(back);var cObj = new LSprite();cObj.x = 200;cObj.y = 120;cObj.graphics.drawArc(0,0,0,50,0,2*Math.PI,true,red);back.addChild(cObj);var rObj = new LSprite();rObj.x = 250;rObj.y = 70;rObj.alpha = 0.8;rObj.graphics.drawRect(0,0,0,100,100,true,green);back.addChild(rObj);trace(hitTestRectArc(rObj,cObj);back.addEventListener(LMouseEvent.MOUSE_DOWN,function(e)rObj.x = e.offsetX-rObj.getWidth()*0.5;rObj.y = e.offsetY-rObj.getHeight()*0.5;trace(hitTestRectArc(rObj,cObj););测试链接:/yorhom/articles/hitTestRectArc.html三,C+版C+版我用的是Qt,所以大家运行要在Qt creator里编译运行。HitTestAlg.h里的代码:cpp view plaincopyprint?1. #ifndef HITTESTALG_H 2. #define HITTESTALG_H 3.4. #include 5. #include 6. #include 7.8. class CMath 9. 10.11. public: 12.13. static int pow(int base, int powerOf) 14. 15. return (int):pow(double)base, (double)powerOf); 16. 17.18. static int sqrt(int n) 19. 20. return (int):sqrt(double)n); 21. 22.23. static int abs(int n) 24. 25. n = n = 0 & nRectRight - nArcCenterX = 0 & nRectTop - nArcCenterY = 0 & nRectBottom - nArcCenterY = 0) 77. | (nRectLeft - nArcCenterX = 0 & nRectRight - nArcCenterX = 0 & nRectTop - nArcCenterY = 0 & nRectBottom - nArcCenterY = 0) 78. | (nRectLeft - nArcCenterX = 0 & nRectRight - nArcCenterX = 0 & nRectBottom - nArcCenterY = 0) 79. | (nRectLeft - nArcCenterX = 0 & nRectRight - nArcCenterX = 0 & nRectTop - nArcCenterY = 0 & nRectBottom - nArcCenterY = 0) 80. ) 81. bRes = true; 82. 83. return bRes; 84. 85.86. bool hitTestRect() const 87. 88. QRect rtArc = m_arArc.rect(); 89. bool bRes = false; 90. if(CMath:abs(m_rtRect.center().x() - rtArc.center().x() = CMath:abs(m_rtRect.width() + rtArc.width() / 2) 91. & CMath:abs(m_rtRect.center().y() - rtArc.center().y() = CMath:abs(m_rtRect.height() + rtArc.height() / 2) 92. ) 93. bRes = true; 94. 95. return bRes; 96. 97.98. bool hitTestAngleArc() const 99. 100. bool bRes = false; 101. QPoint ptRectTopLeft = m_rtRect.topLeft(), ptRectTopRight = m_rtRect.topRight() 102. , ptRectBottomLeft = m_rtRect.bottomLeft(), ptRectBottomRight = m_rtRect.bottomRight() 103. , ptArcCenter = m_arArc.center(); 104. int nArcRadius = m_arArc.radius(); 105.106. if(CMath:distance(ptRectTopLeft, ptArcCenter) = nArcRadius 107. | CMath:distance(ptRectTopRight, ptArcCenter) = nArcRadius 108. | CMath:distance(ptRectBottomLeft, ptArcCenter) = nArcRadius 109. | CMath:distance(ptRectBottomRight, ptArcCenter) = nArcRadius 110. ) 111. bRes = true; 112. 113. return bRes; 114. 115.116. public: 117.118. CHitTestAlg(const QRect& rect, const CArc& arc) : m_rtRect(rect), m_arArc(arc) 119. CHitTestAlg() 120.121. bool hitTest() const 122. 123. bool bRes = false; 124. if(locatedSameQuadrant() 125. bRes = hitTestAngleArc(); 126. else 127. bRes = hitTestRect(); 128. 129. return bRes; 130. 131.132. ; 133.134. #endif / HITTESTALG_H #ifndef HITTESTALG_H#define HITTESTALG_H#include #include #include class CMathpublic:static int pow(int base, int powerOf)return (int):pow(double)base, (double)powerOf);static int sqrt(int n)return (int):sqrt(double)n);static int abs(int n)n = n = 0 & nRectRight - nArcCenterX = 0 & nRectTop - nArcCenterY = 0 & nRectBottom - nArcCenterY = 0)| (nRectLeft - nArcCenterX = 0 & nRectRight - nArcCenterX = 0 & nRectTop - nArcCenterY = 0 & nRectBottom - nArcCenterY = 0)| (nRectLeft - nArcCenterX = 0 & nRectRight - nArcCenterX = 0 & nRectBottom - nArcCenterY = 0)| (nRectLeft - nArcCenterX = 0 & nRectRight - nArcCenterX = 0 & nRectTop - nArcCenterY = 0 & nRectBottom - nArcCenterY = 0)bRes = true;return bRes;bool hitTestRect() constQRect rtArc = m_arArc.rect();bool bRes = false;if(CMath:abs(m_rtRect.center().x() - rtArc.center().x() = CMath:abs(m_rtRect.width() + rtArc.width() / 2)& CMath:abs(m_rtRect.center().y() - rtArc.center().y() = CMath:abs(m_rtRect.height() + rtArc.height() / 2)bRes = true;return bRes;bool hitTestAngleArc() constbool bRes = false;QPoint ptRectTopLeft = m_rtRect.topLeft(), ptRectTopRight = m_rtRect.topRight(), ptRectBottomLeft = m_rtRect.bottomLeft(), ptRectBottomRight = m_rtRect.bottomRight(), ptArcCenter = m_arArc.center();int nArcRadius = m_arArc.radius();if(CMath:distance(ptRectTopLeft, ptArcCenter) = nArcRadius| CMath:distance(ptRectTopRight, ptArcCenter) = nArcRadius| CMath:distance(ptRectBottomLeft, ptArcCenter) = nArcRadius| CMath:distance(ptRectBottomRight, ptArcCenter) = nArcRadius)bRes = true;return bRes;public:CHitTestAlg(const QRect& rect, const CArc& arc) : m_rtRect(rect), m_arArc(arc)CHitTestAlg()bool hitTest() constbool bRes = false;if(locatedSameQuadrant()bRes = hitTestAngleArc();elsebRes = hitTestRect();return bRes;#endif / HITTESTALG_Hmainwindow.h里的代码:cpp view plaincopyprint?1. #ifndef MAINWINDOW_H 2. #define MAINWINDOW_H 3.4. #include 5. #include HitTestAlg.h 6.7. class MainWindow : public QWidget 8. 9. Q_OBJECT 10.11. protected: 12.13. QRect m_rtRect; 14. CArc m_arArc; 15. bool m_bHit; 16.17. protected: 18.19. virtual void mouseReleaseEvent(QMouseEvent *mouseEvent); 20. virtual void paintEvent(QPaintEvent *paintEvent); 21.22. public: 23.24. MainWindow(QWidget *parent = 0); 25. MainWindow(); 26.27. ; 28.29. #endif / MAINWINDOW_H #ifndef MAINWINDOW_H#define MAINWINDOW_H#include #include HitTestAlg.hclass MainWindow : public QWidgetQ_OBJECTprotected:QRectm_rtRect;CArcm_arArc;boolm_bHit;protected:virtual void mouseReleaseEvent(QMouseEvent *mouseEvent);virtual void paintEvent(QPaintEvent *paintEvent);public:MainWindow(QWidget *parent = 0);MainWindow();#endif / MAINWINDOW_Hmainwindow.cpp里的代码:cpp view plaincopyprint?1. #include 2. #include 3. #include 4. #include 5. #include mainwindow.h 6.7. MainWindow:MainWindow(QWidget *parent) 8. : QWidget(parent) 9. , m_rtRect(0, 0, 100, 50) 10. , m_arArc(50, 200, 200) 11. , m_bHit(false) 12. 13. QWidget:showMaximized(); 14. 15.16. MainWindow:MainWindow() 17. 18.19. 20.21. void MainWindow:mouseReleaseEvent(QMouseEvent *mouseEve
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 厂房受损补偿协议书
- 员工家属安全协议书
- 商业委托经营协议书
- 地税办理ca协议书
- 员工合作建房协议书
- 商品货款抵债协议书
- 劳务扶贫协作协议书
- 医院进修培训协议书
- 厂院租凭合同协议书
- 合伙电路改造协议书
- 建筑工程总价包干合同
- 2024年高考数学答题技巧与模板 不等式相关解题技巧(基本不等式链、权方和不等式、两类糖水不等式)(解析版)
- 低压电涌保护器(SPD) 第12部分:低压电源系统的电涌保护器选择和使用导则
- 信息技术与人工智能智慧树知到期末考试答案章节答案2024年重庆工业职业技术学院
- 第六章-数据采集技术课件
- 《人像摄影教程》课件
- 复绿施工方案
- 2024年贵州黔东南州能源投资有限公司招聘笔试参考题库含答案解析
- 相邻关系知识讲座
- 毛泽东著作《实践论》
- 人工智能医疗器械注册审查指导原则(2022年第8号)
评论
0/150
提交评论