Merge pull request #4912 from pchote/exits

Clean up mobile world insertion.
This commit is contained in:
Matthias Mailänder
2014-03-20 11:58:46 +01:00
10 changed files with 73 additions and 63 deletions

View File

@@ -161,6 +161,8 @@ namespace OpenRA.Traits
Activity MoveTo(CPos cell, Actor ignoredActor);
Activity MoveWithinRange(Target target, WRange range);
Activity MoveFollow(Actor self, Target target, WRange range);
Activity MoveIntoWorld(Actor self, CPos cell);
Activity VisualMove(Actor self, WPos fromPos, WPos toPos);
CPos NearestMoveableCell(CPos target);
bool IsMoving { get; set; }
}

View File

@@ -37,18 +37,11 @@ namespace OpenRA.Mods.RA.Activities
return Util.SequenceActivities(new MoveAdjacentTo(self, target), this);
// Move to the middle of the target, ignoring impassable tiles
var mobile = self.Trait<Mobile>();
var to = target.CenterPosition;
var from = self.CenterPosition;
var speed = mobile.MovementSpeedForCell(self, self.Location);
var length = speed > 0 ? (to - from).Length / speed : 0;
var move = self.Trait<IMove>();
return Util.SequenceActivities(
new Turn(Util.GetFacing(to - from, mobile.Facing)),
new Drag(from, to, length),
move.VisualMove(self, self.CenterPosition, target.CenterPosition),
inner,
new Turn(Util.GetFacing(from - to, mobile.Facing)),
new Drag(to, from, length),
move.VisualMove(self, target.CenterPosition, self.CenterPosition),
NextActivity
);
}

View File

@@ -33,20 +33,21 @@ namespace OpenRA.Mods.RA.Activities
public CPos? ChooseExitCell(Actor passenger)
{
var mobile = passenger.Trait<Mobile>();
var pos = passenger.Trait<IPositionable>();
return cargo.CurrentAdjacentCells
.Shuffle(self.World.SharedRandom)
.Cast<CPos?>()
.FirstOrDefault(c => mobile.CanEnterCell(c.Value));
.FirstOrDefault(c => pos.CanEnterCell(c.Value));
}
IEnumerable<CPos> BlockedExitCells(Actor passenger)
{
var mobile = passenger.Trait<Mobile>();
var pos = passenger.Trait<IPositionable>();
// Find the cells that are blocked by transient actors
return cargo.CurrentAdjacentCells
.Where(c => mobile.MovementSpeedForCell(passenger, c) != int.MaxValue && !mobile.CanEnterCell(c));
.Where(c => pos.CanEnterCell(c, null, true) != pos.CanEnterCell(c, null, false));
}
public override Activity Tick(Actor self)
@@ -58,6 +59,7 @@ namespace OpenRA.Mods.RA.Activities
cloak.Uncloak();
var actor = cargo.Peek(self);
var spawn = self.CenterPosition;
var exitCell = ChooseExitCell(actor);
if (exitCell == null)
@@ -71,33 +73,18 @@ namespace OpenRA.Mods.RA.Activities
}
cargo.Unload(self);
self.World.AddFrameEndTask(w =>
{
if (actor.Destroyed)
return;
var mobile = actor.Trait<Mobile>();
var exitSubcell = mobile.GetDesiredSubcell(exitCell.Value, null);
mobile.fromSubCell = exitSubcell; // these settings make sure that the below Set* calls
mobile.toSubCell = exitSubcell; // and the above GetDesiredSubcell call pick a good free subcell for later units being unloaded
var exit = exitCell.Value.CenterPosition + MobileInfo.SubCellOffsets[exitSubcell];
var current = self.Location.CenterPosition + MobileInfo.SubCellOffsets[exitSubcell];
mobile.Facing = Util.GetFacing(exit - current, mobile.Facing);
mobile.SetPosition(actor, exitCell.Value);
mobile.SetVisualPosition(actor, current);
var speed = mobile.MovementSpeedForCell(actor, exitCell.Value);
var length = speed > 0 ? (exit - current).Length / speed : 0;
var move = actor.Trait<IMove>();
var pos = actor.Trait<IPositionable>();
w.Add(actor);
actor.CancelActivity();
actor.QueueActivity(new Drag(current, exit, length));
actor.QueueActivity(mobile.MoveTo(exitCell.Value, 0));
pos.SetVisualPosition(actor, spawn);
actor.QueueActivity(move.MoveIntoWorld(actor, exitCell.Value));
actor.SetTargetLine(Target.FromCell(exitCell.Value), Color.Green, false);
});

