示例#1
0
        private void ComputeSteps()
        {
            var validBalls = m_Balls.Where(b => b.InGame).ToList();

            m_BallSteps.Clear();
            for (int i = 0; i < validBalls.Count; i++)
            {
                var info = new BallStepInfo(double.PositiveInfinity);
                for (int j = i + 1; j < validBalls.Count; j++)
                {
                    CheckBallCollision(ref info, validBalls[i], validBalls[j]);
                }
                m_BallSteps[validBalls[i]] = info;
            }
        }
示例#2
0
        private void HandleBallCollision(IBallInternal ball, BallStepInfo info, Dictionary <IBallInternal, NewVelocity> newVelocities)
        {
            var validBalls = info.CollidedBalls.Where(b => b.InGame);
            //prepare linear system wich solutions gives the impulses
            Matrix A = new Matrix(validBalls.Count());
            Vector B = new Vector(validBalls.Count());

            foreach (var iBall in validBalls.Select((Value, Idx) => new { Value, Idx }))
            {
                var iNorm = info.GetNormalVersor(iBall.Value);
                //build matrix A
                foreach (var jBall in Enumerable.Where(validBalls.Select((Value, Idx) => new { Value, Idx }), e => e.Idx <= iBall.Idx))
                {
                    if (iBall.Idx == jBall.Idx)
                    {
                        A[iBall.Idx, iBall.Idx] = (1 / ball.Mass + 1 / iBall.Value.Mass);
                    }
                    else
                    {
                        var jNorm = info.GetNormalVersor(jBall.Value);
                        A[iBall.Idx, jBall.Idx] = Coordinates.Dot(iNorm, jNorm) / ball.Mass;
                        A[jBall.Idx, iBall.Idx] = A[iBall.Idx, jBall.Idx];
                    }
                }
                //build known terms vector
                B[iBall.Idx] = (1 + Math.Min(iBall.Value.Elasticity, ball.Elasticity)) * Coordinates.Dot(Coordinates.Sub(iBall.Value.Velocity, ball.Velocity), iNorm);
            }
            //solve the system
            var x = LinearSystem.Solve(A, B);

            //apply the impulses
            foreach (var iBall in validBalls.Select((Value, Idx) => new { Value, Idx }))
            {
                var iNorm = info.GetNormalVersor(iBall.Value);
                newVelocities[ball].Value        = Coordinates.Add(newVelocities[ball].Value, x[iBall.Idx] / ball.Mass * iNorm);
                newVelocities[iBall.Value].Value = Coordinates.Sub(newVelocities[iBall.Value].Value, x[iBall.Idx] / iBall.Value.Mass * iNorm);
                iBall.Value.SetHitSomethingFlag(true);
            }
            ball.SetHitSomethingFlag(validBalls.Count() != 0);
        }
示例#3
0
 private void CheckBallCollision(ref BallStepInfo info, IBallInternal first, IBallInternal second)
 {
     if (first.Velocity.Module != 0 || second.Velocity.Module != 0)
     {
         int         N = 0;
         double      distance;
         double      nextDistance;
         double      step;
         Coordinates normal;
         var         tmp = ComponentManager.Cache.Get(first.Position, first.Velocity, first.Friction, second.Position, second.Velocity, second.Friction);
         if (tmp != null)
         {
             int iSteps = (int)Math.Floor(tmp.Step);
             distance     = GeometryUtils.Distance(first.ForeseenPosition(iSteps + 1), second.ForeseenPosition(iSteps + 1));
             nextDistance = GeometryUtils.Distance(first.ForeseenPosition(iSteps + 2), second.ForeseenPosition(iSteps + 2));
             step         = tmp.Step;
             normal       = tmp.Normal;
         }
         else
         {
             nextDistance = GeometryUtils.Distance(first.ForeseenPosition(N), second.ForeseenPosition(N));
             do
             {
                 distance     = nextDistance;
                 nextDistance = GeometryUtils.Distance(first.ForeseenPosition(N + 1), second.ForeseenPosition(N + 1));
                 N++;
             }while (distance > nextDistance && distance.ToleranceGreater(first.Radius + second.Radius));
             N -= 2;
             if (N < 0)
             {
                 step   = 0;
                 normal = Coordinates.Normalize(Coordinates.Sub(second.Position, first.Position));
             }
             else
             {
                 var    p1     = first.ForeseenPosition(N);
                 var    p2     = second.ForeseenPosition(N);
                 var    v1     = first.ForeseenVelocity(N);
                 var    v2     = second.ForeseenVelocity(N);
                 var    deltaP = Coordinates.Sub(p1, p2);
                 var    deltaV = Coordinates.Sub(v1, v2);
                 var    a      = Coordinates.Dot(deltaV, deltaV);
                 var    b      = 2 * Coordinates.Dot(deltaP, deltaV);
                 var    c      = Coordinates.Dot(deltaP, deltaP) - Math.Pow(first.Radius + second.Radius, 2);
                 var    t1     = (-b + Math.Sqrt(b * b - 4 * a * c)) / (2 * a);
                 var    t2     = (-b - Math.Sqrt(b * b - 4 * a * c)) / (2 * a);
                 double t      = (t1.ToleranceGreaterEqual(0) && t2.ToleranceGreaterEqual(0)) ? Math.Min(t1, t2) : (t1.ToleranceGreaterEqual(0) ? t1 : (t2.ToleranceGreaterEqual(0) ? t2 : 0));
                 step   = N + t;
                 normal = Coordinates.Normalize(Coordinates.Sub(Coordinates.Add(p2, t * v2), (Coordinates.Add(p1, t * v1))));
             }
             ComponentManager.Cache.Add(step, normal, Coordinates.Zero, first.Position, first.Velocity, first.Friction, second.Position, second.Velocity, second.Friction);
         }
         if (distance.ToleranceLessEqual(first.Radius + second.Radius) && ((step.ToleranceGreater(0) && step.ToleranceLessEqual(info.Step)) || (step.ToleranceEqual(0) && distance > nextDistance)))
         {
             if (!step.ToleranceEqual(info.Step))
             {
                 info = new BallStepInfo(step);
             }
             info.AddCollidedBall(second, normal);
         }
     }
 }