Convert Aircraft.Facing to WAngle.

This commit is contained in:
Paul Chote
2020-05-30 22:39:50 +01:00
committed by reaperrr
parent 7a78c37851
commit 6d6b21a0eb
11 changed files with 80 additions and 48 deletions

View File

@@ -54,7 +54,9 @@ namespace OpenRA.Mods.Common.Activities
if (info.MaximumSpinSpeed < 0 || Math.Abs(spin) < info.MaximumSpinSpeed) if (info.MaximumSpinSpeed < 0 || Math.Abs(spin) < info.MaximumSpinSpeed)
spin += acceleration; // TODO: Possibly unhardcode this spin += acceleration; // TODO: Possibly unhardcode this
aircraft.Facing = (aircraft.Facing + spin) % 256; // Allow for negative spin values and convert from facing to angle units
// TODO: Remember to convert this when removing WAngle.FromFacing
aircraft.Facing = new WAngle(aircraft.Facing.Angle + 4 * spin);
} }
var move = info.Moves ? aircraft.FlyStep(aircraft.Facing) : WVec.Zero; var move = info.Moves ? aircraft.FlyStep(aircraft.Facing) : WVec.Zero;

View File

@@ -60,7 +60,7 @@ namespace OpenRA.Mods.Common.Activities
this.minRange = minRange; this.minRange = minRange;
} }
public static void FlyTick(Actor self, Aircraft aircraft, int desiredFacing, WDist desiredAltitude, WVec moveOverride, int turnSpeedOverride = -1) public static void FlyTick(Actor self, Aircraft aircraft, WAngle desiredFacing, WDist desiredAltitude, WVec moveOverride, int turnSpeedOverride = -1)
{ {
var dat = self.World.Map.DistanceAboveTerrain(aircraft.CenterPosition); var dat = self.World.Map.DistanceAboveTerrain(aircraft.CenterPosition);
var move = aircraft.Info.CanSlide ? aircraft.FlyStep(desiredFacing) : aircraft.FlyStep(aircraft.Facing); var move = aircraft.Info.CanSlide ? aircraft.FlyStep(desiredFacing) : aircraft.FlyStep(aircraft.Facing);
@@ -83,13 +83,13 @@ namespace OpenRA.Mods.Common.Activities
aircraft.SetPosition(self, aircraft.CenterPosition + move); aircraft.SetPosition(self, aircraft.CenterPosition + move);
} }
public static void FlyTick(Actor self, Aircraft aircraft, int desiredFacing, WDist desiredAltitude, int turnSpeedOverride = -1) public static void FlyTick(Actor self, Aircraft aircraft, WAngle desiredFacing, WDist desiredAltitude, int turnSpeedOverride = -1)
{ {
FlyTick(self, aircraft, desiredFacing, desiredAltitude, WVec.Zero, turnSpeedOverride); FlyTick(self, aircraft, desiredFacing, desiredAltitude, WVec.Zero, turnSpeedOverride);
} }
// Should only be used for vertical-only movement, usually VTOL take-off or land. Terrain-induced altitude changes should always be handled by FlyTick. // Should only be used for vertical-only movement, usually VTOL take-off or land. Terrain-induced altitude changes should always be handled by FlyTick.
public static bool VerticalTakeOffOrLandTick(Actor self, Aircraft aircraft, int desiredFacing, WDist desiredAltitude, int turnSpeedOverride = -1) public static bool VerticalTakeOffOrLandTick(Actor self, Aircraft aircraft, WAngle desiredFacing, WDist desiredAltitude, int turnSpeedOverride = -1)
{ {
var dat = self.World.Map.DistanceAboveTerrain(aircraft.CenterPosition); var dat = self.World.Map.DistanceAboveTerrain(aircraft.CenterPosition);
var move = WVec.Zero; var move = WVec.Zero;
@@ -173,7 +173,7 @@ namespace OpenRA.Mods.Common.Activities
return true; return true;
var isSlider = aircraft.Info.CanSlide; var isSlider = aircraft.Info.CanSlide;
var desiredFacing = delta.HorizontalLengthSquared != 0 ? delta.Yaw.Facing : aircraft.Facing; var desiredFacing = delta.HorizontalLengthSquared != 0 ? delta.Yaw : aircraft.Facing;
var move = isSlider ? aircraft.FlyStep(desiredFacing) : aircraft.FlyStep(aircraft.Facing); var move = isSlider ? aircraft.FlyStep(desiredFacing) : aircraft.FlyStep(aircraft.Facing);
// Inside the minimum range, so reverse if we CanSlide, otherwise face away from the target. // Inside the minimum range, so reverse if we CanSlide, otherwise face away from the target.
@@ -183,8 +183,7 @@ namespace OpenRA.Mods.Common.Activities
FlyTick(self, aircraft, desiredFacing, aircraft.Info.CruiseAltitude, -move); FlyTick(self, aircraft, desiredFacing, aircraft.Info.CruiseAltitude, -move);
else else
{ {
desiredFacing = Util.NormalizeFacing(desiredFacing + 128); FlyTick(self, aircraft, desiredFacing + new WAngle(512), aircraft.Info.CruiseAltitude, move);
FlyTick(self, aircraft, desiredFacing, aircraft.Info.CruiseAltitude, move);
} }
return false; return false;
@@ -230,10 +229,9 @@ namespace OpenRA.Mods.Common.Activities
// The current facing is a tangent of the minimal turn circle. // The current facing is a tangent of the minimal turn circle.
// Make a perpendicular vector, and use it to locate the turn's center. // Make a perpendicular vector, and use it to locate the turn's center.
var turnCenterFacing = aircraft.Facing; var turnCenterFacing = aircraft.Facing + new WAngle(Util.GetTurnDirection(aircraft.Facing, desiredFacing) * 256);
turnCenterFacing += Util.GetNearestFacing(aircraft.Facing, desiredFacing) > 0 ? 64 : -64;
var turnCenterDir = new WVec(0, -1024, 0).Rotate(WRot.FromFacing(turnCenterFacing)); var turnCenterDir = new WVec(0, -1024, 0).Rotate(WRot.FromYaw(turnCenterFacing));
turnCenterDir *= turnRadius; turnCenterDir *= turnRadius;
turnCenterDir /= 1024; turnCenterDir /= 1024;
@@ -267,8 +265,8 @@ namespace OpenRA.Mods.Common.Activities
{ {
// turnSpeed -> divide into 256 to get the number of ticks per complete rotation // turnSpeed -> divide into 256 to get the number of ticks per complete rotation
// speed -> multiply to get distance travelled per rotation (circumference) // 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 // 180 -> divide by 2*pi to get the turn radius: 180==1024/(2*pi), with some extra leeway
return turnSpeed > 0 ? 45 * speed / turnSpeed : 0; return turnSpeed > 0 ? 180 * speed / turnSpeed : 0;
} }
} }
} }

