Ejemplo n.º 1
0
        /// <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);
            }
        }
Ejemplo n.º 2
0
        /// <summary>
        /// 计算球和球的互相作用方向
        /// </summary>
        /// <returns></returns>
        //public static TSVector2[] CheckCircle_CircleCollision(CircleRunData runCircle, CircleRunData staticCircle)
        //{
        //    TSVector2 V = runCircle.next_pos - runCircle.cur_pos;
        //    TSVector2 U = staticCircle.next_pos - staticCircle.cur_pos;
        //    TSVector2 AB = staticCircle.cur_pos - runCircle.cur_pos;
        //    TSVector2 BA = runCircle.cur_pos - staticCircle.cur_pos;
        //    TSVector2 Vx = TSVector2.Dot(V, AB.normalized)*AB.normalized;
        //    TSVector2 Vy = V - Vx;
        //    TSVector2 Ux = TSVector2.Dot(U, BA.normalized) * BA.normalized;
        //    TSVector2 Uy = U - Ux;
        //    V = Ux + Vy;//反弹后的方向
        //    U = Vx + Uy;//反弹后的方向
        //    return new TSVector2[2] { V,U };
        //}
        //public static TSVector2[] CheckCircle_CircleCollision(TSVector2 V, TSVector2 U)
        //{
        //    TSVector2 Vx = new TSVector2(V.x, 0);
        //    TSVector2 Vy = new TSVector2(0, V.y);
        //    TSVector2 Ux = new TSVector2(U.x, 0);
        //    TSVector2 Uy = new TSVector2(0, U.y);
        //    V = Ux + Vy;//反弹后的方向
        //    U = Vx + Uy;//反弹后的方向
        //    return new TSVector2[2] { V, U };
        //}
        /// <summary>
        /// 圆和圆的动态相交检测(根据相对运动,抽象为一方是运动,另一方是静止)
        /// </summary>
        /// <param name="cd"></param>
        /// <param name="crd"></param>
        /// <returns></returns>
        public static bool CheckCircle_CircleContact(CircleRunData runCircle, CircleRunData staticCircle, FP deltaTime, ref FP _percent)
        {
            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 Idir = staticCircle.cur_pos - runCircle.cur_pos; //射线起点到静态圆的方向
            //FP Idir_length_square = TSVector2.Dot(Idir, Idir);
            FP Idir_length_square   = Idir.LengthSquared();
            FP static_radius_square = (staticCircle.radius * 2) * (staticCircle.radius * 2);

            //Func<TSVector2,FP,FP> calHitInfo = (e_dir,a_projvalue) =>
            ////可以在返回true的时候再计算,后优化
            //{
            //    //TSVector2 e_dir = staticCircle.cur_pos - runCircle.cur_pos;
            //    //FP a_projvalue = TSMath.Abs(TSVector2.Dot(e_dir, VAB.normalized));
            //    a_projvalue = TSMath.Abs(a_projvalue);
            //    FP b_squar = TSVector2.Dot(e_dir, e_dir) - a_projvalue * a_projvalue;
            //    FP f = TSMath.Sqrt(static_radius_square - b_squar);
            //    FP t = a_projvalue - f;//碰撞到静态圆所走的路程,总路程是runCircle.cur_pos+VAB*delataTime;
            //    return t /*/ (VAB * deltaTime).magnitude*/;//求出占比
            //};

            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 < 0)
                        {
                            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 (isFlag && _percent < FP.EN4)
                        {
                            return(false);
                        }
                        return(isFlag);
                    }
                }
            }
        }
Ejemplo n.º 3
0
        /// <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);
                    }
                }
            }
        }
