From 27ddae3df9786f44a413cb5c9409495b1354fc3d Mon Sep 17 00:00:00 2001 From: reaperrr Date: Sun, 14 Mar 2021 00:48:58 +0100 Subject: [PATCH] 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. --- OpenRA.Mods.Common/Activities/Move/Move.cs | 24 ++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/OpenRA.Mods.Common/Activities/Move/Move.cs b/OpenRA.Mods.Common/Activities/Move/Move.cs index 157c4321fb..79e3e7d594 100644 --- a/OpenRA.Mods.Common/Activities/Move/Move.cs +++ b/OpenRA.Mods.Common/Activities/Move/Move.cs @@ -38,6 +38,8 @@ namespace OpenRA.Mods.Common.Activities BlockedByActor.None }; + int carryoverProgress; + List path; CPos? destination; @@ -218,7 +220,8 @@ namespace OpenRA.Mods.Common.Activities var to = Util.BetweenCells(self.World, mobile.FromCell, mobile.ToCell) + (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; } @@ -391,10 +394,11 @@ namespace OpenRA.Mods.Common.Activities protected readonly WAngle ArcFromAngle; protected readonly int ArcToLength; protected readonly WAngle ArcToAngle; - protected readonly int Distance; protected int progress; + protected bool firstTick = true; + public MovePart(Move move, WPos from, WPos to, WAngle fromFacing, WAngle toFacing, int carryoverProgress) { Move = move; @@ -404,6 +408,7 @@ namespace OpenRA.Mods.Common.Activities ToFacing = toFacing; progress = carryoverProgress; Distance = (to - from).Length; + IsInterruptible = false; // See comments in Move.Cancel() // Calculate an elliptical arc that joins from and to @@ -436,11 +441,17 @@ namespace OpenRA.Mods.Common.Activities public override bool Tick(Actor self) { var mobile = Move.mobile; - progress += mobile.MovementSpeedForCell(self, mobile.ToCell); + + // 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); + + firstTick = false; if (progress >= Distance) { - progress = Distance; mobile.SetCenterPosition(self, To); mobile.Facing = ToFacing; @@ -546,6 +557,11 @@ namespace OpenRA.Mods.Common.Activities protected override MovePart OnComplete(Actor self, Mobile mobile, Move parent) { 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; } }