Better fix for formation waltzing, revert 5d96346ac5
.
5d96346ac5
proved unsufficient to fix formation 'waltzing'. This is a
better fix, which makes sure units actually try to reach their
designated offset in the first place.
Further, it removes code that recalculated offsets un-necessarily, which
led to an issue with "sloppy" formations such as open and closed orders.
Fixes #5997
Differential Revision: https://code.wildfiregames.com/D3543
This was SVN commit r24865.
This commit is contained in:
parent
06639a0383
commit
e94e1f1fcf
@ -85,7 +85,6 @@ Formation.prototype.variablesToSerialize = [
|
||||
"formationMembersWithAura",
|
||||
"width",
|
||||
"depth",
|
||||
"oldOrientation",
|
||||
"twinFormations",
|
||||
"formationSeparation",
|
||||
"offsets"
|
||||
@ -146,7 +145,6 @@ Formation.prototype.Init = function(deserialized = false)
|
||||
this.formationMembersWithAura = [];
|
||||
this.width = 0;
|
||||
this.depth = 0;
|
||||
this.oldOrientation = { "sin": 0, "cos": 0 };
|
||||
this.twinFormations = [];
|
||||
// Distance from which two twin formations will merge into one.
|
||||
this.formationSeparation = 0;
|
||||
@ -515,17 +513,12 @@ Formation.prototype.MoveMembersIntoFormation = function(moveCenter, force, varia
|
||||
|
||||
let offsetsChanged = false;
|
||||
let newOrientation = this.GetEstimatedOrientation(avgpos);
|
||||
let dSin = Math.abs(newOrientation.sin - this.oldOrientation.sin);
|
||||
let dCos = Math.abs(newOrientation.cos - this.oldOrientation.cos);
|
||||
// If the formation existed, only recalculate positions if the turning agle is somewhat large.
|
||||
if (!this.offsets || dSin > 1 || dCos > 1)
|
||||
if (!this.offsets)
|
||||
{
|
||||
this.offsets = this.ComputeFormationOffsets(active, positions);
|
||||
offsetsChanged = true;
|
||||
}
|
||||
|
||||
this.oldOrientation = newOrientation;
|
||||
|
||||
let xMax = 0;
|
||||
let yMax = 0;
|
||||
let xMin = 0;
|
||||
|
@ -941,13 +941,14 @@ UnitAI.prototype.UnitFsmSpec = {
|
||||
|
||||
"IDLE": {
|
||||
"enter": function(msg) {
|
||||
// Turn rearrange off. Otherwise, if the formation is idle,
|
||||
// but individual units go off to fight, any death
|
||||
// will rearrange the formation, looking odd.
|
||||
// Turn rearrange off. Otherwise, if the formation is idle
|
||||
// but individual units go off to fight,
|
||||
// any death will rearrange the formation, which looks odd.
|
||||
// Instead, move idle units in formation on a timer.
|
||||
let cmpFormation = Engine.QueryInterface(this.entity, IID_Formation);
|
||||
cmpFormation.SetRearrange(false);
|
||||
this.StartTimer(0, 2000);
|
||||
// Start the timer on the next turn to catch up with potential stragglers.
|
||||
this.StartTimer(100, 2000);
|
||||
this.isIdle = true;
|
||||
this.CallMemberFunction("ResetIdle");
|
||||
return false;
|
||||
|
@ -1007,10 +1007,13 @@ bool CCmpUnitMotion::PossiblyAtDestination() const
|
||||
if (cmpControllerMotion && cmpControllerMotion->IsMoveRequested())
|
||||
return false;
|
||||
|
||||
// In formation, return a match only if we are exactly at the target position.
|
||||
// Otherwise, units can go in an infinite "walzting" loop when the Idle formation timer
|
||||
// reforms them.
|
||||
CFixedVector2D targetPos;
|
||||
ComputeTargetPosition(targetPos);
|
||||
CmpPtr<ICmpPosition> cmpPosition(GetEntityHandle());
|
||||
return cmpObstructionManager->IsInPointRange(GetEntityId(), targetPos.X, targetPos.Y, m_MoveRequest.m_MinRange, m_MoveRequest.m_MaxRange, false);
|
||||
return (targetPos-cmpPosition->GetPosition2D()).CompareLength(fixed::Zero()) <= 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -1072,11 +1075,7 @@ bool CCmpUnitMotion::PerformMove(fixed dt, const fixed& turnRate, WaypointPath&
|
||||
target = CFixedVector2D(shortPath.m_Waypoints.back().x, shortPath.m_Waypoints.back().z);
|
||||
|
||||
CFixedVector2D offset = target - pos;
|
||||
// Idle formations reorder their members to move to their offset, but numerical imprecisions can lead
|
||||
// to small offsets every time. Units would then rotate in-place, looking odd.
|
||||
// If the offset is small enough (epsilon is about 0.000015, so that's 0.0015 which is still irrelevant),
|
||||
// simply don't turn.
|
||||
if (turnRate > zero && offset.CompareLength(fixed::Epsilon() * 100) > 0)
|
||||
if (turnRate > zero && !offset.IsZero())
|
||||
{
|
||||
fixed maxRotation = turnRate.Multiply(timeLeft);
|
||||
fixed angleDiff = angle - atan2_approx(offset.X, offset.Y);
|
||||
|
Loading…
Reference in New Issue
Block a user