示例#1
0
 public void InGameCheck(IBallInternal ball)
 {
     foreach (var pocket in c_Pockets)
     {
         ball.SetInGameFlag(ball.InGame & Coordinates.Sub(ball.Position, pocket).Module > c_PocketRadius);
     }
 }
示例#2
0
        public BankStepInfo ComputeStep(IBallInternal ball)
        {
            BankStepInfo res = new BankStepInfo(double.PositiveInfinity, Coordinates.Zero, Coordinates.Zero);

            foreach (var bank in c_Banks)
            {
                var tmp = ComponentManager.Cache.Get(bank, ball.Position, ball.Velocity, ball.Friction);
                if (tmp != null)
                {
                    res = new BankStepInfo(tmp.Step, tmp.Normal, tmp.Tangent);
                }
                else
                {
                    UpdateStep(ref res, bank, ball);
                    ComponentManager.Cache.Add(res.Step, res.NormalVersor, res.TangentVersor, bank, ball.Position, ball.Velocity, ball.Friction);
                }
            }
            foreach (var corner in c_BankCorners.Where((c, i) => IsCornerValidForCollision(i)))
            {
                var tmp = ComponentManager.Cache.Get(corner, ball.Position, ball.Velocity, ball.Friction);
                if (tmp != null)
                {
                    res = new BankStepInfo(tmp.Step, tmp.Normal, tmp.Tangent);
                }
                else
                {
                    UpdateStep(ref res, corner, ball);
                    ComponentManager.Cache.Add(res.Step, res.NormalVersor, res.TangentVersor, corner, ball.Position, ball.Velocity, ball.Friction);
                }
            }
            return(res);
        }
示例#3
0
        private void UpdateStep(ref BankStepInfo info, ICoordinates corner, IBallInternal ball)
        {
            double distance = double.PositiveInfinity;
            int    N        = -1;

            while (distance > ball.Radius)
            {
                N++;
                double newDistance = GeometryUtils.Distance(ball.ForeseenPosition(N), corner);
                if (newDistance >= distance)
                {
                    return;
                }
                else
                {
                    distance = newDistance;
                }
            }
            N--;
            var    p            = ball.ForeseenPosition(N);
            var    v            = ball.ForeseenVelocity(N);
            double a            = v.X * (corner.X - p.X) + v.Y * (corner.Y - p.Y);
            double c            = Math.Pow(v.X, 2) + Math.Pow(v.Y, 2);
            double b            = Math.Sqrt(Math.Pow(a, 2) - c * (Math.Pow(corner.X - p.X, 2) + Math.Pow(corner.Y - p.Y, 2) - Math.Pow(ball.Radius, 2)));
            double t1           = (a + b) / c;
            double t2           = (a - b) / c;
            double t            = (t1.Between(0, 1) ? (t2.Between(0, 1) ? Math.Min(t1, t2) : t1) : (t2.Between(0, 1) ? t2 : double.PositiveInfinity));
            var    ballCenter   = Coordinates.Add(p, t * v);
            var    contactPoint = Coordinates.Add(ballCenter, Coordinates.Sub(corner, ballCenter));

            if (!CheckCenterPoint(ballCenter, ball.Radius) || !CheckContactPoint(contactPoint))
            {
                return;
            }
            double step = N + t;

            if (!step.ToleranceEqual(0) && step.ToleranceLessEqual(info.Step))
            {
                if (step < info.Step)
                {
                    var normal  = Coordinates.Normalize(Coordinates.Sub(p, corner));
                    var tangent = new Coordinates(module: 1, phase: normal.Phase + 90);
                    info = new BankStepInfo(step, normal, tangent);
                }
            }
        }
示例#4
0
        private void UpdateStep(ref BankStepInfo info, Line2 bank, IBallInternal ball)
        {
            double distance = double.PositiveInfinity;
            int    N        = -1;

            while (distance > ball.Radius)
            {
                N++;
                double newDistance = GeometryUtils.Distance(ball.ForeseenPosition(N), bank);
                if (newDistance >= distance)
                {
                    return;
                }
                else
                {
                    distance = newDistance;
                }
            }
            N--;
            var    p            = ball.ForeseenPosition(N);
            var    v            = ball.ForeseenVelocity(N);
            double a            = bank.A * p.X + bank.B * p.Y + bank.C;
            double b            = ball.Radius * Math.Sqrt(Math.Pow(bank.A, 2) + Math.Pow(bank.B, 2));
            double c            = bank.A * v.X + bank.B * v.Y;
            double t1           = (-a + b) / c;
            double t2           = (-a - b) / c;
            double t            = (t1.Between(0, 1) ? (t2.Between(0, 1) ? Math.Min(t1, t2) : t1) : (t2.Between(0, 1) ? t2 : double.PositiveInfinity));
            var    ballCenter   = Coordinates.Add(p, t * v);
            var    contactPoint = Coordinates.Add(ballCenter, -ball.Radius * bank.NormalVersor);

            if (!CheckCenterPoint(ballCenter, ball.Radius) || !CheckContactPoint(contactPoint))
            {
                return;
            }
            double step = N + t;

            if (!step.ToleranceEqual(0) && step.ToleranceLessEqual(info.Step))
            {
                if (step < info.Step)
                {
                    info = new BankStepInfo(step, bank.NormalVersor, bank.Versor);
                }
            }
        }
示例#5
0
文件: Ball.cs 项目: Anubi85/PoolAI
 public Ball(BallGraphicsData graphicsData, BallPhysicsData physicsData, ITableInternal table, Coordinates startPosition)
 {
     m_GraphicsData  = graphicsData;
     m_PhysicsData   = physicsData;
     m_Table         = table;
     m_BallInterface = this;
     m_InGame        = true;
     m_Position      = startPosition;
     m_Velocity      = Coordinates.Zero;
     m_DrawingOffset = new Coordinates(m_Table.Width / 2, m_Table.Height / 2);
     Coordinates.MakeReadonly(m_DrawingOffset);
     m_BallDrawingOffset = new Coordinates(m_PhysicsData.Radius, m_PhysicsData.Radius);
     Coordinates.MakeReadonly(m_BallDrawingOffset);
     m_StripedRadius        = (int)Math.Ceiling(m_PhysicsData.Radius * m_GraphicsData.StripedRadiusCoefficient);
     m_StripedDiameter      = 2 * m_StripedRadius;
     m_StripedDrawingOffset = new Coordinates(m_StripedRadius, m_StripedRadius);
     Coordinates.MakeReadonly(m_StripedDrawingOffset);
     m_DirectionUpdated = false;
 }
示例#6
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);
        }
示例#7
0
 public Coordinates GetNormalVersor(IBallInternal ball)
 {
     return(m_CollidedBalls[ball]);
 }
示例#8
0
 public void AddCollidedBall(IBallInternal ball, Coordinates normalVersor)
 {
     m_CollidedBalls[ball] = normalVersor;
 }
示例#9
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);
         }
     }
 }