forked from mirrors/0ad
Further Pushing tweaks: more customisable, longer ranges.
This overall decreases the deathball effect from units walking to each other a bit. - Fix formations - this cleans up a UnitMotion hack for formations, making it possible to increase pushing ranges without breaking closely knit formations like testudo. - Make MINIMAL_PUSHING and the MOVE_EXTENSION configurable, and add a STATIC_EXTENSION as well. - Increase the pushing range significantly, making units sparser. Differential Revision: https://code.wildfiregames.com/D4098 This was SVN commit r25708.
This commit is contained in:
@@ -38,11 +38,6 @@ namespace {
|
||||
*/
|
||||
static const int PUSHING_GRID_SIZE = 20;
|
||||
|
||||
/**
|
||||
* Pushing is ignored if the combined push force has lower magnitude than this.
|
||||
*/
|
||||
static const entity_pos_t MINIMAL_PUSHING = entity_pos_t::FromInt(3) / 10;
|
||||
|
||||
/**
|
||||
* For pushing, treat the clearances as a circle - they're defined as squares,
|
||||
* so we'll take the circumscribing square (approximately).
|
||||
@@ -50,15 +45,15 @@ namespace {
|
||||
*/
|
||||
static const entity_pos_t PUSHING_CORRECTION = entity_pos_t::FromInt(5) / 7;
|
||||
|
||||
/**
|
||||
* When moving, units exert a pushing influence at a greater distance.
|
||||
*/
|
||||
static const entity_pos_t PUSHING_MOVING_INFLUENCE_EXTENSION = entity_pos_t::FromInt(1);
|
||||
|
||||
/**
|
||||
* Arbitrary constant used to reduce pushing to levels that won't break physics for our turn length.
|
||||
*/
|
||||
static const int PUSHING_REDUCTION_FACTOR = 2;
|
||||
|
||||
/**
|
||||
* Maximum distance multiplier.
|
||||
*/
|
||||
static const entity_pos_t MAX_DISTANCE_FACTOR = entity_pos_t::FromInt(2);
|
||||
}
|
||||
|
||||
CCmpUnitMotionManager::MotionState::MotionState(CmpPtr<ICmpPosition> cmpPos, CCmpUnitMotion* cmpMotion)
|
||||
@@ -73,7 +68,12 @@ void CCmpUnitMotionManager::Init(const CParamNode&)
|
||||
// TODO: there seems to be no real reason why we could not register a 'system' entity somewhere instead.
|
||||
CParamNode externalParamNode;
|
||||
CParamNode::LoadXML(externalParamNode, L"simulation/data/pathfinder.xml", "pathfinder");
|
||||
const CParamNode radius = externalParamNode.GetChild("Pathfinder").GetChild("PushingRadius");
|
||||
CParamNode pushingNode = externalParamNode.GetChild("Pathfinder").GetChild("Pushing");
|
||||
|
||||
// NB: all values are given sane default, but they are not treated as optional in the schema,
|
||||
// so the XML file is the reference.
|
||||
|
||||
const CParamNode radius = pushingNode.GetChild("Radius");
|
||||
if (radius.IsOk())
|
||||
{
|
||||
m_PushingRadius = radius.ToFixed();
|
||||
@@ -86,7 +86,25 @@ void CCmpUnitMotionManager::Init(const CParamNode&)
|
||||
}
|
||||
else
|
||||
m_PushingRadius = entity_pos_t::FromInt(8) / 5;
|
||||
m_PushingRadius = m_PushingRadius.Multiply(PUSHING_CORRECTION);
|
||||
|
||||
const CParamNode minForce = pushingNode.GetChild("MinimalForce");
|
||||
if (minForce.IsOk())
|
||||
m_MinimalPushing = minForce.ToFixed();
|
||||
else
|
||||
m_MinimalPushing = entity_pos_t::FromInt(2) / 10;
|
||||
|
||||
const CParamNode movingExt = pushingNode.GetChild("MovingExtension");
|
||||
const CParamNode staticExt = pushingNode.GetChild("StaticExtension");
|
||||
if (movingExt.IsOk() && staticExt.IsOk())
|
||||
{
|
||||
m_MovingPushExtension = movingExt.ToFixed();
|
||||
m_StaticPushExtension = staticExt.ToFixed();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_MovingPushExtension = entity_pos_t::FromInt(5) / 2;
|
||||
m_StaticPushExtension = entity_pos_t::FromInt(2);
|
||||
}
|
||||
}
|
||||
|
||||
void CCmpUnitMotionManager::Register(CCmpUnitMotion* component, entity_id_t ent, bool formationController)
|
||||
@@ -212,7 +230,7 @@ void CCmpUnitMotionManager::Move(EntityMap<MotionState>& ents, fixed dt)
|
||||
it->second.push = CFixedVector2D();
|
||||
}
|
||||
// Only apply pushing if the effect is significant enough.
|
||||
if (it->second.push.CompareLength(MINIMAL_PUSHING) > 0)
|
||||
if (it->second.push.CompareLength(m_MinimalPushing) > 0)
|
||||
{
|
||||
// If there was an attempt at movement, and the pushed movement is in a sufficiently different direction
|
||||
// (measured by an extremely arbitrary dot product)
|
||||
@@ -255,16 +273,17 @@ void CCmpUnitMotionManager::Push(EntityMap<MotionState>::value_type& a, EntityMa
|
||||
// Exception: units in the same control group (i.e. the same formation) never push farther than themselves
|
||||
// and are also allowed to push idle units (obstructions are ignored within formations,
|
||||
// so pushing idle units makes one member crossing the formation look better).
|
||||
if (a.second.controlGroup != INVALID_ENTITY && a.second.controlGroup == b.second.controlGroup)
|
||||
bool sameControlGroup = a.second.controlGroup != INVALID_ENTITY && a.second.controlGroup == b.second.controlGroup;
|
||||
if (sameControlGroup)
|
||||
movingPush = 0;
|
||||
|
||||
if (movingPush == 1)
|
||||
return;
|
||||
|
||||
entity_pos_t combinedClearance = (a.second.cmpUnitMotion->m_Clearance + b.second.cmpUnitMotion->m_Clearance).Multiply(m_PushingRadius);
|
||||
entity_pos_t combinedClearance = (a.second.cmpUnitMotion->m_Clearance + b.second.cmpUnitMotion->m_Clearance).Multiply(PUSHING_CORRECTION);
|
||||
entity_pos_t maxDist = combinedClearance;
|
||||
if (movingPush)
|
||||
maxDist += PUSHING_MOVING_INFLUENCE_EXTENSION;
|
||||
if (!sameControlGroup)
|
||||
maxDist = combinedClearance.Multiply(m_PushingRadius) + (movingPush ? m_MovingPushExtension : m_StaticPushExtension);
|
||||
|
||||
CFixedVector2D offset = a.second.pos - b.second.pos;
|
||||
if (offset.CompareLength(maxDist) > 0)
|
||||
@@ -301,11 +320,12 @@ void CCmpUnitMotionManager::Push(EntityMap<MotionState>::value_type& a, EntityMa
|
||||
offsetLength = fixed::Zero();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// The formula expects 'normal' pushing if the two entities edges are touching.
|
||||
entity_pos_t distanceFactor = movingPush ? (maxDist - offsetLength) / (maxDist - combinedClearance) : combinedClearance - offsetLength + entity_pos_t::FromInt(1);
|
||||
distanceFactor = Clamp(distanceFactor, entity_pos_t::Zero(), entity_pos_t::FromInt(2));
|
||||
entity_pos_t distanceFactor = maxDist - combinedClearance;
|
||||
if (distanceFactor <= entity_pos_t::Zero())
|
||||
distanceFactor = MAX_DISTANCE_FACTOR;
|
||||
else
|
||||
distanceFactor = Clamp((maxDist - offsetLength) / distanceFactor, entity_pos_t::Zero(), MAX_DISTANCE_FACTOR);
|
||||
|
||||
// Mark both as needing an update so they actually get moved.
|
||||
a.second.needUpdate = true;
|
||||
@@ -314,6 +334,6 @@ void CCmpUnitMotionManager::Push(EntityMap<MotionState>::value_type& a, EntityMa
|
||||
CFixedVector2D pushingDir = offset.Multiply(distanceFactor);
|
||||
|
||||
// Divide by an arbitrary constant to avoid pushing too much.
|
||||
a.second.push += pushingDir.Multiply(movingPush ? dt : dt / PUSHING_REDUCTION_FACTOR);
|
||||
b.second.push -= pushingDir.Multiply(movingPush ? dt : dt / PUSHING_REDUCTION_FACTOR);
|
||||
a.second.push += pushingDir.Multiply(dt / PUSHING_REDUCTION_FACTOR);
|
||||
b.second.push -= pushingDir.Multiply(dt / PUSHING_REDUCTION_FACTOR);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user