View File

@@ -153,7 +153,7 @@ namespace OpenRA.Mods.Common.Activities
} }
var delta = attackAircraft.GetTargetPosition(pos, target) - pos; var delta = attackAircraft.GetTargetPosition(pos, target) - pos;
var desiredFacing = delta.HorizontalLengthSquared != 0 ? delta.Yaw.Facing : aircraft.Facing; var desiredFacing = delta.HorizontalLengthSquared != 0 ? delta.Yaw : aircraft.Facing;
QueueChild(new TakeOff(self)); QueueChild(new TakeOff(self));

View File

@@ -26,7 +26,7 @@ namespace OpenRA.Mods.Common.Activities
public FlyIdle(Actor self, int ticks = -1, bool tickIdle = true) public FlyIdle(Actor self, int ticks = -1, bool tickIdle = true)
{ {
aircraft = self.Trait<Aircraft>(); aircraft = self.Trait<Aircraft>();
turnSpeed = aircraft.Info.IdleTurnSpeed > -1 ? aircraft.Info.IdleTurnSpeed : aircraft.TurnSpeed; turnSpeed = aircraft.IdleTurnSpeed > -1 ? aircraft.IdleTurnSpeed : aircraft.TurnSpeed;
remainingTicks = ticks; remainingTicks = ticks;
if (tickIdle) if (tickIdle)
@@ -50,12 +50,11 @@ namespace OpenRA.Mods.Common.Activities
if (!aircraft.Info.CanHover) if (!aircraft.Info.CanHover)
{ {
// We can't possibly turn this fast
var desiredFacing = aircraft.Facing + 64;
// This override is necessary, otherwise aircraft with CanSlide would circle sideways // This override is necessary, otherwise aircraft with CanSlide would circle sideways
var move = aircraft.FlyStep(aircraft.Facing); var move = aircraft.FlyStep(aircraft.Facing);
// We can't possibly turn this fast
var desiredFacing = aircraft.Facing + new WAngle(256);
Fly.FlyTick(self, aircraft, desiredFacing, aircraft.Info.CruiseAltitude, move, turnSpeed); Fly.FlyTick(self, aircraft, desiredFacing, aircraft.Info.CruiseAltitude, move, turnSpeed);
} }

View File

@@ -22,7 +22,7 @@ namespace OpenRA.Mods.Common.Activities
{ {
readonly Aircraft aircraft; readonly Aircraft aircraft;
readonly WVec offset; readonly WVec offset;
readonly int desiredFacing; readonly WAngle? desiredFacing;
readonly bool assignTargetOnFirstRun; readonly bool assignTargetOnFirstRun;
readonly CPos[] clearCells; readonly CPos[] clearCells;
readonly WDist landRange; readonly WDist landRange;
@@ -34,22 +34,22 @@ namespace OpenRA.Mods.Common.Activities
bool landingInitiated; bool landingInitiated;
bool finishedApproach; bool finishedApproach;
public Land(Actor self, int facing = -1, Color? targetLineColor = null) public Land(Actor self, WAngle? facing = null, Color? targetLineColor = null)
: this(self, Target.Invalid, new WDist(-1), WVec.Zero, facing, null) : this(self, Target.Invalid, new WDist(-1), WVec.Zero, facing, null)
{ {
assignTargetOnFirstRun = true; assignTargetOnFirstRun = true;
} }
public Land(Actor self, Target target, int facing = -1, Color? targetLineColor = null) public Land(Actor self, Target target, WAngle? facing = null, Color? targetLineColor = null)
: this(self, target, new WDist(-1), WVec.Zero, facing, targetLineColor: targetLineColor) { } : this(self, target, new WDist(-1), WVec.Zero, facing, targetLineColor: targetLineColor) { }
public Land(Actor self, Target target, WDist landRange, int facing = -1, Color? targetLineColor = null) public Land(Actor self, Target target, WDist landRange, WAngle? facing = null, Color? targetLineColor = null)
: this(self, target, landRange, WVec.Zero, facing, targetLineColor: targetLineColor) { } : this(self, target, landRange, WVec.Zero, facing, targetLineColor: targetLineColor) { }
public Land(Actor self, Target target, WVec offset, int facing = -1, Color? targetLineColor = null) public Land(Actor self, Target target, WVec offset, WAngle? facing = null, Color? targetLineColor = null)
: this(self, target, WDist.Zero, offset, facing, targetLineColor: targetLineColor) { } : this(self, target, WDist.Zero, offset, facing, targetLineColor: targetLineColor) { }
public Land(Actor self, Target target, WDist landRange, WVec offset, int facing = -1, CPos[] clearCells = null, Color? targetLineColor = null) public Land(Actor self, Target target, WDist landRange, WVec offset, WAngle? facing = null, CPos[] clearCells = null, Color? targetLineColor = null)
{ {
aircraft = self.Trait<Aircraft>(); aircraft = self.Trait<Aircraft>();
this.target = target; this.target = target;
@@ -60,8 +60,8 @@ namespace OpenRA.Mods.Common.Activities
// NOTE: desiredFacing = -1 means we should not prefer any particular facing and instead just // NOTE: desiredFacing = -1 means we should not prefer any particular facing and instead just
// use whatever facing gives us the most direct path to the landing site. // use whatever facing gives us the most direct path to the landing site.
if (facing == -1 && aircraft.Info.TurnToLand) if (!facing.HasValue && aircraft.Info.TurnToLand)
desiredFacing = aircraft.Info.InitialFacing; desiredFacing = WAngle.FromFacing(aircraft.Info.InitialFacing);
else else
desiredFacing = facing; desiredFacing = facing;
} }
@@ -141,9 +141,10 @@ namespace OpenRA.Mods.Common.Activities
QueueChild(new Fly(self, Target.FromPos(targetPosition))); QueueChild(new Fly(self, Target.FromPos(targetPosition)));
return false; return false;
} }
else if (desiredFacing != -1 && desiredFacing != aircraft.Facing)
if (desiredFacing.HasValue && desiredFacing.Value != aircraft.Facing)
{ {
QueueChild(new Turn(self, desiredFacing)); QueueChild(new Turn(self, desiredFacing.Value.Facing));
return false; return false;
} }
} }
@@ -159,17 +160,17 @@ namespace OpenRA.Mods.Common.Activities
// Approach landing from the opposite direction of the desired facing // Approach landing from the opposite direction of the desired facing
// TODO: Calculate sensible trajectory without preferred facing. // TODO: Calculate sensible trajectory without preferred facing.
var rotation = WRot.Zero; var rotation = WRot.Zero;
if (desiredFacing != -1) if (desiredFacing.HasValue)
rotation = WRot.FromFacing(desiredFacing); rotation = WRot.FromYaw(desiredFacing.Value);
var approachStart = targetPosition + new WVec(0, landDistance, altitude).Rotate(rotation); var approachStart = targetPosition + new WVec(0, landDistance, altitude).Rotate(rotation);
// Add 10% to the turning radius to ensure we have enough room // Add 10% to the turning radius to ensure we have enough room
var speed = aircraft.MovementSpeed * 32 / 35; var speed = aircraft.MovementSpeed * 32 / 35;
var turnRadius = Fly.CalculateTurnRadius(speed, aircraft.Info.TurnSpeed); var turnRadius = Fly.CalculateTurnRadius(speed, aircraft.TurnSpeed);
// Find the center of the turning circles for clockwise and counterclockwise turns // Find the center of the turning circles for clockwise and counterclockwise turns
var angle = WAngle.FromFacing(aircraft.Facing); var angle = aircraft.Facing;
var fwd = -new WVec(angle.Sin(), angle.Cos(), 0); var fwd = -new WVec(angle.Sin(), angle.Cos(), 0);
// Work out whether we should turn clockwise or counter-clockwise for approach // Work out whether we should turn clockwise or counter-clockwise for approach
@@ -196,7 +197,7 @@ namespace OpenRA.Mods.Common.Activities
var w2 = approachCenter + tangentOffset; var w2 = approachCenter + tangentOffset;
var w3 = approachStart; var w3 = approachStart;
turnRadius = Fly.CalculateTurnRadius(aircraft.Info.Speed, aircraft.Info.TurnSpeed); turnRadius = Fly.CalculateTurnRadius(aircraft.Info.Speed, aircraft.TurnSpeed);
// Move along approach trajectory. // Move along approach trajectory.
QueueChild(new Fly(self, Target.FromPos(w1), WDist.Zero, new WDist(turnRadius * 3))); QueueChild(new Fly(self, Target.FromPos(w1), WDist.Zero, new WDist(turnRadius * 3)));
@@ -252,7 +253,7 @@ namespace OpenRA.Mods.Common.Activities
} }
var landingAlt = self.World.Map.DistanceAboveTerrain(targetPosition) + aircraft.LandAltitude; var landingAlt = self.World.Map.DistanceAboveTerrain(targetPosition) + aircraft.LandAltitude;
Fly.FlyTick(self, aircraft, d.Yaw.Facing, landingAlt); Fly.FlyTick(self, aircraft, d.Yaw, landingAlt);
return false; return false;
} }

