Fix Move jumpy-ness on MovePart transitions

There were 2 issues at work here, both when progress
would overshoot Distance (which is the usual case,
rather than the exception):
- the overshot progress was passed on by MoveFirstHalf, however
  OnComplete would make the next MovePart start ticking the
  same tick on which the old MovePart reached Distance,
  but move by carryoverProgress +(!!!) terrain speed instead of moving
  by just the left-over carryoverProgress.
- MoveSecondHalf would not pass any overshot progress to the
  next MoveFirstHalf queued by parent Move, leading to
  the next MoveFirstHalf performing a full-speed move the same tick
  MoveSecondHalf finished its last move.
This commit is contained in:
reaperrr
2021-03-14 00:48:58 +01:00
committed by teinarss
parent 4c7e3d8f3a
commit 27ddae3df9

View File

@@ -38,6 +38,8 @@ namespace OpenRA.Mods.Common.Activities
BlockedByActor.None BlockedByActor.None
}; };
int carryoverProgress;
List<CPos> path; List<CPos> path;
CPos? destination; CPos? destination;
@@ -218,7 +220,8 @@ namespace OpenRA.Mods.Common.Activities
var to = Util.BetweenCells(self.World, mobile.FromCell, mobile.ToCell) + var to = Util.BetweenCells(self.World, mobile.FromCell, mobile.ToCell) +
(map.Grid.OffsetOfSubCell(mobile.FromSubCell) + map.Grid.OffsetOfSubCell(mobile.ToSubCell)) / 2; (map.Grid.OffsetOfSubCell(mobile.FromSubCell) + map.Grid.OffsetOfSubCell(mobile.ToSubCell)) / 2;
QueueChild(new MoveFirstHalf(this, from, to, mobile.Facing, mobile.Facing, 0)); QueueChild(new MoveFirstHalf(this, from, to, mobile.Facing, mobile.Facing, carryoverProgress));
carryoverProgress = 0;
return false; return false;
} }
@@ -391,10 +394,11 @@ namespace OpenRA.Mods.Common.Activities
protected readonly WAngle ArcFromAngle; protected readonly WAngle ArcFromAngle;
protected readonly int ArcToLength; protected readonly int ArcToLength;
protected readonly WAngle ArcToAngle; protected readonly WAngle ArcToAngle;
protected readonly int Distance; protected readonly int Distance;
protected int progress; protected int progress;
protected bool firstTick = true;
public MovePart(Move move, WPos from, WPos to, WAngle fromFacing, WAngle toFacing, int carryoverProgress) public MovePart(Move move, WPos from, WPos to, WAngle fromFacing, WAngle toFacing, int carryoverProgress)
{ {
Move = move; Move = move;
@@ -404,6 +408,7 @@ namespace OpenRA.Mods.Common.Activities
ToFacing = toFacing; ToFacing = toFacing;
progress = carryoverProgress; progress = carryoverProgress;
Distance = (to - from).Length; Distance = (to - from).Length;
IsInterruptible = false; // See comments in Move.Cancel() IsInterruptible = false; // See comments in Move.Cancel()
// Calculate an elliptical arc that joins from and to // Calculate an elliptical arc that joins from and to
@@ -436,11 +441,17 @@ namespace OpenRA.Mods.Common.Activities
public override bool Tick(Actor self) public override bool Tick(Actor self)
{ {
var mobile = Move.mobile; var mobile = Move.mobile;
// Having non-zero progress in the first tick means that this MovePart is following on from
// a previous MovePart that has just completed during the same tick. In this case, we want to
// apply the carried over progress but not evaluate a full new step until the next tick.
if (!firstTick || progress == 0)
progress += mobile.MovementSpeedForCell(self, mobile.ToCell); progress += mobile.MovementSpeedForCell(self, mobile.ToCell);
firstTick = false;
if (progress >= Distance) if (progress >= Distance)
{ {
progress = Distance;
mobile.SetCenterPosition(self, To); mobile.SetCenterPosition(self, To);
mobile.Facing = ToFacing; mobile.Facing = ToFacing;
@@ -546,6 +557,11 @@ namespace OpenRA.Mods.Common.Activities
protected override MovePart OnComplete(Actor self, Mobile mobile, Move parent) protected override MovePart OnComplete(Actor self, Mobile mobile, Move parent)
{ {
mobile.SetPosition(self, mobile.ToCell); mobile.SetPosition(self, mobile.ToCell);
// Move might immediately queue a new MoveFirstHalf within the same tick if we haven't
// reached the end of the requested path. Make sure that any leftover movement progress is
// correctly carried over into this new activity to avoid a glitch in the apparent move speed.
Move.carryoverProgress = progress - Distance;
return null; return null;
} }
} }