只能提供初步了
1、球体之间的相互碰撞检测(球的半径和质量均相等)
输入数据:(2D向量表示)
球1的球心坐标
球1的速度方向
球1的速率
球1的速度=球1的速度方向×球1的速率
球2的球心坐标
球2的速度方向
球2的速率
球2的速度=球2的速度方向×球2的速率
计算过程:
球1与球2的相对速度 RelativeV = 球1的速度-球2的速度
由球1的球心坐标与RelativeV的单位向量构成一个固定向量,表示由一点向某个方向的一条射线
求球2的球心坐标与射线的距离
如果所得的距离大于2倍半径,则两球不存在碰撞的可能性
如果所得的距离小于等于2倍半径,则两球存在碰撞的可能性
计算当前帧内的碰撞可能性
为了增加计算精度,使用双循环,分离渲染层和逻辑层,渲染速度为33fps
起始时间为 0 时间间隔为 t 把每帧切成30个时间片
计算T 从0到30 之间是否存在一个点NewPosition与球2的球心坐标的距离小于或者等于2倍半径
RV = RelativeV/30;
V1'=V1/30;
V2'=V2/30;
while(T<=30){
T+=t;
NewPosition=Position1+RV*T;
if(Distance(NewPosition, Position2)<=2*RADIUS){
// 计算在碰撞瞬间球1的球心坐标和球2的球心坐标
Pos1=Position1+V1'*(T-1);
Pos2=Position2+V2'*(T-1);
// 计算碰撞之后两个小球各自的速度
CollisionResponseBetweenSphere();
NewV1; // 球1碰撞之后的速度
NewV2; // 球2碰撞之后的速度
NV1 = NewV1/30;
NV2 = NewV2/30;
Pos1'=Pos1+NV1*(30-T);
Pos2'=Pos2+NV2*(30-T);
}
}
2、球体与平面的碰撞检测
在2D环境下,平面可以视为一条直线
输入数据:
球的球心坐标 Position
球的速度方向 Direction
球的速率 Speed
球的速度=球的速度方向×球的速率 Velocity = Direction*Speed
线段的端点1的坐标 SP (Start Point)
线段的端点2的坐标 EP (End Point)
计算过程:
求线段的法向量 Normal
计算球的速度方向与线段法向量的点积 Dot,判断球与线段是否平行
如果Dot为0,表示两个向量互相垂直,即球的运动方向与线段平行,不存在碰撞的可能性
如果Dot不为 0,表示球体与线段存在碰撞的可能
计算当前帧内的碰撞的可能性
由球心的当前坐标与经过一帧之后球心的坐标构成一条线段 P1P2
由线段的StartPoint和EndPoint构成一条线段SE
计算P1P2与SE是否相交
如果不相交,则在当前帧内,球体与线段不会碰撞
如果相交,则在当前帧内,球体与线段发生碰撞
P1=Position;
P2=Position+Velocity;
// Step1
// 线段相交的快速排斥实验
xMax=max(SP.x, EP.x);
xMin=min(SP.x, EP.x);
yMax=max(SP.y, EP.y);
yMin=min(SP.y, EP.y);
if((P1.x>=xMin&&P1.x<=xMax)&&(P1.y>=yMin&&P1.y<=yMax))
flag1=true;
else
flag1=false;
if((P2.x>=xMin&&P2.x<=xMax)&&(P2.y>=yMin&&P2.y<=yMax))
flag2=true;
else
flag2=false;
if(flag1||flag2)
// 快速排斥实验成立
step1=true;
else
continue; // 排斥实验失败,碰撞不会发生
// Step2
// 线段相交的跨立实验
if((P1-SP)×(EP-SP)*(EP-SP)×(P2-SP)>=0){
// 碰撞会发生, 计算碰撞点M
// 分情况:
// 1、两条线段的斜率均存在
// 由碰撞点既在线段P1P2上又在线段SE上,得到一个方程组
// (M-P1)×(P2-P1)=0
// (M-SP)×(EP-SP)=0
M.x = ((P1×P2)*(EP.x-SP.x)-(SP×EP)*(P2.x-P1.x))/((EP-SP)×(P2-P1));
M.y = ((P1×P2)*(EP.y-SP.y)-(SP×EP)*(P2.y-P1.y))/((EP-SP)×(P2-P1));
// 2、线段SE与x轴平行
// M.y为SP.y
// (M-P1)×(P2-P1)=0
M.y = SP.y;
M.x = ((P1×P2)*(EP.x-SP.x)-(SP×EP)*(P2.x-P1.x))/((EP-SP)×(P2-P1));
// 3、线段SE与y轴平行
// M.x为SP.x
// (M-P1)×(P2-P1)=0
M.x = SP.x;
M.y = ((P1×P2)*(EP.y-SP.y)-(SP×EP)*(P2.y-P1.y))/((EP-SP)×(P2-P1));
// 计算碰撞之后球体的速度
CollisionResponseBetweenEdge();
NewVelocity;
NewPos = M+NewVelocity*(Distance(M, P2)/Distance(P1, P2));
}
else
continue;
3、球体之间的碰撞处理CollisionResponseBetweenSphere();
输入数据:
球1的球心坐标位置 Position1
球1的速度方向 Direction1
球1的速率 Speed1
球1的速度=球1的速度方向×球1的速率 Velocity1=Direction1×Speed1
球2的球心坐标位置 Position2
球2的速度方向 Direction2
球2的速率 Speed2
球2的速度=球2的速度方向×球2的速率 Velocity2=Direction2×Speed2
计算目的:
得到两个小球碰撞之后的新速度
计算过程:
计算两球体碰撞时的法向量
Normal=(Position2-Position1).Unit()
计算两球体碰撞前的初速度
将x-y坐标系统中的速度转换到n-t坐标系统中
球1在n轴上的速度 V1n = Normal*(Normal dot Velocity1)
球1在t轴上的速度 V1t = Velocity1-V1n
球2在n轴上的速度 V2n = Normal*(-Normal dot Velocity2)
球2在t轴上的速度 V2t = Velocity2-V2n
计算两球体在碰撞之后的法线方向新速度
NewV1n = ((V1n*m1)+(V2n*m2)-(V1n-V2n)*m2)/(m1+m2)
NewV2n = ((V1n*m1)+(V2n*m2)-(V2n-V1n)*m1)/(m1+m2)
假设m1=m2=1,则有:
NewV1n = (V1n+V2n-(V1n-V2n))/2 = V2n
NewV2n = (V1n+V2n-(V2n-V1n))/2 = V1n
计算两球体在碰撞之后的切线方向新速度
NewV1t = V1t
NewV2t = V2t
计算两球体碰撞之后的最终速度
NewVelocity1 = NewV1n+NewV1t
NewVelocity2 = NewV2n+NewV2t
4、球体与平面的碰撞处理
CollisionResponseBetweenEdge();
输入数据:
球体的球心坐标位置 Position
球体的速度方向 Direction
球体的速率 Speed
球体的速度 = 球体的速度方向×球体的速率 Velocity = Direction×Speed
平面的法向量 Normal
计算过程
计算法线方向的向量 N = (-Velocity*Normal)*Normal
计算球体碰撞之后新的速度
NewVelocity = 2*N+Velocity
数学理论:
矢量叉积P1(x1,y1) P2(x2,y2) P1×P2=x1*y2-x2*y1
矢量点积P1(x1,y1) P2(x2,y2) P1*P2 =x1*x2+y1*y2