void updateDirAndTimeByEdge(FP _percent, tableEdge _tbe, BallObj ball, FP _deltaTime) { ball.UpdateBallPos(_deltaTime * _percent); //先更新到撞击点 var curReflcDir = Detection.CheckCircle_LineCollision(_tbe, ball.GetPos(), ball.GetRadius(), ball.GetMoveDir()); //计算碰撞响应 ball.UpdateMoveDir(curReflcDir); //更新实时方向 }
void AddTestData(tableEdge tbg, TSVector2 prepos, TSVector2 hitpos, TSVector2 premoveDir, TSVector2 aftmoveDir) { td.Add(new testData() { tbg = tbg, prehitPos = prepos, hitpos = hitpos, PremoveDir = premoveDir, AftmoveDir = aftmoveDir }); }
public fastEdge(BallObj _ball, tableEdge _tbe, FP _t_percent) { ball = _ball; tbe = _tbe; t_percent = _t_percent; deltaTime = ball.deltaTime; hitType = HitType.Edge; }
public void Init(BallObj _ball, tableEdge _tbe, FP _t_percent, TSVector2 _hitNormal) { ball = _ball; tbe = _tbe; t_percent = _t_percent; deltaTime = ball.deltaTime; hitType = HitType.Edge; hitNormal = _hitNormal; }
/// <summary> /// 当球的运动矢量和边的法线点积小于零,证明和该边可能产生碰撞 /// </summary> /// <param name="segement"></param> /// <param name="dir"></param> /// <returns></returns> public static bool CheckCloseSegement(tableEdge segement, TSVector2 dir) { FP result = TSVector2.Dot(dir, segement.normal); if (result < 0) { return(true); } return(false); }
/// <summary> /// 圆和边的平面动态相交检测(注意是边的平面 并不是线段) /// </summary> /// <param name="tedge"></param> /// <param name="crd"></param> /// <returns>是否在该段时间内相交</returns> public static bool CheckCircle_LineContact(tableEdge tedge, CircleRunData crd, ref FP t_percent) { //Sc TSVector2 Sc = PointToLineDir(tedge.start, tedge.end, crd.cur_pos); //Se TSVector2 Se = PointToLineDir(tedge.start, tedge.end, crd.next_pos); TSVector2 Scnormal = Sc.normalized; TSVector2 Senormal = Se.normalized; //TSVector2 Scnormal = Sc.normalized; //TSVector2 Senormal = Se.normalized; //只有两种结果 同向和 反向 FP result = TSVector2.Dot(Scnormal, Senormal); //1同向,0垂直,-1反向 FP Scnorm = TSMath.Sqrt(TSMath.Abs(TSVector2.Dot(Sc, Sc))); //Sc模 FP Senorm = TSMath.Sqrt(TSMath.Abs(TSVector2.Dot(Se, Se))); //Se模 //FP radius_square = crd.radius * crd.radius; if (result > 0 && Scnorm > crd.radius && Senorm > crd.radius)//Sc,Se同向,俩圆圆半径大于到直线距离,不相交 { return(false); } else//相交 求t { FP S = 0; if (result > 0) { S = Scnorm - Senorm; } else { S = Scnorm + Senorm; } //TSVector2 sce = Sc - Se; //FP S = TSMath.Sqrt( TSVector2.Dot(sce, sce)); t_percent = (Scnorm - crd.radius) / S;//圆心到达撞击点的距离/圆心经过的总距离 来求出时间占比 if (t_percent > 1) { return(false); Debug.Log("路程百分比大于1,注意!"); } //if (t_percent < 0) //{ // if (Detection.CheckCircle_tableEdgeEndContact(crd, tedge, ref t_percent)) // { // Debug.Log("修正"); // } //} return(t_percent >= 0?true:false); } }
/// <summary> /// 圆碰撞的反弹方向 /// </summary> /// <param name="tedge">线段</param> /// <param name="circlePos">圆心</param> /// <param name="radius">半径</param> /// <param name="moveDir">圆的速度方向</param> /// <returns></returns> public static TSVector2 CheckCircle_LineCollision(tableEdge tedge, TSVector2 circlePos, FP radius, TSVector2 moveDir) { TSVector2 C = circlePos; TSVector2 A = tedge.farstart; TSVector2 B = tedge.farend; TSVector2 V = moveDir; TSVector2 AC = C - A; TSVector2 AB = B - A; TSVector2 ABnormal = TSVector2.Normalize(AB); TSVector2 HC = AC - ABnormal * TSMath.Abs(TSVector2.Dot(AC, ABnormal)); TSVector2 HCnormal = TSVector2.Normalize(HC); FP VP = TSMath.Abs(TSVector2.Dot(V, HCnormal)); if (TSMath.Abs(VP) > 10000) { Debug.Log("圆碰边速度过大"); } TSVector2 VF = V + HCnormal * VP * 2;//反射方向 return(VF); }
/// <summary> /// 静态相交检测,主要是计算圆心到线段最近点的距离。 /// 圆心p(x, y), 半径r, 线段两端点p1(x1, y1)和p2(x2, y2) /// </summary> /// <returns></returns> public static bool CheckCircle_SegementContact(TSVector2 cirPos, tableEdge segement, FP radius) { TSVector2 P1P = cirPos - segement.start; TSVector2 P1P2 = segement.end - segement.start; FP P2P2_len = P1P2.magnitude; TSVector2 P1P2norm = P1P2.normalized; FP u = TSVector2.Dot(P1P, P1P2norm); TSVector2 nearestPos = TSVector2.zero; // determine the nearest point on the lineseg FP x0 = 0; FP y0 = 0; if (u <= 0) { // p is on the left of p1, so p1 is the nearest point on lineseg nearestPos = segement.start; } else if (u >= P2P2_len) { // p is on the right of p2, so p2 is the nearest point on lineseg nearestPos = segement.end; } else { // p0 = p1 + v2 * u // note that v2 is already normalized. nearestPos = segement.start + P1P2norm * u; } var dis = TSVector2.Distance(cirPos, nearestPos); if (dis <= radius + FP.Epsilon) { return(true); } else { return(false); } }
/// <summary> /// 检测圆是否和线段的端点相交,参考了俩个动态圆的动态相交测试,都是转化为射线和圆的相交测试 /// </summary> /// <returns></returns> public static bool CheckCircle_tableEdgeEndContact(CircleRunData runCircle, tableEdge segement, ref FP _percent, ref TSVector2 _nearestPos) { TSVector2 cirPos = runCircle.cur_pos; TSVector2 nearestPos = TSVector2.zero; //先确定圆的起始位置离哪个端点最近 if (TSVector2.DistanceSquared(runCircle.cur_pos, segement.start) < TSVector2.DistanceSquared(runCircle.cur_pos, segement.end)) { _nearestPos = nearestPos = segement.start; } else { _nearestPos = nearestPos = segement.end; } //TSVector2 VA = runCircle.next_pos - runCircle.cur_pos; //TSVector2 VB = staticCircle.next_pos - staticCircle.cur_pos; //两个运动方向描述为一方运动另一方静止 so //TSVector2 VAB = VA - VB;//runCircle相对于staticCircle的运动方向pc TSVector2 VAB = runCircle.next_pos - runCircle.cur_pos; //动态圆射线运动方向 TSVector2 Idir = nearestPos - cirPos; //射线起点到静态圆的方向 //FP Idir_length_square = TSVector2.Dot(Idir, Idir); FP Idir_length_square = Idir.LengthSquared(); FP static_radius_square = runCircle.radius * runCircle.radius; if (Idir_length_square < static_radius_square)//射线起点在圆心内部,相交 { //_percent = calHitInfo(); //_percent = 1;//一开始就相交的 //Debug.Log("射线起点在圆心内部"); return(false); } else//射线起点在圆心外部的情况 { FP a_projvalue = TSVector2.Dot(Idir, VAB.normalized); if (a_projvalue < 0)//球体位于射线原点的后面 不相交 { return(false); } else { FP m_square = Idir_length_square - a_projvalue * a_projvalue; //球心到投影点距离的平方 if (m_square - static_radius_square > 0) //预测不相交 { return(false); } else//有可能有交点,因为有可能距离不够 { //var t = calHitInfo(Idir, a_projvalue); FP b_squar = m_square; FP f = TSMath.Sqrt(static_radius_square - b_squar); //理论上来说 f是开跟后的结果,应该有俩个值? FP t1 = a_projvalue - f; //碰撞到静态圆所走的路程,总路程是runCircle.cur_pos+VAB*delataTime; FP t2 = a_projvalue + f; FP per = 0; bool isFlag = false; if (t1 > 0 && t1 - VAB.magnitude < FP.EN8) { isFlag = true; if (VAB.magnitude < 0) { Debug.Log("除数不能为0"); } per = t1 / VAB.magnitude; } if (t2 > 0 && t2 - VAB.magnitude < 0) { isFlag = true; if (VAB.magnitude < 0) { Debug.Log("除数不能为0"); } var per2 = t2 / VAB.magnitude; if (per2 < per) { per = per2; } } _percent = per; if (_percent > 1) { Debug.Log("路程百分比大于1,注意!"); } if (isFlag && _percent < FP.EN4) { return(false); } return(isFlag); } } } }