View File

@@ -159,5 +159,16 @@ namespace OpenRA.Mods.RA.Air
public Activity MoveWithinRange(Target target, WRange minRange, WRange maxRange) { return new HeliFly(self, target, minRange, maxRange); }
public Activity MoveFollow(Actor self, Target target, WRange range) { return new Follow(self, target, range); }
public CPos NearestMoveableCell(CPos cell) { return cell; }
public Activity MoveIntoWorld(Actor self, CPos cell)
{
return new HeliFly(self, Target.FromCell(cell));
}
public Activity VisualMove(Actor self, WPos fromPos, WPos toPos)
{
// TODO: Ignore repulsion when moving
return Util.SequenceActivities(new CallFunc(() => SetVisualPosition(self, fromPos)), new HeliFly(self, Target.FromPos(toPos)));
}
}
}

View File

@@ -100,5 +100,8 @@ namespace OpenRA.Mods.RA.Air
public Activity MoveWithinRange(Target target, WRange minRange, WRange maxRange) { return Util.SequenceActivities(new Fly(self, target, minRange, maxRange), new FlyCircle()); }
public Activity MoveFollow(Actor self, Target target, WRange range) { return new FlyFollow(self, target, range); }
public CPos NearestMoveableCell(CPos cell) { return cell; }
public Activity MoveIntoWorld(Actor self, CPos cell) { return new Fly(self, Target.FromCell(cell)); }
public Activity VisualMove(Actor self, WPos fromPos, WPos toPos) { return Util.SequenceActivities(new CallFunc(() => SetVisualPosition(self, fromPos)), new Fly(self, Target.FromPos(toPos))); }
}
}

View File

@@ -548,5 +548,31 @@ namespace OpenRA.Mods.RA.Move
if (self.IsIdle && self.AppearsFriendlyTo(blocking))
Nudge(self, blocking, true);
}
public Activity MoveIntoWorld(Actor self, CPos cell)
{
var pos = self.CenterPosition;
// Reserve the exit cell
SetPosition(self, cell);
SetVisualPosition(self, pos);
// Animate transition
var to = cell.CenterPosition;
var speed = MovementSpeedForCell(self, cell);
var length = speed > 0 ? (to - pos).Length / speed : 0;
var facing = Util.GetFacing(to - pos, Facing);
return Util.SequenceActivities(new Turn(facing), new Drag(pos, to, length));
}
public Activity VisualMove(Actor self, WPos fromPos, WPos toPos)
{
var speed = MovementSpeedForCell(self, self.Location);
var length = speed > 0 ? (toPos - fromPos).Length / speed : 0;
var facing = Util.GetFacing(toPos - fromPos, Facing);
return Util.SequenceActivities(new Turn(facing), new Drag(fromPos, toPos, length));
}
}
}

View File

@@ -34,6 +34,7 @@ namespace OpenRA.Mods.RA
[Desc("Cell offset where the exiting actor enters the ActorMap")]
public readonly CVec ExitCell = CVec.Zero;
public readonly int Facing = -1;
public readonly bool MoveIntoWorld = true;
}
public class Exit { }
@@ -58,28 +59,15 @@ namespace OpenRA.Mods.RA
var newUnit = self.World.CreateActor(producee.Name, new TypeDictionary
{
new OwnerInit(self.Owner),
new LocationInit(exit),
new CenterPositionInit(spawn),
new FacingInit(initialFacing)
});
// TODO: Move this into an *Init
// TODO: We should be adjusting the actual position for aircraft, not just visuals.
var teleportable = newUnit.Trait<IPositionable>();
teleportable.SetVisualPosition(newUnit, spawn);
// TODO: Generalize this for non-mobile (e.g. aircraft) too
// Remember to update the Enter activity too
var mobile = newUnit.TraitOrDefault<Mobile>();
if (mobile != null)
{
// Animate the spawn -> exit transition
var speed = mobile.MovementSpeedForCell(newUnit, exit);
var length = speed > 0 ? (to - spawn).Length / speed : 0;
newUnit.QueueActivity(new Drag(spawn, to, length));
}
var move = newUnit.Trait<IMove>();
if (exitinfo.MoveIntoWorld)
newUnit.QueueActivity(move.MoveIntoWorld(newUnit, exit));
var target = MoveToRallyPoint(self, newUnit, exit);
newUnit.SetTargetLine(Target.FromCell(target), Color.Green, false);
foreach (var t in self.TraitsImplementing<INotifyProduction>())
t.UnitProduced(self, newUnit, exit);

