Add plane repulsion logic

This commit is contained in:
ScottNZ
2014-07-27 22:06:30 +12:00
parent a57c9c5cf3
commit 16a30fd6b1
3 changed files with 77 additions and 41 deletions

View File

@@ -22,6 +22,11 @@ namespace OpenRA.Mods.RA.Air
public class AircraftInfo : ITraitInfo, IFacingInfo, IOccupySpaceInfo, UsesInit<LocationInit>, UsesInit<FacingInit>
{
public readonly WRange CruiseAltitude = new WRange(1280);
public readonly WRange IdealSeparation = new WRange(1706);
[Desc("Whether the aircraft can be repulsed.")]
public readonly bool Repulsable = true;
[Desc("The speed at which the aircraft is repulsed from other aircraft. Specify -1 for normal movement speed.")]
public readonly int RepulsionSpeed = -1;
[ActorReference]
public readonly string[] RepairBuildings = { "fix" };
@@ -38,7 +43,7 @@ namespace OpenRA.Mods.RA.Air
public class Aircraft : IFacing, IPositionable, ISync, INotifyKilled, IIssueOrder, IOrderVoice, INotifyAddedToWorld, INotifyRemovedFromWorld
{
static readonly Pair<CPos, SubCell>[] NoCells = new Pair<CPos, SubCell>[] { };
static readonly Pair<CPos, SubCell>[] NoCells = { };
readonly AircraftInfo info;
readonly Actor self;
@@ -60,13 +65,61 @@ namespace OpenRA.Mods.RA.Air
if (init.Contains<CenterPositionInit>())
SetPosition(self, init.Get<CenterPositionInit, WPos>());
this.Facing = init.Contains<FacingInit>() ? init.Get<FacingInit, int>() : info.InitialFacing;
Facing = init.Contains<FacingInit>() ? init.Get<FacingInit, int>() : info.InitialFacing;
}
public void Repulse()
{
var repulsionForce = GetRepulsionForce();
var repulsionFacing = Util.GetFacing(repulsionForce, -1);
if (repulsionFacing == -1)
return;
var speed = info.RepulsionSpeed != -1 ? info.RepulsionSpeed : MovementSpeed;
SetPosition(self, CenterPosition + FlyStep(speed, repulsionFacing));
}
public virtual WVec GetRepulsionForce()
{
if (!info.Repulsable)
return WVec.Zero;
// Repulsion only applies when we're flying!
var altitude = CenterPosition.Z;
if (altitude != info.CruiseAltitude.Range)
return WVec.Zero;
return self.World.FindActorsInCircle(self.CenterPosition, info.IdealSeparation)
.Where(a => !a.IsDead() && a.HasTrait<Aircraft>())
.Select(GetRepulsionForce)
.Aggregate(WVec.Zero, (a, b) => a + b);
}
public WVec GetRepulsionForce(Actor other)
{
if (self == other || other.CenterPosition.Z < self.CenterPosition.Z)
return WVec.Zero;
var d = self.CenterPosition - other.CenterPosition;
var distSq = d.HorizontalLengthSquared;
if (distSq > info.IdealSeparation.Range * info.IdealSeparation.Range)
return WVec.Zero;
if (distSq < 1)
{
var yaw = self.World.SharedRandom.Next(0, 1023);
var rot = new WRot(WAngle.Zero, WAngle.Zero, new WAngle(yaw));
return new WVec(1024, 0, 0).Rotate(rot);
}
return (d * 1024 * 8) / (int)distSq;
}
public Actor GetActorBelow()
{
if (self.CenterPosition.Z != 0)
return null; // not on the ground.
return null; // not on the ground.
return self.World.ActorMap.GetUnitsAt(self.Location)
.FirstOrDefault(a => a.HasTrait<Reservable>());
@@ -158,7 +211,11 @@ namespace OpenRA.Mods.RA.Air
public WVec FlyStep(int facing)
{
var speed = MovementSpeed;
return FlyStep(MovementSpeed, facing);
}
public WVec FlyStep(int speed, int facing)
{
var dir = new WVec(0, -1024, 0).Rotate(WRot.FromFacing(facing));
return speed * dir / 1024;
}

View File

@@ -18,8 +18,6 @@ namespace OpenRA.Mods.RA.Air
{
class HelicopterInfo : AircraftInfo, IMoveInfo
{
public readonly WRange IdealSeparation = new WRange(1706);
[Desc("Allow the helicopter land after it has no more commands.")]
public readonly bool LandWhenIdle = true;
@@ -135,41 +133,7 @@ namespace OpenRA.Mods.RA.Air
self.QueueActivity(new TakeOff());
}
// Repulsion only applies when we're flying!
var altitude = CenterPosition.Z;
if (altitude != Info.CruiseAltitude.Range)
return;
var otherHelis = self.World.FindActorsInCircle(self.CenterPosition, Info.IdealSeparation)
.Where(a => a.HasTrait<Helicopter>());
var f = otherHelis
.Select(h => GetRepulseForce(self, h))
.Aggregate(WVec.Zero, (a, b) => a + b);
var repulsionFacing = Util.GetFacing(f, -1);
if (repulsionFacing != -1)
SetPosition(self, CenterPosition + FlyStep(repulsionFacing));
}
public WVec GetRepulseForce(Actor self, Actor other)
{
if (self == other || other.CenterPosition.Z < self.CenterPosition.Z)
return WVec.Zero;
var d = self.CenterPosition - other.CenterPosition;
var distSq = d.HorizontalLengthSquared;
if (distSq > Info.IdealSeparation.Range * Info.IdealSeparation.Range)
return WVec.Zero;
if (distSq < 1)
{
var yaw = self.World.SharedRandom.Next(0, 1023);
var rot = new WRot(WAngle.Zero, WAngle.Zero, new WAngle(yaw));
return new WVec(1024, 0, 0).Rotate(rot);
}
return (d * 1024 * 8) / (int)distSq;
Repulse();
}
public Activity MoveTo(CPos cell, int nearEnough) { return new HeliFly(self, Target.FromCell(self.World, cell)); }

View File

@@ -50,6 +50,21 @@ namespace OpenRA.Mods.RA.Air
self.QueueActivity(new TakeOff());
}
Repulse();
}
public override WVec GetRepulsionForce()
{
var repulsionForce = base.GetRepulsionForce();
if (repulsionForce == WVec.Zero)
return WVec.Zero;
var currentDir = FlyStep(Facing);
var dot = WVec.Dot(currentDir, repulsionForce) / (currentDir.HorizontalLength * repulsionForce.HorizontalLength);
// avoid stalling the plane
return dot >= 0 ? repulsionForce : WVec.Zero;
}
public void ResolveOrder(Actor self, Order order)