internal void PrepareForPlanningPhase(PlayLayer pl) { // first check the aggro // i.e. if an enemy (i.e. a player aircraft) is close enough break formation // also if one of the aircrafts is damaged break formation too if (InFormation) { foreach (var aircraft in pl.PlayerAircrafts) { if (CCPoint.Distance(aircraft.Position, Position) < AggroRange) { //Console.WriteLine("TRIGGERED - DISTANCE"); InFormation = false; break; } } foreach (var aircraft in AircraftsWithRelPositions.Keys) { if (aircraft.Health < aircraft.MaxHealth) { //Console.WriteLine("TRIGGERED - HP"); InFormation = false; break; } } } foreach (var aircraft in AircraftsWithRelPositions.Keys) { aircraft.PrepareForPlanningPhase(); } if (!InFormation) { return; // squadrons only control their units while in formation } //Console.WriteLine("FLYING IN FORMATION"); const float dt = Constants.TURN_DURATION; // if you're too close to the current Waypoint roll a new one var diff = WayPoint - Leader.Position; float advanceDistance = Velocity * dt; if (diff.Length < advanceDistance) { GenerateWayPoint(); diff = WayPoint - Leader.Position; } LeaderWayPoint = Leader.Position + CCPoint.Normalize(diff) * advanceDistance; // rotate all formation positions correctly around the leader and tell everyone to go to their positions float angle = Constants.DxDyToRadians(diff.X, diff.Y); foreach (var entry in AircraftsWithRelPositions) { var formationPoint = CCPoint.RotateByAngle(entry.Value, CCPoint.Zero, angle); var yourWaypoint = LeaderWayPoint + formationPoint; entry.Key.TryToSetFlightPathHeadTo(yourWaypoint); } }
/// <summary> /// Returns the (relative) rotation angle (for MyRotation) indicating how far into which direction the weapon /// should be turned to be able to hit the target perfectly. /// </summary> /// <returns></returns> internal float AngleToAimFor() { // as there is no exact solution the solution is here approched by iteration CCPoint TargetToMyPart = MyPart.PositionWorldspace - TargetPart.PositionWorldspace; // rotate the vector, so that the movement direction of the target is identical to the x axis float transformationRotation = -Constants.DxDyToRadians(TargetAircraft.VelocityVector.X, TargetAircraft.VelocityVector.Y); TargetToMyPart = CCPoint.RotateByAngle(TargetToMyPart, CCPoint.Zero, transformationRotation); // now the cordinate system is simpler and we can compute the difference between // a) the intersection of the flight path and the bullet path // and b) the point where the target actually is going to be by then // of course we want to minimize this error, for this we will iterate // ITERATION USING THE BISECTION METHOD double epsilon = 1; double angle = 0; // define the interval double startAngle = Constants.DxDyToRadians(-TargetToMyPart.X, -TargetToMyPart.Y); double endAngle = 0; float totalBulletVelocity = ProjectileBlueprint.Velocity + AircraftVelocityBoost(); double deltaStart = TargetToMyPart.X - TargetToMyPart.Y / Math.Tan(startAngle) + (TargetToMyPart.Y * TargetAircraft.VelocityVector.Length) / (Math.Sin(startAngle) * totalBulletVelocity); for (int i = 0; i < 6; i++) // iterate 6 times at max { angle = (startAngle + endAngle) / 2; double delta = TargetToMyPart.X - TargetToMyPart.Y / Math.Tan(angle) + (TargetToMyPart.Y * TargetAircraft.VelocityVector.Length) / (Math.Sin(angle) * totalBulletVelocity); if (Math.Abs(delta) < epsilon) // you're close enough so break already break; // delta is negative when the bullet hits behind the part -> angle needs to be closer to 0 if (Math.Sign(deltaStart) == Math.Sign(delta)) { startAngle = angle; deltaStart = delta; } else { endAngle = angle; } } // subtract the transformation rotation to get the total angle float totalAngle = Constants.RadiansToCCDegrees((float)angle - transformationRotation); // for the final angle transform the total angle to a relative angle return Constants.AngleFromToDeg(((IGameObject)MyPart.Parent).TotalRotation, totalAngle); }