Hey, I’m working on a 2D RTS where the map is basically a stack of platforms connected by stairs:

The issue I’m running into is getting the stairs to work properly. Units need to be able to selectively ignore the edge colliders associated with the stairs when they want to walk past them. I’ve considered just not using the built-in physics engine but I’d like to be able to leverage it later if needed.
My initial attempt was using oncollisionenter2d() to detect when a unit collides with stairs and then call Physics2D.IgnoreCollision() between the stair collider and the unit collider. This has a few issues
- The collision between the stairs and the unit affects the unit’s position prior to oncollisionenter2d(). In order to prevent a “jitter” from this movement i’ll have to constantly save each units position in FixedUpdate() and then restore it.
- I have to add additional logic (possibly another collider?) to detect when a unit leaves the stair collider to restore collisions for future checks.
An additional issue is when you have scenarios where a horizontal platform is right above the stairs (as in the left side of the image). In these cases, if a unit wants to descend the stairs they’ll have to be able to ignore the horizontal platform.
I think I can solve these issues with additional colliders on every unit and constantly calling oncollisionenter2d() against pretty much every platform+stair segment but I was hoping someone else might know of a more elegant solution?
Well you seem to have discovered that you cannot use the rigidbody collision response because you’re defining logic in-between the detection and response which means you need to exclusively use physics queries for detection and/or use Kinematic bodies with UseFullKinematicContacts active so you get contacts between kinematic and static/kinematic. You can retrieve contacts with Rigidbody2D.GetContacts, even filter them as you would like with ContactFilter2D.
This way you can use contacts to ensure you don’t overlap/move through stuff and can choose which directions you can move. You can then decide which contacts you want to ignore and “pass through”. I don’t want to get into the actual logic you want but as a basis for your decisions on how to move I would think you only care about intersections, points, collision normals and maybe some info you’ve associated with the collider.
I do have a basic kinematic controller no rigidbody collision response but only its own that ensures no overlap. You could do worse than look here. There’s also another here that exclusively uses GetContacts to decide when it’s grounded. A similar set-up can be used to retrieve contacts.
Here’s the line that decides if the character is grounded. The ContactFilter is defined so that only a collision normal coming within an arc from below is considered ground as well as specific layers. Imagine you doing the same but looknig for stairs.
I just think if you use a dynamic body and you’re getting contacts via collision callbacks (which is obviously after the collision response has been applied) and then you want to somehow counter that, you’re making it super hard.
1 Like
Alternately you could have the horizontal parts (floor) be something you can collide with (using a Dynamic Rigidbody2D) and put the diagonal (stairs) onto another collision layer and simply use queries to detect this and calculate and control your movement for these stairs. This allows you to control when you move up/down stairs or pass through them but don’t need to deal with col-det for standing on the ground (non-stairs).
1 Like
This is awesome! Thanks so much for all the info. Ill dig in and let you know what i end up with
1 Like