View File

@@ -26,7 +26,7 @@ namespace OpenRA.Mods.Common.Activities
readonly Rearmable rearmable; readonly Rearmable rearmable;
readonly bool alwaysLand; readonly bool alwaysLand;
Actor dest; Actor dest;
int facing = -1; WAngle? facing;
public ReturnToBase(Actor self, Actor dest = null, bool alwaysLand = false) public ReturnToBase(Actor self, Actor dest = null, bool alwaysLand = false)
{ {
@@ -114,7 +114,7 @@ namespace OpenRA.Mods.Common.Activities
var exit = dest.FirstExitOrDefault(); var exit = dest.FirstExitOrDefault();
var offset = exit != null ? exit.Info.SpawnOffset : WVec.Zero; var offset = exit != null ? exit.Info.SpawnOffset : WVec.Zero;
if (aircraft.Info.TurnToDock || !aircraft.Info.VTOL) if (aircraft.Info.TurnToDock || !aircraft.Info.VTOL)
facing = aircraft.Info.InitialFacing; facing = WAngle.FromFacing(aircraft.Info.InitialFacing);
aircraft.MakeReservation(dest); aircraft.MakeReservation(dest);
QueueChild(new Land(self, Target.FromActor(dest), offset, facing, Color.Green)); QueueChild(new Land(self, Target.FromActor(dest), offset, facing, Color.Green));

View File

@@ -93,7 +93,7 @@ namespace OpenRA.Mods.Common.Activities
ChildActivity.Cancel(self); ChildActivity.Cancel(self);
var localOffset = carryall.OffsetForCarryable(self, cargo).Rotate(carryableBody.QuantizeOrientation(self, cargo.Orientation)); var localOffset = carryall.OffsetForCarryable(self, cargo).Rotate(carryableBody.QuantizeOrientation(self, cargo.Orientation));
QueueChild(new Land(self, Target.FromActor(cargo), -carryableBody.LocalToWorld(localOffset), carryableFacing.Facing)); QueueChild(new Land(self, Target.FromActor(cargo), -carryableBody.LocalToWorld(localOffset), WAngle.FromFacing(carryableFacing.Facing)));
// Pause briefly before attachment for visual effect // Pause briefly before attachment for visual effect
if (delay > 0) if (delay > 0)

View File

@@ -156,7 +156,7 @@ namespace OpenRA.Mods.Common.Scripting
// Scripted cargo aircraft must turn to default position before unloading. // Scripted cargo aircraft must turn to default position before unloading.
// TODO: pass facing through UnloadCargo instead. // TODO: pass facing through UnloadCargo instead.
if (aircraft != null) if (aircraft != null)
transport.QueueActivity(new Land(transport, Target.FromCell(transport.World, entryPath.Last()), WDist.FromCells(dropRange), aircraft.Info.InitialFacing)); transport.QueueActivity(new Land(transport, Target.FromCell(transport.World, entryPath.Last()), WDist.FromCells(dropRange), WAngle.FromFacing(aircraft.Info.InitialFacing)));
if (cargo != null) if (cargo != null)
transport.QueueActivity(new UnloadCargo(transport, WDist.FromCells(dropRange))); transport.QueueActivity(new UnloadCargo(transport, WDist.FromCells(dropRange)));

View File

@@ -209,13 +209,21 @@ namespace OpenRA.Mods.Common.Traits
IOverrideAircraftLanding overrideAircraftLanding; IOverrideAircraftLanding overrideAircraftLanding;
[Sync] [Sync]
public int Facing { get; set; } public WAngle Facing;
int IFacing.Facing
{
get { return Facing.Facing; }
set { Facing = WAngle.FromFacing(value); }
}
[Sync] [Sync]
public WPos CenterPosition { get; private set; } public WPos CenterPosition { get; private set; }
public CPos TopLeft { get { return self.World.Map.CellContaining(CenterPosition); } } public CPos TopLeft { get { return self.World.Map.CellContaining(CenterPosition); } }
public int TurnSpeed { get { return !IsTraitDisabled && !IsTraitPaused ? Info.TurnSpeed : 0; } } public int TurnSpeed { get { return !IsTraitDisabled && !IsTraitPaused ? 4 * Info.TurnSpeed : 0; } }
public int IdleTurnSpeed { get { return Info.IdleTurnSpeed != -1 ? 4 * Info.IdleTurnSpeed : -1; } }
public Actor ReservedActor { get; private set; } public Actor ReservedActor { get; private set; }
public bool MayYieldReservation { get; private set; } public bool MayYieldReservation { get; private set; }
public bool ForceLanding { get; private set; } public bool ForceLanding { get; private set; }
@@ -240,7 +248,7 @@ namespace OpenRA.Mods.Common.Traits
MovementType movementTypes; MovementType movementTypes;
WPos cachedPosition; WPos cachedPosition;
int cachedFacing; WAngle cachedFacing;
public Aircraft(ActorInitializer init, AircraftInfo info) public Aircraft(ActorInitializer init, AircraftInfo info)
: base(info) : base(info)
@@ -255,7 +263,7 @@ namespace OpenRA.Mods.Common.Traits
if (centerPositionInit != null) if (centerPositionInit != null)
SetPosition(self, centerPositionInit.Value); SetPosition(self, centerPositionInit.Value);
Facing = init.GetValue<FacingInit, int>(info, Info.InitialFacing); Facing = WAngle.FromFacing(init.GetValue<FacingInit, int>(info, Info.InitialFacing));
creationActivityDelay = init.GetValue<CreationActivityDelayInit, int>(info, 0); creationActivityDelay = init.GetValue<CreationActivityDelayInit, int>(info, 0);
} }
@@ -393,7 +401,7 @@ namespace OpenRA.Mods.Common.Traits
// HACK: Prevent updating visibility twice per tick. We really shouldn't be // HACK: Prevent updating visibility twice per tick. We really shouldn't be
// moving twice in a tick in the first place. // moving twice in a tick in the first place.
notify = false; notify = false;
SetPosition(self, CenterPosition + FlyStep(speed, repulsionForce.Yaw.Facing)); SetPosition(self, CenterPosition + FlyStep(speed, repulsionForce.Yaw));
notify = true; notify = true;
} }
@@ -558,14 +566,14 @@ namespace OpenRA.Mods.Common.Traits
return new[] { Pair.New(TopLeft, SubCell.FullCell) }; return new[] { Pair.New(TopLeft, SubCell.FullCell) };
} }
public WVec FlyStep(int facing) public WVec FlyStep(WAngle facing)
{ {
return FlyStep(MovementSpeed, facing); return FlyStep(MovementSpeed, facing);
} }
public WVec FlyStep(int speed, int facing) public WVec FlyStep(int speed, WAngle facing)
{ {
var dir = new WVec(0, -1024, 0).Rotate(WRot.FromFacing(facing)); var dir = new WVec(0, -1024, 0).Rotate(WRot.FromYaw(facing));
return speed * dir / 1024; return speed * dir / 1024;
} }
@@ -663,7 +671,7 @@ namespace OpenRA.Mods.Common.Traits
public void ModifyDeathActorInit(Actor self, TypeDictionary init) public void ModifyDeathActorInit(Actor self, TypeDictionary init)
{ {
init.Add(new FacingInit(Facing)); init.Add(new FacingInit(Facing.Facing));
} }
void INotifyBecomingIdle.OnBecomingIdle(Actor self) void INotifyBecomingIdle.OnBecomingIdle(Actor self)
@@ -1176,7 +1184,7 @@ namespace OpenRA.Mods.Common.Traits
void IActorPreviewInitModifier.ModifyActorPreviewInit(Actor self, TypeDictionary inits) void IActorPreviewInitModifier.ModifyActorPreviewInit(Actor self, TypeDictionary inits)
{ {
if (!inits.Contains<DynamicFacingInit>() && !inits.Contains<FacingInit>()) if (!inits.Contains<DynamicFacingInit>() && !inits.Contains<FacingInit>())
inits.Add(new DynamicFacingInit(() => Facing)); inits.Add(new DynamicFacingInit(() => Facing.Facing));
} }
Activity ICreationActivity.GetCreationActivity() Activity ICreationActivity.GetCreationActivity()