View File

@@ -14,7 +14,7 @@ using OpenRA.Traits;
namespace OpenRA.Mods.RA.Render
{
public class RenderInfantryInfo : RenderSimpleInfo, Requires<MobileInfo>
public class RenderInfantryInfo : RenderSimpleInfo, Requires<IMoveInfo>
{
public readonly int MinIdleWaitTicks = 30;
public readonly int MaxIdleWaitTicks = 110;
@@ -35,7 +35,7 @@ namespace OpenRA.Mods.RA.Render
IdleAnimating
}
Mobile mobile;
IMove move;
RenderInfantryInfo info;
public bool IsMoving { get; set; }
protected bool dirty = false;
@@ -60,7 +60,7 @@ namespace OpenRA.Mods.RA.Render
this.info = info;
anim.PlayFetchIndex(NormalizeInfantrySequence(self, info.StandAnimations.Random(Game.CosmeticRandom)), () => 0);
State = AnimationState.Waiting;
mobile = self.Trait<Mobile>();
move = self.Trait<IMove>();
self.Trait<IBodyOrientation>().SetAutodetectedFacings(anim.CurrentSequence.Facings);
}
@@ -83,12 +83,12 @@ namespace OpenRA.Mods.RA.Render
{
base.Tick(self);
if ((State == AnimationState.Moving || dirty) && !mobile.IsMoving)
if ((State == AnimationState.Moving || dirty) && !move.IsMoving)
{
State = AnimationState.Waiting;
anim.PlayFetchIndex(NormalizeInfantrySequence(self, info.StandAnimations.Random(Game.CosmeticRandom)), () => 0);
}
else if ((State != AnimationState.Moving || dirty) && mobile.IsMoving)
else if ((State != AnimationState.Moving || dirty) && move.IsMoving)
{
State = AnimationState.Moving;
anim.PlayRepeating(NormalizeInfantrySequence(self, "run"));

View File

@@ -14,7 +14,7 @@ using OpenRA.Mods.RA.Move;
namespace OpenRA.Mods.RA.Render
{
public class RenderLandingCraftInfo : RenderUnitInfo
public class RenderLandingCraftInfo : RenderUnitInfo, Requires<IMoveInfo>
{
public readonly string[] OpenTerrainTypes = { "Clear" };
public readonly string OpenAnim = "open";
@@ -25,26 +25,24 @@ namespace OpenRA.Mods.RA.Render
public class RenderLandingCraft : RenderUnit
{
readonly RenderLandingCraftInfo info;
readonly Actor self;
readonly Cargo cargo;
readonly RenderLandingCraftInfo info;
readonly IMove move;
bool open;
public RenderLandingCraft(Actor self, RenderLandingCraftInfo info)
: base(self)
{
this.info = info;
this.self = self;
cargo = self.Trait<Cargo>();
this.info = info;
move = self.Trait<IMove>();
}
public bool ShouldBeOpen()
{
var mobile = self.TraitOrDefault<Mobile>();
if (mobile == null)
return false;
if (self.CenterPosition.Z > 0 || mobile.IsMoving)
if (self.CenterPosition.Z > 0 || move.IsMoving)
return false;
return cargo.CurrentAdjacentCells

View File

@@ -1025,6 +1025,7 @@ HPAD:
Exit@1:
SpawnOffset: 0,-256,0
ExitCell: 0,0
MoveIntoWorld: false
Production:
Produces: Helicopter
Reservable:
@@ -1059,6 +1060,7 @@ AFLD:
SpawnOffset: 0,170,0
ExitCell: 1,1
Facing: 192
MoveIntoWorld: false
Production:
Produces: Plane
Reservable: