2D游戏中的碰撞检测
更新时间:2023-04-20 13:11:01 阅读量: 实用文档 文档下载
2D游戏中的碰撞检测:圆形与矩形碰撞检测(Javascript&C++版)
分类:【游戏算法】【Html5&Javascript】【C/C++】2014-01-13 16:265491人阅读评论(33)收藏举报JavaScriptHtml5C++算法
目录(?)[+]
这几天放寒假了,时间也多了起来,当然又有时间搞搞程序了。哈哈~
昨天在开发我的塔防游戏时突然发现人物实际攻击范围比规定的范围小,按理说应该是一样大的,但偏偏不是,我被这个问题搞得糊里糊涂的,一直没想出问题所在。最后询问了一个程序高手——我哥哥。他虽然是搞C++的,但听了我代码解释中有检测圆形碰撞时,他立刻就发现了问题,他告诉我,敌人可以看作是方块,而攻击范围是圆的,如果把敌人弄成圆形进行碰撞检测那必然不准,应该检测矩形和圆形碰撞才行。我听了之后恍然大悟,但是lufylegend中没有这个功能,怎么办呢?我第一想法是对lufy说说,让他老人家实现吧。当我点开Google Talk准备发起对话时,突然又想到一来要是lufy老人家去实现,那要等到猴年马月去了,况且lufy前辈琐事缠身,要是我总是给他提意见不帮忙解决,他老人家是不是想打我啊……最后我还是决定自己来实现吧。但是我没搞过这方面的,没有经验,所以一开始有点懵,于是就去Google了一下,发现还真有人讲过,于是就点开看了,不知道是我理解能力不好还是文章写得差(估计都是我理解能力不好……)我看了半晌没看懂,呜呼,无法可想,我当时就失望了。但是文章下面有段C代码,于是我把它移植到js上来,运行了一下,感觉效果还不错,于是就马上跑到github上把代码上传给lufy了,并做了一个demo,并在Google Talk上提醒了lufy叫他老人家测试,结果lufy拿到代码一测试就发现了bug。我X,不愧是大神啊……没有办法,只有另谋出路了。
今早起来,哎呀,天气不错啊,成都好久没有这么爽的天气了。只见空气清新,阳光和煦,真是外出骑车的好机会啊!于是我便和家人一块儿跑到外面溜达了一圈。边走边想矩形和圆形碰撞的事。半天想不明白,呜呼,我只好在路上问了问哥哥。哥哥果然是高手,他想了一会儿便说出了重点,给了我启发。于是回到家,我便马上打开电脑,进行了实验,结果还成功了。当然,按照以往我的习惯,这次小小“发明”也当然也要分享给大家啦~
(以上事情均发生在1月11日和1月12日,所以lufy看到文章开头不要以为走错家门了……)
上面说到了我的塔防游戏,现在已经完工得差不多了~大家可以看看它的一些介绍:27b9bfedc1c708a1294a441f/yorhom/p/sanguotd,顺便发几张截图,给大伙提提兴趣。
废话写了一大堆,接下来还是来看看矩形和圆形碰撞实现过程吧。
一,原理介绍
这回有点复杂,不过看懂了还是很好理解的。当然,我不敢保证这种算法在任何情况下都会起效果,如果有同学测试时,发现出现错误,请及时联系我。
我们首先来建立一个以圆心为原点的坐标系:
然后要检测碰撞就只有两种情况了。
情况一,矩形全部都在一个象限内,如图:
当然,图中只是举个例子,不一定是只在第二象限,任何一个象限都行,只要是矩形全在该象限。
这种情况比较好解决,首先,我们计算出矩形每个角的坐标,然后用勾股定律依次算出这个角到圆心的距离是否小于或者等于半径。设这个角与圆心横坐标之差为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-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 对象,格式为:
[javascript]view plaincopyprint?
1.{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 - 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圆形半径(可不填)] 当然,或许些朋友不懂这几行代码:
[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;
好吧,我告诉你,这里用到的是lufylegend中LSprite和LShape,这两个类有x、y属性,还有获取宽度和高度的getWidth()和getHeight(),这里看不懂没关系,你知道是取高度和宽度还有x,y坐标的就行了。当然你要深究,那就看看lufylegend.js的API文档吧:
27b9bfedc1c708a1294a441f/lufylegend/api,以下测试代码也用到了lufylegend.js,据说这个引擎是个不错的引擎,想了解的同学,去官方网站看看吧:27b9bfedc1c708a1294a441f/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.}
测试链接:27b9bfedc1c708a1294a441f/yorhom/articles/hitTestRectArc
三,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 ? -n : n;
26.return n;
27.}
28.
29.static int distance(const QPoint& pt1, const QPoint& pt2)
30.{
31.return CMath::sqrt(CMath::pow(CMath::abs(pt1.x() - pt2.x()), 2) + CMath::pow(CMath::abs(pt1.y() - pt2.y()), 2));
32.}
33.
34.};
35.
36.class CArc
37.{
38.
39.protected:
40.
41.int m_nRadius;
42.QPoint m_ptCenter;
43.
44.public:
45.
46.CArc() : m_nRadius(0), m_ptCenter(0, 0){}
47.CArc(const CArc& arc) : m_nRadius(arc.radius()), m_ptCenter(arc.center()){}
48.CArc(int radius, QPoint center) : m_nRadius(radius), m_ptCenter(center){}
49.CArc(int radius, int centerX, int centerY) : m_nRadius(radius), m_ptCenter(centerX, centerY){}
50.~CArc(){}
51.
52.void setRadius(int radius){m_nRadius = radius;}
53.int radius() const {return m_nRadius;}
54.void setCenter(const QPoint& center){m_ptCenter = center;}
55.void setCenter(int centerX, int centerY){m_ptCenter = QPoint(centerX, centerY);}
56.QPoint center() const {return m_ptCenter;}
57.QRect rect() const {return QRect(center().x() - radius(), center().y() - radius(), 2 * radius(), 2 * radius());}
58.
59.};
60.
61.class CHitTestAlg
62.{
63.
64.protected:
65.
66.QRect m_rtRect;
67.CArc m_arArc;
68.
69.protected:
70.
71.bool locatedSameQuadrant() const
72.{
73.bool bRes = false;
74.int nRectLeft = m_rtRect.left(), nRectTop = m_rtRect.top(), nRectRight = m_rtRect.right(), nRectBottom = m_rtRect.bottom();
75.int nArcCenterX = m_arArc.center().x(), nArcCenterY = m_arArc.center().y();
76.if((nRectLeft - nArcCenterX >= 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 && nRectTop - nArcCenterY >= 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
mainwindow.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
mainwindow.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 *mouseEvent)
22.{
23.if(mouseEvent){
24.QPoint ptPos = mouseEvent->pos();
25.QRect rtRect;
26.rtRect.setX(ptPos.x() - m_rtRect.width() / 2);
27.rtRect.setY(ptPos.y() - m_rtRect.height() / 2);
28.rtRect.setWidth(m_rtRect.width());
29.rtRect.setHeight(m_rtRect.height());
30.m_rtRect = rtRect;
31.m_bHit = CHitTestAlg(m_rtRect, m_arArc).hitTest();
32.QWidget::update();
33.}
34.}
35.
36.void MainWindow::paintEvent(QPaintEvent *paintEvent)
37.{
38.Q_UNUSED(paintEvent)
39.
40.QPainter xPainter(this);
41.{
42.xPainter.save();
43.QBrush xBrush; xBrush.setColor(Qt::red); xBrush.setStyle(Qt::SolidPattern);
44.QPen xPen; xPen.setColor(Qt::black); xPen.setStyle(Qt::SolidLine);
45.xPainter.setBrush(xBrush);
46.xPainter.setPen(xPen);
47.xPainter.drawEllipse(m_arArc.center(), m_arArc.radius(), m_arArc.radius());
48.xPainter.restore();
49.}
50.{
51.xPainter.save();
52.QBrush xBrush; xBrush.setColor(Qt::darkGreen); xBrush.setStyle(Qt::SolidPattern);
53.QPen xPen; xPen.setColor(Qt::black); xPen.setStyle(Qt::SolidLine);
54.xPainter.setBrush(xBrush);
55.xPainter.setPen(xPen);
56.xPainter.drawRect(m_rtRect);
57.xPainter.restore();
58.}
59.{
60.xPainter.save();
61.QString sContent = QString("Hit Test: %1").arg(m_bHit ? "true" : "false");
62.QFont ftFont("Tahoma", 12, QFont::DemiBold, true);
63.xPainter.setFont(ftFont);
64.xPainter.drawText(20, m_arArc.rect().bottom() + 30, sContent);
65.xPainter.restore();
66.}
67.}
main.cpp里的代码:
[cpp]view plaincopyprint?
1.#include
2.#include "mainwindow.h"
3.
4.int main(int argc, char *argv[])
5.{
6.QApplication a(argc, argv);
7.MainWindow w;
8.w.show();
9.
10.return a.exec();
11.}
原理和js版是一样的,就不多解释了,在下面我会放出所有代码。C++版运行demo如下:
Qt做的界面感觉还是不错的,哈哈~~
源代码下载:27b9bfedc1c708a1294a441f/yorhom/hitTestRectArc.rar 本文就到此为止,以上就是本篇所有内容,欢迎大家交流。----------------------------------------------------------------
欢迎大家转载我的文章。
转载请注明:转自Yorhom's Game Box
27b9bfedc1c708a1294a441f/yorhomwang
欢迎继续关注我的博客
正在阅读:
2D游戏中的碰撞检测04-20
福建省珠宝首饰零售商店名录2018版1095家 - 图文04-15
寻秋作文450字06-22
《普通高中音乐课程标准》 - 课标解读12-29
未来的我我想对你说作文400字06-17
中小学生健康知识知晓率和健康行为形成率调查问卷题库(最新)10-10
《经济法》作业02-03
房屋建筑学模拟试题05-16
- 1基于CaTICs网络2D赛的研究与探讨
- 2ANSYS电磁场分析指南-2D
- 3Clinical Microwave Breast Imaging – 2D Results and th
- 4UG带尺寸的草图保存-2D批量绘UG-3D-2D自动标注尺寸
- 5游戏中的数学 - 对策问题
- 6游戏中的数学模型
- 7ANSYS Maxwell 2D求解齿槽转矩的几种方法
- 8ANSYS Maxwell 2D求解齿槽转矩的几种方法
- 9Dirac operator and Ising model on a compact 2D random lattice
- 10Dirac operator and Ising model on a compact 2D random lattice
- 教学能力大赛决赛获奖-教学实施报告-(完整图文版)
- 互联网+数据中心行业分析报告
- 2017上海杨浦区高三一模数学试题及答案
- 招商部差旅接待管理制度(4-25)
- 学生游玩安全注意事项
- 学生信息管理系统(文档模板供参考)
- 叉车门架有限元分析及系统设计
- 2014帮助残疾人志愿者服务情况记录
- 叶绿体中色素的提取和分离实验
- 中国食物成分表2020年最新权威完整改进版
- 推动国土资源领域生态文明建设
- 给水管道冲洗和消毒记录
- 计算机软件专业自我评价
- 高中数学必修1-5知识点归纳
- 2018-2022年中国第五代移动通信技术(5G)产业深度分析及发展前景研究报告发展趋势(目录)
- 生产车间巡查制度
- 2018版中国光热发电行业深度研究报告目录
- (通用)2019年中考数学总复习 第一章 第四节 数的开方与二次根式课件
- 2017_2018学年高中语文第二单元第4课说数课件粤教版
- 上市新药Lumateperone(卢美哌隆)合成检索总结报告
- 碰撞
- 检测
- 游戏
- 基于matlab语音信号处理设计毕业论文
- 广东省各市各区域医院名单
- 云南省腾冲县第六中学2014-2015学年高二上学期教学质量综合检测
- 2022届高考语文全国百强名校模拟作文题 100题之(13-14题)
- 最新版精选电力交易员模拟考试复习题库158题(答案)
- 历年江西省公务员考试《申论》真题
- 人音版三年级音乐下册(简谱)第6课《剪羊毛》教学设计
- 行政管理专业社会调查报告范例
- TEDAS a Twitter Based Event Detection and Analysis System
- 替莫唑胺胶囊治疗恶性脑胶质瘤30例疗效分析_白红民
- 2022-2022年初中地理广西初二专题试卷测试试题【6】含答案考点及
- 被外行美化的野蛮史评天国王朝
- 第二章施工组织总体设想,方案针对性及施工段划分
- 2022年聊城大学文学院古代汉语复试笔试仿真模拟题
- 讲卫生的演讲稿500字
- 43影响气候的主要因素(无答案)-江苏省徐州市王杰中学湘教版七年
- 排洪泵价格国内十大品牌总评榜
- 参考幼儿教师转正自我鉴定五篇合集
- 高考数学第一轮复习直线与圆的位置关系学案(教师版)
- 八年级历史上册期中考试试卷人教版