Add plane repulsion logic
This commit is contained in:
@@ -22,6 +22,11 @@ namespace OpenRA.Mods.RA.Air
|
|||||||
public class AircraftInfo : ITraitInfo, IFacingInfo, IOccupySpaceInfo, UsesInit<LocationInit>, UsesInit<FacingInit>
|
public class AircraftInfo : ITraitInfo, IFacingInfo, IOccupySpaceInfo, UsesInit<LocationInit>, UsesInit<FacingInit>
|
||||||
{
|
{
|
||||||
public readonly WRange CruiseAltitude = new WRange(1280);
|
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]
|
[ActorReference]
|
||||||
public readonly string[] RepairBuildings = { "fix" };
|
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
|
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 AircraftInfo info;
|
||||||
readonly Actor self;
|
readonly Actor self;
|
||||||
@@ -60,13 +65,61 @@ namespace OpenRA.Mods.RA.Air
|
|||||||
if (init.Contains<CenterPositionInit>())
|
if (init.Contains<CenterPositionInit>())
|
||||||
SetPosition(self, init.Get<CenterPositionInit, WPos>());
|
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()
|
public Actor GetActorBelow()
|
||||||
{
|
{
|
||||||
if (self.CenterPosition.Z != 0)
|
if (self.CenterPosition.Z != 0)
|
||||||
return null; // not on the ground.
|
return null; // not on the ground.
|
||||||
|
|
||||||
return self.World.ActorMap.GetUnitsAt(self.Location)
|
return self.World.ActorMap.GetUnitsAt(self.Location)
|
||||||
.FirstOrDefault(a => a.HasTrait<Reservable>());
|
.FirstOrDefault(a => a.HasTrait<Reservable>());
|
||||||
@@ -158,7 +211,11 @@ namespace OpenRA.Mods.RA.Air
|
|||||||
|
|
||||||
public WVec FlyStep(int facing)
|
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));
|
var dir = new WVec(0, -1024, 0).Rotate(WRot.FromFacing(facing));
|
||||||
return speed * dir / 1024;
|
return speed * dir / 1024;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,8 +18,6 @@ namespace OpenRA.Mods.RA.Air
|
|||||||
{
|
{
|
||||||
class HelicopterInfo : AircraftInfo, IMoveInfo
|
class HelicopterInfo : AircraftInfo, IMoveInfo
|
||||||
{
|
{
|
||||||
public readonly WRange IdealSeparation = new WRange(1706);
|
|
||||||
|
|
||||||
[Desc("Allow the helicopter land after it has no more commands.")]
|
[Desc("Allow the helicopter land after it has no more commands.")]
|
||||||
public readonly bool LandWhenIdle = true;
|
public readonly bool LandWhenIdle = true;
|
||||||
|
|
||||||
@@ -135,41 +133,7 @@ namespace OpenRA.Mods.RA.Air
|
|||||||
self.QueueActivity(new TakeOff());
|
self.QueueActivity(new TakeOff());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Repulsion only applies when we're flying!
|
Repulse();
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Activity MoveTo(CPos cell, int nearEnough) { return new HeliFly(self, Target.FromCell(self.World, cell)); }
|
public Activity MoveTo(CPos cell, int nearEnough) { return new HeliFly(self, Target.FromCell(self.World, cell)); }
|
||||||
|
|||||||
@@ -50,6 +50,21 @@ namespace OpenRA.Mods.RA.Air
|
|||||||
|
|
||||||
self.QueueActivity(new TakeOff());
|
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)
|
public void ResolveOrder(Actor self, Order order)
|
||||||
|
|||||||
Reference in New Issue
Block a user