Logo 3.5Cats_AndHalfAFish

3.5Cats_AndHalfAFish

Rooms with Doors.

October 30, 2020 Shade, Godot : Layers and Masks
... where I learn about collision layers and masks.

Note : Godot 3.2.3, Blender 2.83.


I spent a fair amount of time creating rooms and adding doors to one of the levels in the castle. This involved quite a bit of going back and forth between Blender and Godot to check room sizes as well as game logic (the fun part !).

Rooms with doors.
Rooms with doors.

Since it's been a LONG time since I did any coding, I also spent half a day trying to figure out why mouse_over() wasn't working on the new doors. 😐
As it turned out, my younger self had decided on 'raycasting' (out of necessity - and yes, I completely forgot about that) rather than my goto 'mouse_entered' and 'mouse_exited' methods ...

And that brings me to another important point : CollisionObject (Area and StaticBody) layer and mask settings !
Up until now, I hadn't been paying much attention to these settings. Mostly because I had no idea what they did, or why I would want to use them.

Collision layers and masks.
Collision layers and masks.

This is what the Godot documentation has to say :
. collision_layer : where -this- object is in
. collision_mask : what layers this object will scan for -other- objects to interact with
Note : I think the decimal calculations on that page are wrong. If you convert 0b1101 to decimal, you get 13, not 26 (the 1st bit is pow(2,0) !). Also, if you hold the mouse over one of the little squares in the editor, it will show you a 'value'. This is the value specific for that particular layer. So, layers 1, 3, and 4 give us : 1 + 4 + 8 = 13.

So. Why is this important ?
Well, if you leave everything at the default values of layer=1 and mask=1, then, everything will interact with everything. For instance, the collisionshapes for the walls will register a collision with other walls (if they intersect), with doors, and even with area nodes that I use for mouse interactions. The floor will pick up a huge number of collisions if walls, doors, player, pickups, etc intersect even a little bit with the floor.
Probably not what you want.

Also, if you're using raycasting for all interactions of the player with his environment, these settings are important :

Raycasting in Godot.
Raycasting in Godot.

Raycasting returns a Dictionary with information about the first object the ray (going from the mouse position to a certain distance inside the game world) detects.
So, sometimes, overlapping StaticBodies and Areas can make things a bit complicated (see below) ...

Some important parameters are :
1) 'collide_with_bodies' and 'collide_with_areas' : you can specify if you want to detect only Area nodes, only PhysicsBody nodes (eg. StaticBody), or both.
2) 'exclude' : you can exclude a list of specific objects from being detected.
3) 'collision_mask' : speficy the layers that should be scanned by the ray.

Before I started using layers and masks, my code looked like this (see my earlier post for more info) :

Raycasting in Godot : earlier version.

I speficied that I'm only interested in Area nodes (and not eg. the StaticBody of a door) and that the ray should ignore the player. Further down the code, I then specified what I wanted to do with each of the Area nodes detected (eg. the door 'hotspot' node for detecting mouse clicks, and the door 'push zone' that prevents the player from being in the way of a door opening).

Door with Area and PhysicsBody nodes.
Door with Area and PhysicsBody nodes.

But this approach gave me some trouble when I was trying to change the mouse cursor to indicate that the player could interact with the door :

Changing shape of pointer.

As you can see, the door collisionshape is filtered out, but the push zone is blocking (in front of) the door hotspot node.

I fixed this problem by using masks and layers.

Raycasting with layers and masks.

I have placed the player in layer 32, and for now, he is not scanning for anything (mask=64, but no objects will be placed in that layer).
The push zone ('Z_DOOR') is present in layer 2 and scans for the player. The hotspot area ('DOOR_HSL') is placed in layer 4 and doesn't scan for anything (it only interacts with the mouse).
I can now adjust the raycast code to only scan layer 4 :

Raycasting in Godot : latest version.

The result :


There is something else that I may need to investigate, and that's the 'monitoring' and 'monitarable' settings, also for CollisionObjects. But that will be something for the future. =)