碰撞检测一般用于游戏设计中,比如现在比较火的游戏“王者荣耀”,我们玩游戏中可以看到英雄一般走到地方防御塔的攻击范围,就会被攻击,但是程序员在下代码的时候,不能看到,只能用一段段代码表示,这是就要用到碰撞检测,还判断两个物体是否相交。
在这里我主要说三种主要的相交的判断,其他的碰撞都是在此条件下演变出来的:
在这里先写一下矩形、圆、直线的类代码:
//矩形类
class rect{
private:
double xl;
double yl;
double xr;
double yr;
public:
rect(double _xl, double _yl, double _xr, double _yr)
:xl(_xl), yl(_yl), xr(_xr), yr(_yr)
{}
bool collideRL(linear& l);
bool collideRC(Circle& c);
bool collideRR(rect& r, rect& r1);
};
//圆类
class Circle{
private:
double x;
double y;
double r;
public:
Circle(double _x, double _y, double _r)
:x(_x), y(_y), r(_r)
{}
double getCx(){ return x; }
double getCy(){ return y; }
double getCr(){ return r; }
};
//直线类
class linear{
private:
double k;
double b;
double x1;
double x2;
public:
linear(double _k, double _b, double _x1, double _x2)
:k(_k), b(_b), x1(_x1), x2(_x2)
{}
double getlk(){ return k; }
double getlb(){ return b; }
double getlx1(){ return x1; }
double getlx2(){ return x2; }
};
- 直线和矩形的碰撞检测
直线和矩形的相交判断,我在此用到的方法主要是判断矩形的的对角线和直线的交点是否在矩形内,图形表示如下:
如上图所示,我们只需要判断直线和矩形对角线是否相交的交点是否在矩形内,函数代码为:
bool rect::collideRL(linear& l)
{
//定义四个常量,分别表示矩形两对角线的斜率和与y轴交点;
double k1, k2;
double b1, b2;
k1 = (yl - yr) / (xl - xr);
b1 = yl - xl*k1;
k2 = -k1;
b2 = yl - xr*k2;
double k = l.getlk();
double b = l.getlb();
double x1 = l.getlx1();
double x2 = l.getlx1();
double x, y;
//计算直线和矩形对角线的交点的想x,y值;
x = (b - b1) / (k1 - k);
y = (b - b1) / (k1 - k)*k + b;
//判断交点是否在矩形内
if ((xl < x && x < xr)|| (xr < x && x < xl))
{
if ((y>yl&&y<yr) || (y>yr&&y < yl))
{
cout << "直线和矩形相交" << endl;
return true;
}
}
x = (b - b2) / (k2 - k);
y = (b - b2) / (k2 - k)*k + b;
if ((xl < x && x < xr) || (xr < x && x < xl))
{
if ((y>yl&&y<yr) || (y>yr&&y < yl))
{
cout << "直线和矩形相交" << endl;
return true;
}
}
cout << "直线和矩形相离" << endl;
return false;
}
- 圆和矩形的碰撞检测
圆和矩形的相交判断,我主要把它分为以下几种情况:
函数代码表示为:
bool rect::collideRC(Circle& c)
{
double x = c.getCx();
double y = c.getCy();
double r = c.getCr();
double s = sqrt(pow(x - xl, 2) + pow(y - yl, 2));
double s1 = sqrt(pow(x - xl, 2) + pow(y - yr, 2));
double s2 = sqrt(pow(x - xr, 2) + pow(y - yr, 2));
double s3 = sqrt(pow(x - xr, 2) + pow(y - yl, 2));
if ((r > xl&&r < xr) || (r<xl&&r>xr))
{
if ((r<yl&&r>yr) || (r>yl&&r < yr))
{
cout << "圆和矩形相交" << endl;
return true;
}
}
if ((fabs(y - yl) < r) || (fabs(y - yr) < r) || (fabs(x - xl) < r) || (fabs(x - xr) < r))
{
if ((r > xl&&r < xr) || (r<xl&&r>xr) || (r<yl&&r>yr) || (r>yl&&r < yr))
{
cout << "圆和矩形相交" << endl;
return true;
}
}
if (s > r&&s1 > r&&s2 > r&&s3 > r)
{
cout << "圆和矩形相离" << endl;
return false;
}
cout << "圆和矩形相交" << endl;
return true;
}
形的碰撞检测和圆与矩形的碰撞检测时所用的第二种方法相似,**比较两矩形的中心连线在x,y轴上的投影和两矩形的长或者宽的1/2之和比较,投影同时小于两矩形的长或者宽的1/2之和是,两矩形相交。**下面用图来表示一下为:
用代码表示为下:
bool rect::collideRR(rect& r,rect& r1)
{
//判断原理 :两矩形中点相连在x轴上的投影小于与x轴平行的边的和的二分之一;y轴同理;
if (fabs((r.xl + r.xr) / 2 - (r1.xl + r1.xr) / 2) < (fabs(r.xl - r.xr) + fabs(r1.xl - r1.xr)) / 2)
{
if (fabs((r.yl + r.yr) / 2 - (r1.yl + r1.yr) / 2) < (fabs(r.yl - r.yr) + fabs(r1.yl - r1.yr)) / 2)
{
cout << "两矩形相交" << endl;
return true;
}
}
cout << "两矩形相离" << endl;
return false;
}
以上就是碰撞检测的理解,其中有一点问题就是此方法不能用来判断两物体是否相切,只能证明相离和相交,因为定义的类型都是double型的,不能用来直接判等于;所以上面的方法只能判是否相撞,不能判什么时候相遇。