Physics2D.IgnoreLayerCollision not working as expected.

Hello,

This is the first question I’ve asked in Unity forums. I’ve been trying to solve this issue for weeks.

So I’m building a 2D Metroidvania and would like to implement one-way platforms in certain situations. I’m using a Kinematic character controller and Tilemaps for the environment layout, so Platform Effectors are not an Ideal solution. I have a method I wrote for solving which detects if the player is above a platform on a special one-way platform layer and converts the platform to a trigger if they are not.

I would like to change this method to use Physics2D.IgnoreLayerCollision rather than .IsTrigger so that enemies and such can stand on a one-way platform while the player can move freely through it. When trying to do this however, ignore layer collision does not seem to work in real-time. When I bring up the layer collision matrix, it shows what I’m intending to do, but the collisions in-game only comply with their defaults.

Below is the method in question, it is run on Update.

protected virtual void TwoWayPlatforms()
{
abovePlatform = Physics2D.BoxCast(new Vector2(transform.position.x, transform.position.y - 1.5f), new Vector2(1, .5f), 0f, Vector2.down, 1f, passPlatformLayer);
if (abovePlatform && velocity.y <= 0 && platformTime <= 0)
{
Physics2D.IgnoreLayerCollision(6, 9, false);
}
else
{
Physics2D.IgnoreLayerCollision(6, 9, true);
}
if (!Grounded)
{
platformTime -= Time.deltaTime;
}
}

Additionally, I tried a workaround which switches the player’s layer to a “passable layer” which ignores collisions between platform and player. In the inspector their layer changes, but once again the intended effect is not achieved.

Is their something about the Layer Collision Matrix or Physics2D.IgnoreLayerCollision that I’m missing or did I find a bug?

I’m developing currently in version 2020.3 LTS.

Changing the layers doesn’t affect existing contacts, only new ones. Going through all existing contacts each time you change this could get prohibitibly expensive. If you want to force contacts to be recalculated then use the Rigidbody2D.simulated property and turn it off then on again. Contacts will be re-evaluated for that body only.

Of course I’m guessing this might be your issue so beyond that, no idea.

1 Like

Thank you MelvMay for responding so quickly! the Rigidbody2D.simulated property would work, but I would arrive at the same problem as I do with .IsTrigger. The player needs to have simulated checked to make sure all other collisions are able to take place in the scene, which leaves me with toggling the platform colliders. If any other object which reacts to gravity sits on the one-way platforms while Rigidbody2D.simulated gets toggled, they will fall through.

Perhaps it would be best for me to design around this issue.

Out of curiosity, if Physics2D.IgnoreLayerCollision is not designed for the purpose of quickly modifying contacts this way, what is it for?

I only said toggle the simulated property. Doing that doesn’t instantly cause things to fall through, the same resting contact will be calculated next frame but any modifications you’ve made to the layer collisions will cause those ones to be filtered out.

Layer collisions are for future contacts. We’re looking at adding in a refilter option so you can explicitly choose which ones to refilter but the simulated toggle does a similar thing indirectly. Downside is it does affect the enter/stay/exit state.

Thanks again for the clarification. After some trial and error, I’ve decided to stick with using the Collider.isTrigger bool. It may be my lack of experience, but I couldn’t get the simulated property to work as smoothly because the boxcast wouldn’t see the object I’m attempting to alter. I did come up with a relatively “hacky” solution to get my desired effect. In addition to the passable platforms layer I can set up a duplicate proxy layer for enemy collisions that doesn’t ever affect the player. This way the player can pass through passable platforms and enemies can walk across the same space unaffected.

Well it won’t if you leave it off because it’s not there. I said toggle this off then on, not leave it off.

1 Like

Understood. This sounds like the solution I’ve been looking for, but I’m not quite sure logically when to toggle off and on and I’m having trouble finding any examples on the web that do this type of contact re-evaluation. Would it be wise to repeatedly toggle simulated during every frame? That seems off to me, but it also seems like that would be required in order to logically be able to jump “through” platforms, search below the player object, and alter the layer collision.

I was having the same problem, and doing a little digging I found that the Platform Effectors ignore global collision settings in favor of their own. So even though you’re calling IgnoreLayerCollision the Platform Effector is sitting there fat and happy with its own rules. I needed to access useColliderMask, which is a public bool, pass it the platform Game Object my character was standing on, and set useColliderMask to false, THEN tell it to ignoreLayerCollision, and it worked. Hope that helps anyone looking for this solution!

3 Likes

Thank you for actually providing the correct solution!