Exemplo n.º 1
0
        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);
        }