From 2233a76e2a307d613cd020ef9f1217b71e9ae331 Mon Sep 17 00:00:00 2001 From: wraitii Date: Tue, 10 Sep 2019 18:11:07 +0000 Subject: [PATCH] Fix units sometimes turning around when fleeing (introduced by D1987/99a341f379) D1987/99a341f379 introduced logic to predict the target movement, which fixed unit chasing. However, sometimes fleeing units would then predict that their target will end up in front of them, so they turned around towards the attacker. This is fixed by not anticipating the position when it would cause the vector towards to target to change direction. Reported By: Freagarach Tested By: Freagarach Fixes #5541 Differential Revision: https://code.wildfiregames.com/D2275 This was SVN commit r22885. --- .../simulation2/components/CCmpUnitMotion.cpp | 26 ++++++++++++++----- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/source/simulation2/components/CCmpUnitMotion.cpp b/source/simulation2/components/CCmpUnitMotion.cpp index 64cbb06ad2..43baeac0d3 100644 --- a/source/simulation2/components/CCmpUnitMotion.cpp +++ b/source/simulation2/components/CCmpUnitMotion.cpp @@ -1056,28 +1056,40 @@ bool CCmpUnitMotion::ComputeTargetPosition(CFixedVector2D& out, const MoveReques return true; } - CmpPtr cmpPosition(GetSimContext(), moveRequest.m_Entity); - if (!cmpPosition || !cmpPosition->IsInWorld()) + CmpPtr cmpTargetPosition(GetSimContext(), moveRequest.m_Entity); + if (!cmpTargetPosition || !cmpTargetPosition->IsInWorld()) return false; if (moveRequest.m_Type == MoveRequest::OFFSET) { // There is an offset, so compute it relative to orientation - entity_angle_t angle = cmpPosition->GetRotation().Y; + entity_angle_t angle = cmpTargetPosition->GetRotation().Y; CFixedVector2D offset = moveRequest.GetOffset().Rotate(angle); - out = cmpPosition->GetPosition2D() + offset; + out = cmpTargetPosition->GetPosition2D() + offset; } else { - out = cmpPosition->GetPosition2D(); + out = cmpTargetPosition->GetPosition2D(); // If the target is moving, we might never get in range if we just try to reach its current position, // so we have to try and move to a position where we will be in-range, including their movement. - // Since we request paths asynchronously a the end of our turn, we need to account for twice the movement speed. + // Since we request paths asynchronously a the end of our turn and the order in which two units move is uncertain, + // we need to account for twice the movement speed to be sure that we're targeting the correct point. // TODO: be cleverer about this. It fixes fleeing nicely currently, but orthogonal movement should be considered, // and the overall logic could be improved upon. CmpPtr cmpUnitMotion(GetSimContext(), moveRequest.m_Entity); if (cmpUnitMotion && cmpUnitMotion->IsMoveRequested()) - out += (out - cmpPosition->GetPreviousPosition2D()) * 2; + { + CmpPtr cmpPosition(GetEntityHandle()); + if (!cmpPosition || !cmpPosition->IsInWorld()) + return true; // Still return true since we don't need a position for the target to have one. + + CFixedVector2D tempPos = out + (out - cmpTargetPosition->GetPreviousPosition2D()) * 2; + + // Check if we anticipate the target to go through us, in which case we shouldn't anticipate + // (or e.g. units fleeing might suddenly turn around towards their attacker). + if ((out - cmpPosition->GetPosition2D()).Dot(tempPos - cmpPosition->GetPosition2D()) >= fixed::Zero()) + out = tempPos; + } } return true; }