在网易游戏研发笔试题中有一题就是这个碰撞检测,之前我看过一些文章,现在整理一个写个整理后的文章
之前大二写了一个简单的游戏【http://shouji.baidu.com/game/item?docid=6487395&from=as】,里面就是用很笨的枚举所有来相互检测是否碰撞 这样效率太慢了
1、前言:
下面这是我写的益智类小游戏 也要有碰撞检测和重力掉落 那时大二比较无知用了枚举去做碰撞检测 orz
飞机有很多子弹 还有敌机 相互之前要做碰撞检测
2、碰撞基础知识:
AABB包围盒:二维来说就是如图 三个矩形判断是否相交
OBB包围盒:就是AABB加一个方向 矩形可以旋转 在全民打飞机可以看到有的飞机会转弯
3、碰撞检测
AABB:
struct
Point
{
int
x,y;};
struct
Rect
{
Point
LeftBottom;
Point
RightTop;
bool
IsIntersect(
const
Rect
&
A
)
{
return
!(
RightTop.x<
A
.LeftBottom.x||
RightTop.y<
A
.LeftBottom.y||
LeftBottom.x>
A
.RightTop.x||
LeftBottom.y>
A
.RightTop.y);
}
};
OBB:
要用到sat分离轴定理
只针对凸多边形 凹多边形可以变成多个凸多边形 然后再运用sat
为:
(1)如果可以找到一条轴使得两个多边形在这条轴上的投影不相交,则这两个凸多边形就不相交
(2)以两个多边形的所有边的法线为轴 如果两个多边形在所有这些轴上的投影都相交,则这两个多边形就是相交的
4、OBB的实际代码
因为是矩形,所以法线也就是找长宽这两条线
代码有点挫 后期改进
struct
Point
{
int
x,y;};
struct
Line
{
Point
p1,p2;
};
struct
Vector
{
Vector(
int
x
=0,
int
y
=0)
{
this
->x=
x
;
this
->y=
y
;
}
int
x,y;};
struct
OBBRect
{
Line
Line1;
Line
Line2;
bool
IsIntersect(
const
OBBRect
&
A
)
{
//在Line1投影
Vector
v(Line1.p2.x-Line1.p1.x,Line1.p2.y-Line1.p1.y);
//四个点在v上面的投影
Vector
p1,p2,p3,p4;
float
L1 = (v *[点乘] p1)/|p1|;
float
L2 = (v *[点乘] p2)/|p2|;
float
L3 = (v *[点乘] p3)/|p3|;
float
L4 = (v *[点乘] p4)/|p4|;
float
minL=min(L1,L2,l3,l4);
float
maxL=max(L1,L2,l3,l4);
//所以矩形的投影是v上面长度minL 到 maxL的线段
//同理
Vector
Ap1,Ap2,Ap3,Ap4;
float
AL1 = (v *[点乘] Ap1)/|Ap1|;
float
AL2 = (v *[点乘] Ap2)/|Ap2|;
float
AL3 = (v *[点乘] Ap3)/|Ap3|;
float
AL4 = (v *[点乘] Ap4)/|Ap4|;
float
AminL=min(L1,L2,l3,l4);
float
AmaxL=max(L1,L2,l3,l4);
//查看是否相交
//如果minL>AmaxL 或者 maxL<AmaxL 则不相交
//反之,相交
//同理
//在Line2投影
//同理
//在A.Line1投影
//同理
//在A.Line2投影
}
};
5、未完待续:
还有四叉树的优化 减少枚举全部的飞机或者说是子弹 orz
【关于博客】:每次都要上传图片 好麻烦 还是印象比较好