Detecting one way collision

Godot Version

v4.4.1.stable.mono.official [49a5bc7b6]

Question

If you have CharacterBody2D with CollisionShape2D, you can conveniently detect if it collides with something using this:

if (GetSlideCollisionCount() > 0)
   //handle collision

The issues start when you want to detect what exactly are you colliding with. In my case I need to detect if this is one way collision from TileMapLayer. And I absolutely can’t figure out how to do it.

Real life use case - I want object to continue falling down instead of being locked on platforms (which are one way collision).

You should go to the draw section in the tileset, scroll to the bottom of the physics layer properties, enable the “polygon_0_one_way” checkbox and draw the collision shapes to the tiles you want to have a one way collision

1 Like

I don’t know if I understand it right, but I already have platforms with one way collision set up, and they work. But certain projectiles should fly through from both ways. And this is why I need a way to detect if this is one way collision, and ignore it.

In theory I could give different mask to one way collision tiles, but I feel like this will complicate other things, since this way it will stop being default terrain.

try giving the projectiles a different collision layer(eg. 5) and add a collision mask to the non-one_way_collision tiles (eg. 5, the same as the projectile’s collision layer), and because those layers we’re not used before, you’ll be good,

but if that’s not what you wanted, please show some screenshots or recodrdings of the project :smiley:

1 Like

If I won’t figure out anything better I will try dealing with layers. I would want to avoid it since I will have to adjust layers and masks of everything that can potentially interact with one way collision, and that feels like more work than simple script check.

To fully simplify the problem - that piece of code in original post is in Process and happens on loop. It properly detects if CollisionShape2D collides with anything else. And once that collision happens, I need to know if it’s one way collision tile from TileMapLayer, or not. So for example:

if (GetSlideCollisionCount() > 0)
{
   if (isOneWayCollision && isTileMapLayer)
      GD.Print("One way collision tile detected");
   else
      GD.Print("Normal collision detected");
}

I want to do an actual useful things with that but I think this properly shows what I want to do in the first place.

Update:

int slideCollisionCount = GetSlideCollisionCount();
if (slideCollisionCount > 0) {
  for (int i = 0; i < slideCollisionCount; i++) {
    KinematicCollision2D collision = GetSlideCollision(i);
    var collider = collision.GetCollider() as Node2D;
    if (collision.GetColliderShape() is CollisionShape2D shape) {
      bool isOneWay = shape.OneWayCollision;
      GD.Print($"Collider: {collider?.Name}, OneWay: {isOneWay}");
    }
  }
}

I think this has chances of working, but if (collision.GetColliderShape() is CollisionShape2D shape) doesn’t detect collision from TileMapLayer. So I’m still nowhere.

Edit

I’ve started getting somewhere, but even if I get the collision type, it leads me nowhere, because projectile still collides with it and collision can’t be ignored. I didn’t save the code, but it was from ChatGPT, so I would not recommend using it, he is not very good at Godot 4, and especially not Mono.

I had to use layers. I’ve set one way platforms as layer 4, and made it interact (mask) with layer player and layer mobs. I don’t like this solution because now I need to mark everything to collide with it (mask 4) except that one single projectile. Sometimes easy problems require complex solutions I guess.

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.