From 2d4bad66aeea97ef9a59f70ac87da98c83daee55 Mon Sep 17 00:00:00 2001 From: portablestew <20881580+portablestew@users.noreply.github.com> Date: Fri, 11 Jan 2019 20:31:06 -0800 Subject: [PATCH] Fix for #7083: Fly stops turning when target is inside the turn radius --- OpenRA.Mods.Common/Activities/Air/Fly.cs | 28 +++++++++++++++++++ .../Activities/Air/ReturnToBase.cs | 9 ++---- 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/OpenRA.Mods.Common/Activities/Air/Fly.cs b/OpenRA.Mods.Common/Activities/Air/Fly.cs index 486d0968cc..16102b0e59 100644 --- a/OpenRA.Mods.Common/Activities/Air/Fly.cs +++ b/OpenRA.Mods.Common/Activities/Air/Fly.cs @@ -123,6 +123,26 @@ namespace OpenRA.Mods.Common.Activities var targetAltitude = aircraft.CenterPosition.Z + aircraft.Info.CruiseAltitude.Length - self.World.Map.DistanceAboveTerrain(aircraft.CenterPosition).Length; if (aircraft.CenterPosition.Z < targetAltitude) desiredFacing = aircraft.Facing; + else + { + // Using the turn rate, compute a hypothetical circle traced by a continuous turn. + // If it contains the destination point, it's unreachable without more complex manuvering. + var turnRadius = CalculateTurnRadius(aircraft.MovementSpeed, aircraft.TurnSpeed); + + // The current facing is a tangent of the minimal turn circle. + // Make a perpendicular vector, and use it to locate the turn's center. + var turnCenterFacing = aircraft.Facing; + turnCenterFacing += Util.GetNearestFacing(aircraft.Facing, desiredFacing) > 0 ? 64 : -64; + + var turnCenterDir = new WVec(0, -1024, 0).Rotate(WRot.FromFacing(turnCenterFacing)); + turnCenterDir *= turnRadius; + turnCenterDir /= 1024; + + // Compare with the target point, and keep flying away if it's inside the circle. + var turnCenter = aircraft.CenterPosition + turnCenterDir; + if ((checkTarget.CenterPosition - turnCenter).HorizontalLengthSquared < turnRadius * turnRadius) + desiredFacing = aircraft.Facing; + } FlyToward(self, aircraft, desiredFacing, aircraft.Info.CruiseAltitude); @@ -133,5 +153,13 @@ namespace OpenRA.Mods.Common.Activities { yield return target; } + + public static int CalculateTurnRadius(int speed, int turnSpeed) + { + // turnSpeed -> divide into 256 to get the number of ticks per complete rotation + // speed -> multiply to get distance travelled per rotation (circumference) + // 45 -> divide by 2*pi to get the turn radius: 45==256/(2*pi), with some extra leeway + return 45 * speed / turnSpeed; + } } } diff --git a/OpenRA.Mods.Common/Activities/Air/ReturnToBase.cs b/OpenRA.Mods.Common/Activities/Air/ReturnToBase.cs index a78c0b2d52..0d0efaaf85 100644 --- a/OpenRA.Mods.Common/Activities/Air/ReturnToBase.cs +++ b/OpenRA.Mods.Common/Activities/Air/ReturnToBase.cs @@ -53,11 +53,6 @@ namespace OpenRA.Mods.Common.Activities .ClosestTo(self); } - int CalculateTurnRadius(int speed) - { - return 45 * speed / aircraft.Info.TurnSpeed; - } - void Calculate(Actor self) { if (dest == null || dest.IsDead || Reservable.IsReserved(dest)) @@ -77,7 +72,7 @@ namespace OpenRA.Mods.Common.Activities // Add 10% to the turning radius to ensure we have enough room var speed = aircraft.MovementSpeed * 32 / 35; - var turnRadius = CalculateTurnRadius(speed); + var turnRadius = Fly.CalculateTurnRadius(speed, aircraft.Info.TurnSpeed); // Find the center of the turning circles for clockwise and counterclockwise turns var angle = WAngle.FromFacing(aircraft.Facing); @@ -154,7 +149,7 @@ namespace OpenRA.Mods.Common.Activities List landingProcedures = new List(); - var turnRadius = CalculateTurnRadius(aircraft.Info.Speed); + var turnRadius = Fly.CalculateTurnRadius(aircraft.Info.Speed, aircraft.Info.TurnSpeed); landingProcedures.Add(new Fly(self, Target.FromPos(w1), WDist.Zero, new WDist(turnRadius * 3))); landingProcedures.Add(new Fly(self, Target.FromPos(w2)));