View File

@@ -99,7 +99,7 @@ namespace OpenRA.Mods.Common.Traits
}); });
var exitCell = self.Location + exit.ExitCell; var exitCell = self.Location + exit.ExitCell;
actor.QueueActivity(new Land(actor, Target.FromActor(self), WDist.Zero, WVec.Zero, info.Facing, clearCells: new CPos[1] { exitCell })); actor.QueueActivity(new Land(actor, Target.FromActor(self), WDist.Zero, WVec.Zero, WAngle.FromFacing(info.Facing), clearCells: new CPos[1] { exitCell }));
actor.QueueActivity(new CallFunc(() => actor.QueueActivity(new CallFunc(() =>
{ {
if (!self.IsInWorld || self.IsDead) if (!self.IsInWorld || self.IsDead)

View File

@@ -46,6 +46,30 @@ namespace OpenRA.Mods.Common
return facing + turn; return facing + turn;
} }
/// <summary>
/// Adds step angle units to facing in the direction that takes it closer to desiredFacing.
/// If facing is already within step of desiredFacing then desiredFacing is returned.
/// Step is given as an integer to allow negative values (step away from the desired facing)
/// </summary>
public static WAngle TickFacing(WAngle facing, WAngle desiredFacing, int step)
{
var leftTurn = (facing - desiredFacing).Angle;
var rightTurn = (desiredFacing - facing).Angle;
if (leftTurn < step || rightTurn < step)
return desiredFacing;
return rightTurn < leftTurn ? new WAngle(facing.Angle + step) : new WAngle(facing.Angle - step);
}
/// <summary>
/// Determines whether desiredFacing is clockwise (-1) or anticlockwise (+1) of facing.
/// If desiredFacing is equal to facing or directly behind facing we treat it as being anticlockwise
/// </summary>
public static int GetTurnDirection(WAngle facing, WAngle desiredFacing)
{
return (facing - desiredFacing).Angle < 512 ? -1 : 1;
}
/// <summary> /// <summary>
/// Calculate the frame index (between 0..numFrames) that /// Calculate the frame index (between 0..numFrames) that
/// should be used for the given facing value. /// should be used for the given facing value.