/// <summary> /// Passes the ball to the cursor by rolling it around the ground /// The ball's velocity at arrival is given by Constants.ShortPassDesiredVelocityAtArrival. /// </summary> private void KickShortPass() { // NOTE: Works, but isn't optimized. Fix as necessary. // Take cursor location and obtain the vector pointing toward (relative to the position of the ball). Coords clicked = PixelUnderMousecursor(); Vector3d clickedVector = new Vector3d(clicked.X, clicked.Y, 0); Vector2d test0 = new Vector2d(clicked.X - _ball.Position3d.X, clicked.Y - _ball.Position3d.Y); // Proximity check. if (test0.Length() < Constants.TargetCheckTolerance) { // target too close. just nudge the ball. _ball.Kick(new Vector3d(test0.X, test0.Y, 0), Constants.ShortPassDefaultSpin, null); } // Scale velocity vector test0.ScaleToLength(1); // NOTE: // The calibration works as follows: // We start with a velocity vector of magnitude 1 aimed in the correct direction. // We obtain the magnitude of the ball's velocity at arrival at the target (0 = didn't arrive). // We scale the velocity vector as necessary. The scaling is linear, defined by Constants.ShortPassCalibrationSensitivity. // If the target is too far, we use the Constants.ShortPassMaxVelocity loop stopping condition. // WARMING: This algo assumes the ShortPassDefaultSpin is 0. With spin, once has to alter the algo // in a way similar to the alteration for the Lob calibration. // Definet he calibrator ball and its helper variables, and do the first cycle of the loop BallCalibrator calibrator = new BallCalibrator(_ball); calibrator.Kick(new Vector3d(test0.X, test0.Y, 0), Constants.ShortPassDefaultSpin); double testResult = calibrator.VelocityMagnitudeAtTarget(clickedVector); double difference = this._shotPower - testResult; double length = test0.Length(); // Loop until the desired velocity has been found. while (difference > Constants.ShortPassDesiredVelocityAtArrivalTolerance && length < Constants.ShortPassMaxVelocity) { calibrator.SpawnAt(new Vector2d(_ball.Position3d.X, _ball.Position3d.Y)); length = test0.Length(); test0.ScaleToLength(test0.Length() + Constants.ShortPassCalibrationSensitivity); calibrator.Kick(new Vector3d(test0.X, test0.Y, 0), Constants.ShortPassDefaultSpin); testResult = calibrator.VelocityMagnitudeAtTarget(clickedVector); difference = this._shotPower - testResult; } // Kick ball. _ball.Kick(new Vector3d(test0.X, test0.Y, 0), Constants.ShortPassDefaultSpin, null); }
/// <summary> /// Projects the ball's travel path until stopping. /// </summary> private void ConstructProjection() { // clear old projection _projection.Clear(); BallCalibrator calibrator = new BallCalibrator(this); calibrator.Kick(this._velocity, new Vector3d(0, 0, 0)); calibrator.Spin3d = _spin3d; // to bypass the spin realignment. do this more cleverly later. int j = 0; while (calibrator.Velocity.Length() > 0 && j < Constants.ProjectionMaxLength) { calibrator.UpdateMotion3D(); _projection.Add(calibrator.Position3d); ++j; } _projection.Reverse(); }
/// <summary> /// Lobs the ball so it bounces at the cursor. Spin is defined by Constants.LobDefaultSpin. /// </summary> private void KickLob(Ball ball, Vector3d target, Vector3d spinner) { Vector3d spin = new Vector3d(0, spinner.Y, spinner.Z); //Vector3d spin = Constants.LobDefaultSpin; Vector3d clickedVector = new Vector3d(target.X, target.Y, 0); Vector2d test0 = new Vector2d(target.X - ball.Position3d.X, target.Y - ball.Position3d.Y); double distanceToTarget = test0.Length(); // Proximity check. if (distanceToTarget < Constants.TargetCheckTolerance) { // target too close. just nudge the ball. ball.Kick(new Vector3d(test0.X, test0.Y, Constants.LobLiftCoefficient * test0.Length()), spin, _owner); } // Scale velocity vector test0.ScaleToLength(1); // NOTE: // The calibration works as follows: // We start with a velocity vector of magnitude 1 aimed toward the goal. // We obtain the position where the ball bounces. // We compare the distance to bounce with the distance to target. // We scale the velocity vector as necessary. The scaling is linear, defined by Constants.ShortPassCalibrationSensitivity. // If the target is too far, we use the Constants.ShortPassMaxVelocity loop stopping condition. // After we have the desired kick strength, we rotate the kick vector to align the bounce position with the target. // Definet he calibrator ball and its helper variables, and do the first cycle of the loop BallCalibrator calibrator = new BallCalibrator(ball); calibrator.Kick(new Vector3d(test0.X, test0.Y, Constants.LobLiftCoefficient * test0.Length()), spin); Vector3d landing = calibrator.BallPositionAtBounce(); Vector3d vectorToLanding = landing - ball.Position3d; double distanceMagnitude = vectorToLanding.Length(); double difference = distanceMagnitude - distanceToTarget; // Loop until the desired velocity has been found. while (Math.Abs(difference) > Constants.LobTargetCheckTolerance && test0.Length() < Constants.LobMaxVelocity) { calibrator.SpawnAt(new Vector2d(ball.Position3d.X, ball.Position3d.Y)); //length = difference.Length(); test0.ScaleToLength(test0.Length() + Constants.LobCalibrationSensitivity); calibrator.Kick(new Vector3d(test0.X, test0.Y, Constants.LobLiftCoefficient * test0.Length()), spin); landing = calibrator.BallPositionAtBounce(); vectorToLanding = landing - ball.Position3d; distanceMagnitude = vectorToLanding.Length(); difference = distanceMagnitude - distanceToTarget; } // If necessary, rotate to align with target. if (spin.Z != 0) { double angleOfRotation = (new Vector2d(landing.X - ball.Position3d.X, landing.Y - ball.Position3d.Y)). AngleBetween(new Vector2d(clickedVector.X - ball.Position3d.X, clickedVector.Y - ball.Position3d.Y)); test0 = test0.Rotate(angleOfRotation); } // Kick the ball. _owner.KickBall(new Vector3d(test0.X, test0.Y, Constants.LobLiftCoefficient * test0.Length()), spin); }