Ejemplo n.º 4
0
        void UpdatePhysicStep(FP _deltaTime)
        {
            step++;
            //AddTestData(step,balls);

            for (int k = 0; k < balls.Count; k++)
            {
                var ball = balls[k];
                ball.deltaTime = _deltaTime;
                ball.lockcheck = false;
            }
            testnumber = 0;

            FP leftSyncTime = _deltaTime;

            while (true)
            {
                testnumber++;
                if (testnumber > 100)
                {
                    if (testnumber > 200)
                    {
                        Debug.Log("防止死循环");
                        break;
                    }
                }
                //List<BaseHit> baseHits = new List<BaseHit>();
                baseHits.Clear();
                FP _percent = 0;
                for (int i = 0; i < balls.Count - 1; i++)
                {
                    var ball = balls[i];
                    //CircleRunData run_crd = new CircleRunData(ball.GetPos(), ball.PredictPos(leftSyncTime), ball.GetRadius());
                    CircleRunData run_crd = run_crdPool.New();
                    run_crd.Init(ball.GetPos(), ball.PredictPos(leftSyncTime), ball.GetRadius());
                    for (int j = i + 1; j < balls.Count; j++)
                    {
                        var otherball = balls[j];
                        //CircleRunData static_crd = new CircleRunData(otherball.GetPos(), otherball.PredictPos(leftSyncTime), otherball.GetRadius());
                        CircleRunData static_crd = run_crdPool.New();
                        static_crd.Init(otherball.GetPos(), otherball.PredictPos(leftSyncTime), otherball.GetRadius());
                        if (Detection.CheckCircle_CircleContact(run_crd, static_crd, ball.deltaTime, ref _percent))
                        {
                            var obj = fastHitBallPool.New();
                            obj.Init(ball, otherball, _percent);
                            baseHits.Add(obj);
                            //baseHits.Add(new fastHitBall(ball, otherball, _percent));
                        }
                    }
                }

                for (int ii = 0; ii < balls.Count; ii++)
                {
                    var       ball          = balls[ii];
                    TSVector2 predictEndPos = ball.GetPos() + ball.GetMoveDir() * 100;
                    //CircleRunData run_crd = new CircleRunData(ball.GetPos(), ball.PredictPos(leftSyncTime), ball.GetRadius());
                    CircleRunData run_crd = run_crdPool.New();
                    run_crd.Init(ball.GetPos(), ball.PredictPos(leftSyncTime), ball.GetRadius());
                    //在当前速度下,预测圆最先和哪条边碰撞
                    for (int jj = 0; jj < tableEdges.Count; jj++)
                    {
                        TSVector2 predictCirclePos = TSVector2.zero;
                        if (Detection.CheckCloseSegement(tableEdges[jj], ball.moveDir))
                        //if (Detection.CheckCloseEdge(tableEdges[jj].start, tableEdges[jj].end, ball.GetPos(), predictEndPos))
                        {
                            //预测是否和边所在平面碰撞
                            if (Detection.CheckCircle_LineContact(tableEdges[jj], run_crd, ref _percent) /*|| Detection.CheckCircle_tableEdgeEndContact(run_crd, tableEdges[jj], ref _percent)*/)
                            {
                                predictCirclePos = ball.PredictPos(leftSyncTime * _percent);
                                if (Detection.CheckCircle_SegementContact(predictCirclePos, tableEdges[jj], ball.radius))//然后检测离真实线段最近的点是否符合要求
                                {
                                    var obj = fastEdgePool.New();
                                    obj.Init(ball, tableEdges[jj], _percent, tableEdges[jj].normal);
                                    baseHits.Add(obj);
                                }
                                else
                                {
                                    _percent = 0;
                                }
                            }
                            else
                            {
                                //TSVector2 nearestPos = TSVector2.zero;
                                //if(Detection.CheckCircle_tableEdgeEndContact(run_crd, tableEdges[jj], ref _percent,ref nearestPos))//检测是否和线段的端点产生了碰撞
                            }
                        }

                        if (Detection._CheckCircle_tableEdgeEndContact(run_crd, tableEdges[jj].start, ref _percent))//检测是否和线段的左端点产生了碰撞
                        {
                            predictCirclePos = ball.PredictPos(leftSyncTime * _percent);
                            if (Detection.CheckCircle_SegementContact(predictCirclePos, tableEdges[jj], ball.radius))//然后检测离真实线段最近的点是否符合要求
                            {
                                var obj = fastEdgePool.New();
                                obj.Init(ball, tableEdges[jj], _percent, (predictCirclePos - tableEdges[jj].start).normalized);
                                baseHits.Add(obj);
                            }
                            else
                            {
                                _percent = 0;
                            }
                        }
                        else if (Detection._CheckCircle_tableEdgeEndContact(run_crd, tableEdges[jj].end, ref _percent))//检测是否和线段的右端点产生了碰撞
                        {
                            predictCirclePos = ball.PredictPos(leftSyncTime * _percent);
                            if (Detection.CheckCircle_SegementContact(predictCirclePos, tableEdges[jj], ball.radius))//然后检测离真实线段最近的点是否符合要求
                            {
                                var obj = fastEdgePool.New();
                                obj.Init(ball, tableEdges[jj], _percent, (predictCirclePos - tableEdges[jj].end).normalized);
                                baseHits.Add(obj);
                            }
                            else
                            {
                                _percent = 0;
                            }
                        }
                        else
                        {
                            _percent = 0;
                        }
                    }
                }



                if (baseHits.Count > 0)
                {
                    var closedHit = baseHits.OrderBy((m) => m.t_percent).First();
                    closedHit.TagProcess();
                    var syncTime = closedHit.t_percent * leftSyncTime;
                    leftSyncTime -= syncTime;
                    if (leftSyncTime <= 0)
                    {
                        leftSyncTime = 0;
                    }
                    if (closedHit.hitType == HitType.Ball)
                    {
                        var _baseHit = closedHit as fastHitBall;
                        //_baseHit.runballObj.CalBallPos(_baseHit.t_percent * _baseHit.runballObj.deltaTime);
                        //_baseHit.staticballObj.CalBallPos(_baseHit.t_percent * _baseHit.staticballObj.deltaTime);
                        updateDirAndTimeByBall(_baseHit.t_percent, _baseHit.runballObj, _baseHit.staticballObj, syncTime);
                    }
                    else if (closedHit.hitType == HitType.Edge)
                    {
                        var _baseHit = closedHit as fastEdge;
                        //_baseHit.ball.CalBallPos(_baseHit.t_percent * _baseHit.ball.deltaTime);
                        //updateDirAndTimeByEdge(_baseHit.t_percent, _baseHit.tbe, _baseHit.ball, syncTime);
                        _updateDirAndTimeByEdge(_baseHit.t_percent, _baseHit.hitNormal, _baseHit.ball, syncTime);
                    }
                    for (int m = 0; m < balls.Count; m++)
                    {
                        var nothitBall = balls[m];
                        if (nothitBall.lockcheck == false)
                        {
                            nothitBall.UpdateBallPos(syncTime);
                        }
                    }
                }
                else
                {
                    for (int n = 0; n < balls.Count; n++)
                    {
                        var nothitBall = balls[n];
                        //if (nothitBall.deltaTime > 0)
                        nothitBall.UpdateBallPos(leftSyncTime);
                    }
                    break;
                }
                run_crdPool.ResetAll();
                fastEdgePool.ResetAll();
                fastHitBallPool.ResetAll();
                UnLockBalls();
            }
            //ClearTestData();
        }