Convert plane activities to world coords.

This commit is contained in:
Paul Chote
2013-07-20 19:06:15 +12:00
parent f18994f800
commit a070629571
5 changed files with 62 additions and 55 deletions

View File

@@ -16,25 +16,25 @@ namespace OpenRA.Mods.RA.Air
{ {
public class Fly : Activity public class Fly : Activity
{ {
public readonly PPos Pos; readonly WPos pos;
Fly(PPos px) { Pos = px; } Fly(WPos pos) { this.pos = pos; }
public static Fly ToPx( PPos px ) { return new Fly( px ); } public static Fly ToPos(WPos pos) { return new Fly(pos); }
public static Fly ToCell(CPos pos) { return new Fly(Util.CenterOfCell(pos)); } public static Fly ToCell(CPos pos) { return new Fly(pos.CenterPosition); }
public override Activity Tick(Actor self) public override Activity Tick(Actor self)
{ {
var cruiseAltitude = self.Info.Traits.Get<PlaneInfo>().CruiseAltitude; if (IsCanceled)
return NextActivity;
if (IsCanceled) return NextActivity; // Close enough (ported from old code which checked length against sqrt(50) px)
var d = pos - self.CenterPosition;
var d = Pos - self.CenterLocation; if (d.HorizontalLengthSquared < 91022)
if (d.LengthSquared < 50) /* close enough */
return NextActivity; return NextActivity;
var aircraft = self.Trait<Aircraft>(); var aircraft = self.Trait<Aircraft>();
var cruiseAltitude = self.Info.Traits.Get<PlaneInfo>().CruiseAltitude;
var desiredFacing = Util.GetFacing(d, aircraft.Facing); var desiredFacing = Util.GetFacing(d, aircraft.Facing);
if (aircraft.Altitude == cruiseAltitude) if (aircraft.Altitude == cruiseAltitude)
aircraft.Facing = Util.TickFacing(aircraft.Facing, desiredFacing, aircraft.ROT); aircraft.Facing = Util.TickFacing(aircraft.Facing, desiredFacing, aircraft.ROT);
@@ -48,7 +48,7 @@ namespace OpenRA.Mods.RA.Air
public override IEnumerable<Target> GetTargets(Actor self) public override IEnumerable<Target> GetTargets(Actor self)
{ {
yield return Target.FromPos(Pos); yield return Target.FromPos(pos);
} }
} }

View File

@@ -36,7 +36,7 @@ namespace OpenRA.Mods.RA.Air
if( IsCanceled ) if( IsCanceled )
return NextActivity; return NextActivity;
inner = Util.SequenceActivities( inner = Util.SequenceActivities(
Fly.ToPx(Target.CenterLocation), Fly.ToPos(Target.CenterPosition),
new FlyTimed(50)); new FlyTimed(50));
} }
inner = Util.RunActivity( self, inner ); inner = Util.RunActivity( self, inner );

View File

@@ -31,9 +31,9 @@ namespace OpenRA.Mods.RA.Air
var aircraft = self.Trait<Aircraft>(); var aircraft = self.Trait<Aircraft>();
var d = Target.CenterPosition - self.CenterPosition; var d = Target.CenterPosition - self.CenterPosition;
// close enough (1/16 cell) // The next move would overshoot, so just set the final position
// TODO: TickMove may overshoot if the aircraft speed is too high var moveDist = aircraft.MovementSpeed * 7 * 1024 / (Game.CellSize * 32);
if (d.HorizontalLengthSquared < 4096) if (d.HorizontalLengthSquared < moveDist*moveDist)
{ {
aircraft.SetPxPosition(self, PPos.FromWPos(Target.CenterPosition)); aircraft.SetPxPosition(self, PPos.FromWPos(Target.CenterPosition));
return NextActivity; return NextActivity;

View File

@@ -21,7 +21,7 @@ namespace OpenRA.Mods.RA.Air
public class Plane : Aircraft, IResolveOrder, ITick, ISync public class Plane : Aircraft, IResolveOrder, ITick, ISync
{ {
[Sync] public PVecInt RTBPathHash; [Sync] public WPos RTBPathHash;
public Plane( ActorInitializer init, PlaneInfo info ) public Plane( ActorInitializer init, PlaneInfo info )
: base( init, info ) { } : base( init, info ) { }

View File

@@ -19,8 +19,7 @@ namespace OpenRA.Mods.RA.Air
{ {
bool isCalculated; bool isCalculated;
Actor dest; Actor dest;
WPos w1, w2, w3;
PPos w1, w2, w3; /* tangent points to turn circles */
public static Actor ChooseAirfield(Actor self, bool unreservedOnly) public static Actor ChooseAirfield(Actor self, bool unreservedOnly)
{ {
@@ -35,11 +34,14 @@ namespace OpenRA.Mods.RA.Air
void Calculate(Actor self) void Calculate(Actor self)
{ {
if (dest == null || Reservable.IsReserved(dest)) dest = ChooseAirfield(self, true); if (dest == null || Reservable.IsReserved(dest))
dest = ChooseAirfield(self, true);
if (dest == null) return; if (dest == null)
return;
var plane = self.Trait<Plane>(); var plane = self.Trait<Plane>();
var planeInfo = self.Info.Traits.Get<PlaneInfo>();
var res = dest.TraitOrDefault<Reservable>(); var res = dest.TraitOrDefault<Reservable>();
if (res != null) if (res != null)
{ {
@@ -47,41 +49,46 @@ namespace OpenRA.Mods.RA.Air
plane.reservation = res.Reserve(dest, self, plane); plane.reservation = res.Reserve(dest, self, plane);
} }
var landPos = dest.CenterLocation; var landPos = dest.CenterPosition;
var aircraft = self.Trait<Aircraft>(); var speed = plane.MovementSpeed * 1024 / Game.CellSize / 5;
var speed = .2f * aircraft.MovementSpeed; // Distance required for descent.
// TODO: Generalize this for arbitrary flight pitches
var landDistance = planeInfo.CruiseAltitude * speed;
var altitude = planeInfo.CruiseAltitude * 1024 / Game.CellSize;
/* if the aircraft is on the ground, it will take off to the cruise altitude first before approaching */ // Land towards the east
var altitude = aircraft.Altitude; var approachStart = landPos + new WVec(-landDistance, 0, altitude);
if (altitude == 0) altitude = self.Info.Traits.Get<PlaneInfo>().CruiseAltitude;
var approachStart = landPos.ToInt2() - new float2(altitude * speed, 0); // Add 10% to the turning radius to ensure we have enough room
var turnRadius = (128f / self.Info.Traits.Get<AircraftInfo>().ROT) * speed / (float)Math.PI; var turnRadius = (int)(141 * speed / planeInfo.ROT / (float)(Math.PI));
/* work out the center points */ // Find the center of the turning circles for clockwise and counterclockwise turns
var fwd = -float2.FromAngle(aircraft.Facing / 128f * (float)Math.PI); var angle = WAngle.FromFacing(plane.Facing);
var side = new float2(-fwd.Y, fwd.X); /* rotate */ var fwd = -new WVec(angle.Sin(), angle.Cos(), 0);
// Work out whether we should turn clockwise or counter-clockwise for approach
var side = new WVec(-fwd.Y, fwd.X, fwd.Z);
var approachDelta = self.CenterPosition - approachStart;
var sideTowardBase = new[] { side, -side } var sideTowardBase = new[] { side, -side }
.OrderBy(a => float2.Dot(a, self.CenterLocation.ToInt2() - approachStart)) .OrderBy(a => WVec.Dot(a, approachDelta))
.First(); .First();
var c1 = self.CenterLocation.ToInt2() + turnRadius * sideTowardBase; // Calculate the tangent line that joins the turning circles at the current and approach positions
var c2 = approachStart + new float2(0, turnRadius * Math.Sign(self.CenterLocation.Y - approachStart.Y)); // above or below start point var cp = self.CenterPosition + turnRadius * sideTowardBase / 1024;
var posCenter = new WPos(cp.X, cp.Y, altitude);
var approachCenter = approachStart + new WVec(0, turnRadius * Math.Sign(self.CenterPosition.Y - approachStart.Y), 0);
var tangentDirection = approachCenter - posCenter;
var tangentOffset = new WVec(-tangentDirection.Y, tangentDirection.X, 0) * turnRadius / tangentDirection.Length;
/* work out tangent points */ // TODO: correctly handle CCW <-> CW turns
var d = c2 - c1; if (tangentOffset.X > 0)
var e = (turnRadius / d.Length) * d; tangentOffset = -tangentOffset;
var f = new float2(-e.Y, e.X); /* rotate */
/* TODO: support internal tangents, too! */ w1 = posCenter + tangentOffset;
w2 = approachCenter + tangentOffset;
if (f.X > 0) f = -f; w3 = approachStart;
plane.RTBPathHash = w1 + (WVec)w2 + (WVec)w3;
w1 = (PPos)(c1 + f).ToInt2();
w2 = (PPos)(c2 + f).ToInt2();
w3 = (PPos)(approachStart).ToInt2();
plane.RTBPathHash = (PVecInt)w1 + (PVecInt)w2 + (PVecInt)w3;
isCalculated = true; isCalculated = true;
} }
@@ -93,12 +100,12 @@ namespace OpenRA.Mods.RA.Air
public override Activity Tick(Actor self) public override Activity Tick(Actor self)
{ {
if (IsCanceled) if (IsCanceled || self.IsDead())
return NextActivity;
if (self.IsDead())
return NextActivity; return NextActivity;
if (!isCalculated) if (!isCalculated)
Calculate(self); Calculate(self);
if (dest == null) if (dest == null)
{ {
var nearestAfld = ChooseAirfield(self, false); var nearestAfld = ChooseAirfield(self, false);
@@ -111,9 +118,9 @@ namespace OpenRA.Mods.RA.Air
} }
return Util.SequenceActivities( return Util.SequenceActivities(
Fly.ToPx(w1), Fly.ToPos(w1),
Fly.ToPx(w2), Fly.ToPos(w2),
Fly.ToPx(w3), Fly.ToPos(w3),
new Land(Target.FromActor(dest)), new Land(Target.FromActor(dest)),
NextActivity); NextActivity);
} }