/// <summary> /// Advance the current position some distance on the flight path. /// </summary> /// <param name="distance"></param> /// <param name="destination">position after the advance</param> /// <param name="cCfinalDirection">direction of the segment that the position is on after the advance</param> internal void Advance(CCPoint currentPosition, float distance, out CCPoint destination, out float CCfinalDirection) { int currentIndex = (int)AdvancementAsQuasiIndex; float relativeAdvancementToNextPoint = AdvancementAsQuasiIndex % 1; if (currentIndex == Path.Length - 1) // if you've already reached the end you're done { destination = EndPoint; CCfinalDirection = DirectionAt(currentIndex); return; } float absoluteAdvancementToNextPoint = relativeAdvancementToNextPoint * CCPoint.Distance(Path[currentIndex], Path[currentIndex + 1]); float directionToNextPointInRadians = Constants.CCDegreesToMathRadians(DirectionAt(currentIndex)); float absoluteXAdvancement = absoluteAdvancementToNextPoint * (float)Math.Cos(directionToNextPointInRadians); float absoluteYAdvancement = absoluteAdvancementToNextPoint * (float)Math.Sin(directionToNextPointInRadians); //CCPoint currentPosition = new CCPoint(Path[currentIndex].X + absoluteXAdvancement, Path[currentIndex].Y + absoluteYAdvancement); // try to advance from the current position to the next point on the Path float distanceToNextPoint = CCPoint.Distance(currentPosition, Path[currentIndex + 1]); while (distanceToNextPoint < distance) { currentIndex = currentIndex + 1; currentPosition = Path[currentIndex]; distance -= distanceToNextPoint; AdvancementAsQuasiIndex = currentIndex; if (currentIndex == Path.Length - 1) { break; } distanceToNextPoint = CCPoint.Distance(currentPosition, Path[currentIndex + 1]); } // if you can't go far enough just move towards the point if (distance > 0 && currentIndex != Path.Length - 1) { // update the direction directionToNextPointInRadians = Constants.CCDegreesToMathRadians(DirectionAt(currentIndex)); // calculate how far you can go // relative between the points float relativeAdvanche = distance / distanceToNextPoint; // in x direction float newX = currentPosition.X + distance * (float)Math.Cos(directionToNextPointInRadians); // in y direction float newY = currentPosition.Y + distance * (float)Math.Sin(directionToNextPointInRadians); AdvancementAsQuasiIndex = (float)currentIndex + relativeAdvanche; destination = new CCPoint(newX, newY); CCfinalDirection = Constants.RadiansToCCDegrees(directionToNextPointInRadians); } else { destination = Path[currentIndex]; CCfinalDirection = DirectionAt(currentIndex); } // }
/// <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); }