private void TryFireCannons() { //if (_ai.TimeUntilReloaded > 0 && false) { // return; } // Check that we aren't at too extreme an angle to fire (e.g. don't fire off the bow of the ship) float angleTowardsPlayer = Util.AngleTowards(_h.SelfPos, _h.TargetPos); float relativeAngle = Util.Clamp180(angleTowardsPlayer - _h.Heading); // Angle will be the following: // * 0: Front // * 180: Back // * 0 to 180: Right // * -180 to 0: Left if (Mathf.Abs(relativeAngle) < _h.Settings.MaxFiringAngle || Mathf.Abs(relativeAngle) > 180 - _h.Settings.MaxFiringAngle) { return; } // Check if we are in range, then if necessary, fire float sqrDistance = _h.SqrDistanceTo(_h.TargetPos); if (sqrDistance <= _h.Settings.CannonRange * _h.Settings.CannonRange) { int cannonIndex = relativeAngle <= 0 ? _ai._Caravel.GetNextLeftCannonIndex() : _ai._Caravel.GetNextRightCannonIndex(); var cannon = _ai._Caravel.GetCannon(cannonIndex); if (Time.time - cannon.LastFireTime < _ai._AiSettings.ReloadTime || Time.time - _ai._lastFireTime < _ai._AiSettings.FireInterval) { return; } cannon.LastFireTime = Time.time; _ai._lastFireTime = Time.time; Vector3 spawnPos = cannon.SpawnPos.transform.position; // Basic velocity prediction // Predict how long a cannonball would take to land, if it was shot directly to where the target is right // now. // Then shoot the cannonball to where the target will be in that amount of time // This isn't perfect because technically the amount of time for the cannonball to land is dependent on the // distance to the target, so if we're changing the distance, we'll get a slightly different answer for where // it will land. // To solve this, we run multiple iterations of the prediction and cross our fingers it's close enough Vector3 predictedTargetPos = Vector3.zero; // will be initialized in the for-loop float predictedTime = _ai.PredictCannonballTime(spawnPos, _h.TargetPos, _h.Settings.CannonballSpeed, _h.Settings.CannonballGravity); for (int i = 0; i < 25; i++) { predictedTargetPos = _h.TargetPos + predictedTime * _h.TargetVelocity; predictedTime = _ai.PredictCannonballTime(spawnPos, predictedTargetPos, _h.Settings.CannonballSpeed, _h.Settings.CannonballGravity); } // TODO AI cannonballs inherit AI ship velocity, and update prediction to take this into account GameObject instantiated = Instantiate(_ai._CannonballPrefab, spawnPos, Quaternion.identity); Cannonball cannonball = instantiated.GetComponent <Cannonball>(); cannonball.Gravity = _h.Settings.CannonballGravity; cannonball.Velocity = CalculateCannonballTrajectory(spawnPos, predictedTargetPos, _h.Settings.CannonballSpeed, _h.Settings.CannonballGravity); cannonball.IgnoreCollisions = _h.Self; _ai._Caravel.PlayCannonEffects(cannonIndex); } }