一,原理介绍

这回有点复杂,不过看懂了还是很好理解的。当然,我不敢保证这种算法在任何情况下都会起效果,如果有同学测试时,发现出现错误,请及时联系我。

我们首先来建立一个以圆心为原点的坐标系:

然后要检测碰撞就只有两种情况了。

情况一,矩形全部都在一个象限内,如图:

当然,图中只是举个例子,不一定是只在第二象限,任何一个象限都行,只要是矩形全在该象限。

这种情况比较好解决,首先,我们计算出矩形每个角的坐标,然后用勾股定律依次算出这个角到圆心的距离是否小于或者等于半径。设这个角与圆心横坐标之差为d1,纵坐标之差为d2,半径为r,公式表达如下:

如果有一个角满足要求说明产生碰撞,返回true。

但是有朋友懵了,怎么判断矩形是不是在一个象限内呢?很简单,只要判断这个矩形左上角和右下角是否在同一个象限内就可以了。于是我们得写个函数来实现判断某两个角是否在同一象限。

函数代码如下:

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-coodX>0 && xoB-coodX>0){
10. if((yoA-coodY>0 && yoB-coodY>0) || (yoA-coodY<0 && yoB-coodY<0)){
11. return true;
12. }
13. return false;
14. }else if(xoA-coodX<0 && xoB-coodX<0){
15. if((yoA-coodY>0 && yoB-coodY>0) || (yoA-coodY<0 && yoB-coodY<0)){
16. return true;
17. }
18. return false;
19. }else{
20. return false;
21. }
22. }

这个函数原本是准备写到lufylegend中LMath静态类中的,参数原本是LPoint对象,但是这里可以用json,因为LPoint里的x,y属性可以写到json里,函数也就同样取得出值了。函数参数介绍:[cood创建的坐标系原点坐标, objA第一个点坐标, objB第二个点坐标] 这几个参数均为json对象,格式为:

 {x:点的x坐标, y:点的y坐标}  

函数中的代码还是很好理解的,就是判断一下两个点的x坐标都分别减去原点x坐标,看得出的数正负符号是否相同,然后又用同样的办法算出y轴上的符号是否相同,如果都相同就在同一象限。

有了这个函数,剩下得就好办了,直接代入开头给出的公式进行计算即可。

情况二,矩形跨度两个象限或者两个象限以上

这种情况更好办,我们就可以直接把圆看作一个边长为2r正方形,然后用矩形碰撞算法检测正方形和矩形的碰撞,如下图所示:

矩形碰撞的算法是什么呢?很easy,如图:

如果要横向判断碰撞的话,判断(x1-x2)的绝对值是否小于或者等于w1/2+w2/2,如果是则横向则有碰撞。纵向判断是一样的,判断(y1-y2)的绝对值是否小于或等于h1/2+h2/2即可。

有了这些算法,我们就可以实现情况2了。

二,Javascript版算法&测试代码

先上代码吧:

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 - rectVec[0])*0.5;
12. ry += (rh - rectVec[1])*0.5;
13. rw = rectVec[0];
14. rh = rectVec[1];
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. }

由于是为lufylegend设计的函数,所以参数为 [ rectObj矩形对象(LSprite或者LShape对象), arcObj圆形对象(LSprite或者LShape对象), rectVec矩形规定大小(可不填), arcR圆形半径(可不填)] 当然,或许些朋友不懂这几行代码:

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;

好吧,我告诉你,这里用到的是lufylegend中LSprite和LShape,这两个类有x、y属性,还有获取宽度和高度的getWidth()和getHeight(),这里看不懂没关系,你知道是取高度和宽度还有x,y坐标的就行了。当然你要深究,那就看看lufylegend.js的API文档吧:http://lufylegend.com/lufylegend/api ,以下测试代码也用到了lufylegend.js,据说这个引擎是个不错的引擎,想了解的同学,去官方网站看看吧:http://lufylegend.com/lufylegend/ 或者看看我的文章,大多数是讲解有关lufylegend开发的。

示例代码:

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. }

测试链接:http://www.cnblogs.com/yorhom/articles/hitTestRectArc.html

