Exemplo n.º 1
0
 // dirty, because only the center of the bounding box + all points of the box are used to check the angle;
 // this function is using CCDegrees
 internal static bool CollideArcBoundingBox(CCPoint posCircle, float radius, float angleArcCenter, float angleHalfArcWidth, CCRect box)
 {
     if (CollideBoundingBoxCircle(box, posCircle, radius))
     {
         // check whether the center of the box is inside the arc
         CCPoint vectorCirclePoint = box.Center - posCircle;
         float   anglePoint        = Constants.DxDyToCCDegrees(vectorCirclePoint.X, vectorCirclePoint.Y);
         float   angleDifference   = Constants.AbsAngleDifferenceDeg(angleArcCenter, anglePoint);
         if (angleDifference <= angleHalfArcWidth)
         {
             return(true);
         }
         // check whether a point of the box is inside the arc
         foreach (CCPoint point in Constants.CCRectPoints(box))
         {
             vectorCirclePoint = point - posCircle;
             anglePoint        = Constants.DxDyToCCDegrees(vectorCirclePoint.X, vectorCirclePoint.Y);
             angleDifference   = Constants.AbsAngleDifferenceDeg(angleArcCenter, anglePoint);
             if (angleDifference <= angleHalfArcWidth)
             {
                 return(true);
             }
         }
     }
     return(false);
 }
 /// <summary>
 /// Returns the Direction (in CCDegrees) of the segment
 /// starting at pathIndex and ending at pathIndex +1.
 /// For the Endpoint the same value is returned as for endIndex-1.
 /// </summary>
 /// <param name="pathIndex"></param>
 /// <returns></returns>
 internal float DirectionAt(int pathIndex)
 {
     if (pathIndex == Path.Length - 1)
     {
         pathIndex--;
     }
     return(Constants.DxDyToCCDegrees(Path[pathIndex + 1].X - Path[pathIndex].X, Path[pathIndex + 1].Y - Path[pathIndex].Y));
 }
 /// <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);
     }
 }
 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);
                 }
             }
         }
     }
 }