protected Vector2 GetWhiteBallDesiredPosition(Ball targetBall, Vector2 pocketCenter) { Vector2 pocketToBallDirection = targetBall.Center - pocketCenter; pocketToBallDirection.Normalize(); Vector2 whiteCenterTarget = targetBall.Center + 2 * Ball.Radius * pocketToBallDirection; return whiteCenterTarget; }
private Vector2 GetClosestBallWithoutCollisions(Ball whiteBall) { Vector2 result = new Vector2(-1, -1); float minDistance = float.MaxValue; for (int i = 1; i < pool.Balls.Count; i++) { Ball ball = pool.Balls[i]; if (ball.Inserted || !IsPlayersBall(ball)) { continue; } float distanceToWhite = Vector2.Distance(whiteBall.Center, ball.Center); Vector2 pocket = GetClosestPocketCenter(ball); if (pocket.X == -1 && pocket.Y == -1) // the default false value { continue; } Vector2 imaginaryTargetCenter = GetWhiteBallDesiredPosition(ball, pocket); Ball imaginaryBall = new Ball(imaginaryTargetCenter, 100, false); if (minDistance > distanceToWhite && !HasCollision(whiteBall, imaginaryBall)) { minDistance = distanceToWhite; result = imaginaryBall.Center; } } return result; }
public static bool DoesBallCollideWithOtherBall(Ball ball, Ball otherBall, out double collisionTime, Vector2 ballDir, Vector2 otherBallDir, float ballSpeed, float otherBallSpeed) { collisionTime = double.MaxValue; double dx = ball.Center.X - otherBall.Center.X; double dy = ball.Center.Y - otherBall.Center.Y; double dvx = ballDir.X * ballSpeed - otherBallDir.X * otherBallSpeed; double dvy = ballDir.Y * ballSpeed - otherBallDir.Y * otherBallSpeed; double r1 = Ball.Radius; double r2 = Ball.Radius; double d = (dx * dvx + dy * dvy) * (dx * dvx + dy * dvy) - (dvx * dvx + dvy * dvy) * (dx * dx + dy * dy - (r1 + r2) * (r1 + r2)); if (d > 0.00005) { double t1 = -(dx * dvx + dy * dvy - Math.Sqrt(d)) / (dvx * dvx + dvy * dvy); double t2 = -(dx * dvx + dy * dvy + Math.Sqrt(d)) / (dvx * dvx + dvy * dvy); if (t1 > 0 || t2 > 0) { if (t1 < collisionTime) { collisionTime = t1; } if (t2 < collisionTime) { collisionTime = t2; } return true; } } return false; }
protected Ball ChooseClosestBallFromRange(Ball whiteBall, int rangeStart, int rangeEnd) { if (player.ShouldPotBlack(pool.Balls)) { return pool.Balls[8]; // this is the black ball } Ball result = null; float minDistance = float.MaxValue; for (int i = rangeStart; i < rangeEnd; i++) { if (i == 8) { continue; } if (pool.Balls[i].Inserted) { continue; } float distanceToWhite = Vector2.Distance(whiteBall.Center, pool.Balls[i].Center); if (minDistance > distanceToWhite) { result = pool.Balls[i]; minDistance = distanceToWhite; } } return result; }
private bool HasCollisionWithBall(Ball whiteBall, Ball targetBall, Ball possibleObstruction) { double time; Vector2 whiteBallDirection = targetBall.Center - whiteBall.Center; whiteBallDirection.Normalize(); bool result = Physics.DoesBallCollideWithOtherBall(whiteBall, possibleObstruction, out time, whiteBallDirection, Vector2.Zero, 500, 0); return result; }
protected bool IsPlayersBall(Ball ball) { if (player.ShouldPotBlack(pool.Balls)) { return ball.Number == 8; } if (player.BallTypeChosen == BallType.None) { return ball.Number != 8 && ball.Number != 0; } if (player.BallTypeChosen == BallType.Solids) { return ball.Number < 8 && ball.Number > 0; } return ball.Number > 8; }
protected Vector2 GetClosestPocketCenter(Ball ball) { Vector2 result = new Vector2(-1,-1); float minDistance = Vector2.Distance(ball.Center, result); foreach (Vector2 pocket in pool.PocketCentres) { float currentDistance = Vector2.Distance(ball.Center, pocket); float distanceToWhite = Vector2.Distance(pool.Balls[0].Center, pocket); if (currentDistance < minDistance && distanceToWhite > currentDistance && GetCosAngle(pool.Balls[0].Center, ball.Center, pocket) < -0.4) { result = pocket; minDistance = currentDistance; } } return result; }
private bool HasCollision(Ball whiteBall, Ball target) { double distanceToTarget = Vector2.DistanceSquared(whiteBall.Center, target.Center); for (int i = 1; i < pool.Balls.Count; i++) { Ball loopBall = pool.Balls[i]; if (loopBall.Inserted || loopBall.Number == target.Number) { continue; } double distanceToLoopBall = Vector2.DistanceSquared(loopBall.Center, whiteBall.Center); if (HasCollisionWithBall(whiteBall, target, loopBall) && distanceToLoopBall < distanceToTarget) { return true; } } return false; }
private void DrawBall(Ball theBall, Color ballColor) { spriteBatch.Begin(); Vector2 ballCenter = new Vector2(theBall.Center.X - Ball.Radius, theBall.Center.Y - Ball.Radius); spriteBatch.Draw(ball, ballCenter, ballColor); // drawing numbers for debug purposes. //spriteBatch.DrawString(tahoma, theBall.Number.ToString(), ballCenter, Color.Green); spriteBatch.End(); }
float IntersectWithWalls(Ball ball, out Side side) { side = null; float minu = -1; for (int i = 0; i < Sides.Count; i++) { float x1 = ball.Center.X; float y1 = ball.Center.Y; float x2 = ball.Center.X + ball.Dir.X; float y2 = ball.Center.Y + ball.Dir.Y; float x3 = Sides[i].p1.X; float y3 = Sides[i].p1.Y; float x4 = Sides[i].p2.X; float y4 = Sides[i].p2.Y; if ((x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4) == 0) { continue; } float px = ((x1 * y2 - y1 * x2) * (x3 - x4) - (x1 - x2) * (x3 * y4 - y3 * x4)) / ((x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4)); float py = ((x1 * y2 - y1 * x2) * (y3 - y4) - (y1 - y2) * (x3 * y4 - y3 * x4)) / ((x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4)); float u = (px - ball.Center.X) / (ball.Dir.X); if (Math.Abs(ball.Dir.X) < Math.Abs(ball.Dir.Y) || (Math.Abs(u) < 0.0005 && u < 0 && ball.Dir.Y != 0)) { u = (py - ball.Center.Y) / (ball.Dir.Y); } float t = (px - x3) / (x4 - x3); if (x4 == x3) { t = (py - y3) / (y4 - y3); } if (u < -0.00001 || t < 0 || t > 1.000005) { continue; } if (Math.Abs(u) < 0.00001) { u = 0; Vector2 sidev = new Vector2(x4 - x3, y4 - y3); Vector2 next = sidev + ball.Dir; if (Utilities.Cross(sidev, next) < 0) { continue; } } if (minu == -1 || u < minu) { side = Sides[i]; minu = u; } } return Math.Max((ball.Dir.Length() * minu) / ball.Speed, 0); }
float IntersectWithBalls(Ball ball, out Ball firstColidingBall) { firstColidingBall = null; double firstBallCollisionTime = 1e50; for (int i = 0; i < Balls.Count; i++) { if (ball.Number == Balls[i].Number || Balls[i].Inserted) { continue; } double currentBallCollisionTime; if (Physics.DoesBallCollideWithOtherBall(ball, Balls[i], out currentBallCollisionTime)) { if (currentBallCollisionTime < firstBallCollisionTime) { firstBallCollisionTime = currentBallCollisionTime; firstColidingBall = Balls[i]; } } } return (float)Math.Max(firstBallCollisionTime, 0.001); }
void InsertedBall(Ball ball) { ballPotted = true; if (Player1.IsOnTurn) { HandleBallPotted(ball, Player1, Player2); } else { HandleBallPotted(ball, Player2, Player1); } }
private void HandleBallPotted(Ball ball, Player playerOnTurn, Player otherPlayer) { if (ball.Number == 0) // the white ball has been potted { shouldSwitchPlayers = true; Fault = true; return; } if (ball.Number == 8) // the black ball has been potted { if (playerOnTurn.ShouldPotBlack(Balls)) { playerOnTurn.Won = true; otherPlayer.Won = false; } else { playerOnTurn.Won = false; otherPlayer.Won = true; } } if (playerOnTurn.BallTypeChosen == BallType.None) // noone has potted a ball yet { if (ball.Number > 8) // a striped ball has been potted { playerOnTurn.BallTypeChosen = BallType.Stripes; otherPlayer.BallTypeChosen = BallType.Solids; } else // a solid ball has been potted { playerOnTurn.BallTypeChosen = BallType.Solids; otherPlayer.BallTypeChosen = BallType.Stripes; } } else if (playerOnTurn.BallTypeChosen == BallType.Solids) // the player should pot solids { if (ball.Number > 8) // the player potted stripe ball { shouldSwitchPlayers = true; Fault = true; } } else // the player should pot stripes { if (ball.Number < 8) // the player potted solid { shouldSwitchPlayers = true; Fault = true; } } }
public static bool DoesBallCollideWithOtherBall(Ball ball, Ball otherBall, out double collisionTime) { return DoesBallCollideWithOtherBall(ball, otherBall, out collisionTime, ball.Dir, otherBall.Dir, ball.Speed, otherBall.Speed); }
protected void PlaceWhiteBall(Ball whiteBall) { // Hardcoded position for the white ball; whiteBall.Center = new Vector2(200, 200); whiteBall.Inserted = false; }