2D游戏中的碰撞检测:圆形与矩形碰撞检测(Javascrip版)的更多相关文章

  1. 地图四叉树一般用在GIS中,在游戏寻路中2D游戏中一般用2维数组就够了

    地图四叉树一般用在GIS中,在游戏寻路中2D游戏中一般用2维数组就够了 四叉树对于区域查询,效率比较高. 原理图

  2. Unity3D 2D游戏中寻径算法的一些解决思路

    需求 unity3d的3d开发环境中,原生自带了Navigation的组件,可以很便捷快速的实现寻路功能.但是在原生的2d中并没有相同的功能. 现在国内很多手机游戏都有自动寻路的功能,或者游戏中存在一 ...

  3. 2d游戏中的射线与矩形检测碰撞

    cc.exports.LineCollideRect(startLine,endLine,rect)--向量与矩形检测碰撞 --获取矩形的四个顶点位置 local p = {cc.p(rect.x,r ...

  4. 虚幻4:2D游戏中实现二级或多级跳跃

    转自:http://www.52vr.com/article-729-1.html 闲来无事,想做个二级跳跃或者多级跳跃的方法.. 如下所示.即可实现.   第一步:角色蓝图中.设置跳跃事件 第二部: ...

  5. 在2d游戏中常用的向量方式

    function cc.exports.VectorRotateByAngle(vector,angle)--计算向量旋转后的向量,angle:正数逆时针,负输顺时针 angle = angle*ma ...

  6. 2d游戏中求出一个向量的两个垂直向量

    function cc.exports.VerticalVector(vec)--求出两个垂直向量 local result = {} result[1] = cc.p(vec.y/vec.x,-1) ...

  7. 《MFC游戏开发》笔记十 游戏中的碰撞检测进阶:地图类型&障碍物判定

    本系列文章由七十一雾央编写,转载请注明出处. http://blog.csdn.net/u011371356/article/details/9394465 作者:七十一雾央 新浪微博:http:// ...

  8. 2D游戏模型中动态分层的处理 及解决方案 (适用于 webgame 手游等资源控制较严格类型)

    文章若非特别注明转载,皆是原创,转载请注明出处. 本文地址:http://www.cnblogs.com/bobolive/p/3537215.html 2D游戏中模型一般都有换装逻辑,特别是联网游戏 ...

  9. UWP简单示例(三):快速开发2D游戏引擎

    准备 IDE:VisualStudio 2015 Language:VB.NET/C# 图形API:Win2D MSDN教程:UWP游戏开发 游戏开发涉及哪些技术? 游戏开发是一门复杂的艺术,编码方面 ...

随机推荐

  1. Android之SystemUI载入流程和NavigationBar的分析

    Android之SystemUI载入流程和NavigationBar的分析 本篇仅仅分析SystemUI的载入过程和SystemUI的当中的一个模块StatusBar的小模块NavigationBar ...

  2. kettle的日志

    http://blog.sina.com.cn/s/blog_76a8411a01010u2h.html

  3. selenium使用中遇到的问题

    1.Exception in thread "main" org.openqa.selenium.WebDriverException: Cannot find firefox b ...

  4. 002Jsp的内置对象

    1 课程回顾 Jsp基础 1)Jsp的执行过程 tomcat服务器完成:jsp文件->翻译成java文件->编译成class字节码文件-> 构造类对象-> 调用方法 tomca ...

  5. HashSet非常的消耗空间,TreeSet因为有排序功能,因此资源消耗非常的高,我们应该尽量少使用

    注:HashMap底层也是用数组,HashSet底层实际上也是HashMap,HashSet类中有HashMap属性(我们如何在API中查属性).HashSet实际上为(key.null)类型的Has ...

  6. GitHub Permission to <<repository>> denied to <<username>>

    I kept receiving a 403 error saying my usual username couldn’t access the repository with my usual a ...

  7. LoadRunner小技巧集锦

    preftest 性能测试工作室,专注于性能测试技术研究(www.AutomationQA.com) LoadRunner小技巧集锦 1.录制脚本中包含中文,出现乱码怎么办? 把录制选项中的Suppo ...

  8. python3----scrapy(笔记)

    import scrapy import sys # import io # sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='gb ...

  9. UE4打包程序没有声音-需要安装UE4PrereqSetup_x64.exe

    一个UE4工程打包之后,放到一台新机器,最好安装一下UE4自带的Prerequisites,否则可能会出现没有声音的问题 此安装程序位于WindowsNoEditor\Engine\Extras\Re ...

  10. 如何正确设置 Informix GLS 及 CSDK 语言环境

    本文介绍 GLS 相关知识,说明如何正确设置 Informix GLS 语言环境相关变量(DB_LOCALE,CLIENT_LOCALE),保证 Informix 数据库服务器.客户端能正确的支持中文 ...