public void InGameCheck(IBallInternal ball) { foreach (var pocket in c_Pockets) { ball.SetInGameFlag(ball.InGame & Coordinates.Sub(ball.Position, pocket).Module > c_PocketRadius); } }
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); }
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); } } }
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); } } }
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; }
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); }
public Coordinates GetNormalVersor(IBallInternal ball) { return(m_CollidedBalls[ball]); }
public void AddCollidedBall(IBallInternal ball, Coordinates normalVersor) { m_CollidedBalls[ball] = normalVersor; }
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); } } }