Пример #1
0
        public CCMyRotateToState(CCMyRotateTo action, CCNode target)
            : base(action, target)
        {
            FinalAngle = action.FinalAngle;
            StartAngle = ((IGameObject)target).MyRotation;

            // Now we work out how far we actually have to rotate
            DiffAngle = Constants.AngleFromToDeg(StartAngle, FinalAngle);
        }
Пример #2
0
        public void RotateTowards(float angle, float maxRotationAngle)
        {
            float currentRotation = MyRotation;
            float difference      = Constants.AngleFromToDeg(currentRotation, angle);

            if ((float)Math.Abs(difference) <= maxRotationAngle)
            {
                MyRotation = angle;
            }
            else
            {
                MyRotation += maxRotationAngle * Math.Sign(difference);
            }
        }
        /// <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);
        }
 internal void PartsInRange(out List<Part> partsInRange, out List<float> anglesFromTo, out List<float> distances)
 {
     // collect aircrafts that are near enough to have parts which could be targets
     List<Aircraft> aircraftsInRange = new List<Aircraft>();
     foreach (var aircraft in (MyPart.Aircraft.Team == Team.PlayerTeam ? ((PlayLayer)MyPart.Layer).ActiveAircrafts : ((PlayLayer)MyPart.Layer).PlayerAircrafts))   // a bit dirty since technically NPC allies to the player could exist (someday), which would not be contained in PlayerAircrafts, but which would still (maybe) be part of the player team
     {
         // check if it is considered an enemy
         if (!MyPart.Aircraft.Team.IsEnemy(aircraft.Team) || aircraft.MyState.Equals(Aircraft.State.SHOT_DOWN))
             continue;
         // check if in attention arc
         if (Collisions.CollideArcBoundingBox(MyPart.PositionWorldspace, AttentionRange, MyPart.TotalNullRotation, AttentionAngle, aircraft.BoundingBoxTransformedToWorld))
             aircraftsInRange.Add(aircraft);
     }
     partsInRange = new List<Part>();
     anglesFromTo = new List<float>();
     distances = new List<float>();
     foreach (var aircraft in aircraftsInRange)
     {
         foreach (var part in aircraft.TotalParts)
         {
             if (part.MyState == Part.State.DESTROYED) continue;
             // using the position as criterium is a bit dirty and could be improved on by using the bounding box instead (at the cost of performance)
             CCPoint vectorMyPartPart = part.PositionWorldspace - MyPart.PositionWorldspace;
             float distance = vectorMyPartPart.Length;
             if (distance <= AttentionRange)
             {
                 var angleFromTo = Constants.AngleFromToDeg(MyPart.TotalRotation - MyPart.RotationFromNull, Constants.DxDyToCCDegrees(vectorMyPartPart.X, vectorMyPartPart.Y));
                 if ((float)Math.Abs(angleFromTo) <= AttentionAngle)
                 {
                     partsInRange.Add(part);
                     anglesFromTo.Add(Constants.AngleFromToDeg(MyPart.TotalRotation, Constants.DxDyToCCDegrees(vectorMyPartPart.X, vectorMyPartPart.Y)));
                     distances.Add(distance);
                 }
             }
         }
     }
 }
 /// <summary>
 /// called by the Aircraft owning the part owning this WeaponAbility each frame
 /// </summary>
 /// <param name="dt">time since the previous frame</param>
 internal void ExecuteOrders(float dt)
 {
     // cool down
     CooldownUntilNextShot -= dt;
     CooldownUntilNextTargetUpdate -= dt;
     if (CooldownUntilNextShot < 0) CooldownUntilNextShot = 0;
     // if you have a target check if it is still in range
     if (TargetPart != null)
     {
             CCPoint vectorMyPartTarget = TargetPart.PositionWorldspace - MyPart.PositionWorldspace;
             if (TargetPart.MyState == Part.State.DESTROYED || (TargetAircraft != null && TargetAircraft.MyState == Aircraft.State.SHOT_DOWN)
                 || CooldownUntilNextTargetUpdate <= 0
                 || CCPoint.Distance(MyPart.PositionWorldspace, TargetPart.PositionWorldspace) > AttentionRange
                 || Constants.AbsAngleDifferenceDeg(MyPart.TotalRotation - MyPart.RotationFromNull, Constants.DxDyToCCDegrees(vectorMyPartTarget.X, vectorMyPartTarget.Y)) > AttentionAngle)
                 TargetPart = null;
     }
     if (TargetPart == null && CooldownUntilNextTargetUpdate <= 0)     // if you currently do not aim at anything search for a target
     {
         CooldownUntilNextTargetUpdate = UpdateTargetDelay;
         // collect aircrafts that are near enough to have parts which could be targets
         // go through the parts of all of these planes and collect those that are in the attention angle
         PartsInRange(out List<Part> partsInRange, out List<float> anglesFromTo, out List<float> distances);
         // try to choose a part that is in reach
         // choose the part that is closest anglewise
         // but prioritize aircraft bodies:
         //  this means that you should only change target from a body to another part if the part you would choose instead (because it's closer)
         //  belongs to another plane
         float minAngle = float.PositiveInfinity;
         for (int i=0; i<partsInRange.Count(); i++)
         {
             if (distances[i] <= ShootingRange)  // first only try parts that are already in reach
             {
                 float absAngle = (float)Math.Abs(anglesFromTo[i]);
                 var part = partsInRange[i];
                 if (absAngle < minAngle) //&&
                     //(TargetPart == null || !(part.Parent == TargetPart.Parent && TargetPart == TargetAircraft.Body)))  // don't switch from a body to a different part of the same aircraft
                 {
                     TargetPart = part;
                     minAngle = absAngle;
                 }
             }
         }
         if (TargetPart == null) // if you found no target this way check the rest
         {
             minAngle = float.PositiveInfinity;
             for (int i = 0; i < partsInRange.Count(); i++)
             {
                 float absAngle = (float)Math.Abs(anglesFromTo[i]);
                 var part = partsInRange[i];
                 // now also try parts that are not already in reach
                 if (absAngle < minAngle) //&&
                     //(TargetPart == null || !(part.Parent == TargetPart.Parent && TargetPart == TargetAircraft.Body)))  // don't switch from a body to a different part of the same aircraft
                 {
                     TargetPart = part;
                     minAngle = absAngle;
                 }
             }
         }
     }
     // calculate the perfect point to aim for in order to hit the target
     if (TargetPart != null)
     {
         float angleToAimFor = AngleToAimFor();
         if (!(MyPart is WingJet))   // a dirty fix to make sure jet wings don't rotate since rotation screws up the flip state; for other weapons this effect can be neglected since it is only visual
         {
             float angleToTurnTo = angleToAimFor;
             float angleTurn = Constants.AngleFromToDeg(MyPart.NullRotation, angleToTurnTo);
             // make sure you don't rotate further than your MountPoint allows
             if (angleTurn > MyPart.MountPoint.MaxTurningAngle)
                 angleToTurnTo = MyPart.NullRotation + MyPart.MountPoint.MaxTurningAngle;
             else if (angleTurn < -MyPart.MountPoint.MaxTurningAngle)
                 angleToTurnTo = MyPart.NullRotation - MyPart.MountPoint.MaxTurningAngle;
             // make sure you don't rotate further than this weapons MaxTurningAngle allows
             if (MaxTurningAngle < MyPart.MountPoint.MaxTurningAngle)
             {
                 if (angleTurn > MaxTurningAngle)
                     angleToTurnTo = MyPart.NullRotation + MaxTurningAngle;
                 else if (angleTurn < -MaxTurningAngle)
                     angleToTurnTo = MyPart.NullRotation - MaxTurningAngle;
             }
             MyPart.RotateTowards(angleToTurnTo, TurningAnglePerSecond * dt);
         }
         // if you're now close enough to the perfect angle (and in range) start shooting
         if (CanShoot()
             && CCPoint.Distance(MyPart.PositionWorldspace, TargetPart.PositionWorldspace) <= ShootingRange
             && (Constants.AbsAngleDifferenceDeg(angleToAimFor, MyPart.MyRotation) <= ToleratedError || WouldHit()))
         {
             TryShoot();
         }
             
     }
     // and if you have no target try to get back to NullRotation
     else if (!(MyPart is WingJet))
     {
         MyPart.RotateTowards(MyPart.NullRotation, TurningAnglePerSecond * dt);
     }
 }
 private float AircraftVelocityBoost()
 {
     return MyPart.Aircraft.VelocityVector.Length * (float)Math.Cos(Constants.CCDegreesToMathRadians(Constants.AngleFromToDeg(MyPart.TotalRotation, MyPart.Aircraft.TotalRotation)));
 }