Elongated Footprint Support#2829
Elongated Footprint Support#2829KyleAnthonyShepherd wants to merge 15 commits intobeyond-all-reason:masterfrom
Conversation
Change the collision detection and "keep separated" push logic in HandleObjectCollisions/HandleUnitCollisions to use the unit's UnitDef footprint (CSolidObject::xsize/zsize) instead of the MoveDef footprint. This allows elongated units like battleships to have a small square MoveDef for pathfinding (e.g. 2x2) while using a larger rectangular footprint (e.g. 10x2) for collision avoidance. The existing SAT (Separating Axis Theorem) collision test already accounts for unit orientation via frontdir/rightdir, so the asymmetric footprint correctly rotates with the unit. Changes: - HandleObjectCollisions: collider radius and stretch factor now come from collider->CalcFootPrintMaxInteriorRadius/AxisStretchFactor - HandleUnitCollisions: collidee radius and stretch factor now come from collidee->CalcFootPrintMaxInteriorRadius/AxisStretchFactor - SAT::HaveSeparatingAxis: footprint dimensions now come from collider/collidee->GetFootPrint instead of MoveDef->GetFootPrint Pathfinding, TestMoveSquare checks, and ownerRadius (waypoint/arrival) remain based on MoveDef and are unchanged. https://claude.ai/code/session_01Bq9KX9MfLKC5PmwM5YS4fH
The previous change (collider->CalcFootPrintMaxInteriorRadius) had no effect because GroundMoveType initialization overrides the unit's xsize/zsize with MoveDef values (line 530-531). So both the MoveDef and SolidObject methods returned the same values. Fix by reading directly from CSolidObject::footprint, which is set from the UnitDef's footprintX/footprintZ at Unit.cpp:263 and is never overwritten by MoveDef. Specifically: - HandleObjectCollisions: compute collider radius and stretch factor from collider->footprint.x/y - HandleUnitCollisions: compute mobile collidee radius and stretch factor from collidee->footprint.x/y; immobile collidees keep using xsize/zsize (not overridden, so correct) - SAT::HaveSeparatingAxis: use footprint for mobile units (collideeMD != nullptr), keep xsize/zsize for features/immobile (not overridden) https://claude.ai/code/session_01Bq9KX9MfLKC5PmwM5YS4fH
lostsquirrel1
left a comment
There was a problem hiding this comment.
I feel this would be better handled by an explicit footprintX and footprintZ on the unitDef, which the ground move type can use instead for some arbitrary size calculation (which is what it does at the moment.) In fact, it already has it: they are xsize zsize - so you just need a variable to act as an override and then update groundmove to use it for mobile unit <-> unit collisions.
| // true if the unit's UnitDef footprint is significantly non-square (stretch factor > 0.1); | ||
| // gates elongated-footprint collision logic (OBB scan expansion, projected radii, etc.) | ||
| bool hasElongatedFootprint = false; | ||
|
|
||
| // Pre-computed collision geometry derived from the UnitDef footprint (int2). | ||
| // Mobile units have xsize/zsize overridden by MoveDef, so these cache the true | ||
| // physical shape for use in collision detection / OBB tests. | ||
| // Half-extents in world units: ((footprint - 1) * 0.5 * SQUARE_SIZE) per axis. | ||
| float2 footprintHalfExtents; | ||
| // Max half-extent (bounding circle radius): max(footprint.x, footprint.y) - 1) * 0.5 * SQUARE_SIZE. | ||
| float footprintMaxRadius = 0.0f; |
There was a problem hiding this comment.
The footprint changes should be applied to the unit def, not the individual unit. Logically all units of the same type will have the same footprint.
There was a problem hiding this comment.
Units of the same unitdef type can have a different effective footprint due to differing moveDef via Spring.MoveCtrl.SetMoveDef though
There was a problem hiding this comment.
That is a good point; though you probably still need to be able to calibrate this at unitDef level. Then override at unit level in code if you need.
There was a problem hiding this comment.
footprintX/Z already exist on the unitdef level. But I think the functionality has been basically reduced to the dimensions needed to place the nanoframe on the ground.
In current master, almost all other unit dimensions are derived from the MoveDef.
So, this PR uses the unitdef footprintX/Z to control collisions and separation IF they are not square.
There was a problem hiding this comment.
Thanks for the clarification. That's fine for mobile unit <-> mobile unit collisions.
There seems to be similar changes for collisions with static units. We can't use elongated collision against buildings because that can interfere with the unit's ability to follow a path given to it by the path finder. We need absolute parity and agreement between the movement and the pathing systems otherwise units can get stuck or behave badly.
mobile units <-> mobile units is fine because the pathing system cannot see mobile units, and mobile units are expected to move around and push each other about.
There was a problem hiding this comment.
Yeah, the torture test in the video above, where a 3x10 long unit with a 3x3 pathfinding movedef is forced to turn a corner in a 3-wide hallway, shows that some degree of "phasing/intangability" is needed to prevent stuck situations.
I suspect there would be a possible construction of a 3x3 pathable passage that a 3x10 would be unable to traverse due to pushout forces.
So some failsafe mechanism to collapse the "collision" volume of a 3x10 unit into its square 3x3 movedef would be needed.
|
With respects to the grey sphere issue: how are you changing that? I believe that should only refer to a unit's collision for projectiles. |
I have done no changes to that subsystem in this PR. But then when I increased the model radius to the long dimension, it was able to push through a crowd of armbats. [Also did tests with armthor. Armthors with a small model radius were not pushing other armthors away, but armthors wirh a large model radius easily pushed away other armthors] |
|
That's right, model radius, is correct for determining unit <-> unit collision. |
Executive Summary:
PR to allow mobile units with a non-square
footprintto collide and separate like a rectangle, and not as a square dependent onmovedef. This new feature is explicitly gated behindmodInfo.allowSepAxisCollisionTest = true. And collision and separation logic for standard square movedef units should be untouched.This PR was inspired by:
See videos for tests on 3x10 long units (using a 3x3 movedef), and 9x3 wide units (using a 9x9 movedef):
long_ship.mp4
wide_ship3.mp4
One note, the grey model sphere must be large enough to allow units (elongated or not) to push other units out of the way. Related to
CGroundMoveType::CheckCollisionSkid()I think.This is a separate bug? that should be addressed in another PR.