1
0
forked from 0ad/0ad

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.
This commit is contained in:
wraitii 2019-09-10 18:11:07 +00:00
parent 4b0b545fa9
commit 2233a76e2a

View File

@ -1056,28 +1056,40 @@ bool CCmpUnitMotion::ComputeTargetPosition(CFixedVector2D& out, const MoveReques
return true;
}
CmpPtr<ICmpPosition> cmpPosition(GetSimContext(), moveRequest.m_Entity);
if (!cmpPosition || !cmpPosition->IsInWorld())
CmpPtr<ICmpPosition> 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<ICmpUnitMotion> cmpUnitMotion(GetSimContext(), moveRequest.m_Entity);
if (cmpUnitMotion && cmpUnitMotion->IsMoveRequested())
out += (out - cmpPosition->GetPreviousPosition2D()) * 2;
{
CmpPtr<ICmpPosition> 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;
}