cak3_lover
cak3_lover

Reputation: 1938

How to check if 2 CollisionObjects can collide?

let's say I have Obj_A (RigidBody2D) & Obj_B (RigidBody2D)
I want to check if these 2 CAN collide

so far my idea is checking the mutual layers in both their collision_mask & collision_layer

the problem I'm facing is that Obj_A.collision_mask & (collision_layer) does not return an array of the layers and instead returns binary

so is there any inbuilt function to check for it?
or is there some different approach altogether?

Upvotes: 1

Views: 228

Answers (2)

cak3_lover
cak3_lover

Reputation: 1938

I think I've figured it out, turns out it was simpler than I thought :P

func will_collide(obj1,obj2):
    return (obj1.collision_layer & obj2.collision_mask) || (obj1.collision_layer & obj2.collision_mask)

Upvotes: 0

Theraot
Theraot

Reputation: 40220

Use bitwise operations.

Imagine the operation you want, but for a single bit. So a bool. And we want to get true when they are both true. And false otherwise. We write a truth table for that if we want to:

"collision_mask" "collision_layer" desired result
false false false
false true false
true false false
true true true

I'm writing "collision_mask" and "collision_layer" in quotes here as reminder that this is an hypothetical in which they are bool, accounting for only one possible layer (bit).

We observe from the table that, of course, the operation we want is conjunction (and).

Now, the bitwise conjunction operator is &. It works with ints and will perform the operation… bitwise. For example:

var a := 0b1100 # Binary literal for 12
var b := 0b1010 # Binary literal for 10
var c := 0b1000 # Binary literal for  8
print (c == a & b) # true

As you can see, it does not give you a true or false value. Instead what we get is an int where each bit is the result of doing the operation on the bits that are on the same position on the inputs.

In consequence, when we use &, if the inputs have bits that are true 1 on the same position, the bit on that same position but on the result will also be true 1.

Say that in negative terms: if none of bits of the inputs are true 1 on the same position, then all the bits on the result will be false 0.

And we can check that!

Ergo:

if (Obj_A.collision_mask & Obj_B.collision_layer) == 0:
    # no possible collision
    pass

Or, you know, negate it:

if (Obj_A.collision_mask & Obj_B.collision_layer) != 0:
    # possible collision
    pass

And, yes, check both ways:

if (
    (Obj_A.collision_mask & Obj_B.collision_layer) != 0
    and (Obj_A.collision_layer & Obj_B.collision_mask) != 0
):
    # possible collision
    pass

For reference these are the bitwise operators in GDScript:

operation bool alternative bitwise
negation not ! ~
conjunction and && &
disjunction or || |
exclusive disjunction ^

Note that there is a bitwise exclusive disjunction operator (^), but not a corresponding bool operator (there is no xor operator).

I also want to mention that GDScript has bit shifting operators: << and >>.


If you rather not use bitwise operators, you can instead use get_collision_layer_bit and get_collision_mask_bit. With knowledge that there are 32 possible layers, you can do this:

var can_collide := false
for layer in 32:
    if Obj_A.get_collision_mask_bit(layer) and Obj_B.get_collision_layer_bit(layer):
        can_collide = true

if can_collide:
    # possible collision
    pass

That is the same logic that we are executing with the bitwise operations. Except much less succinct and with worse performance.


Also for reference, this is get_collision_mask_bit is implemented:

bool CollisionObject::get_collision_mask_bit(int p_bit) const {
    ERR_FAIL_INDEX_V_MSG(p_bit, 32, false, "Collision mask bit must be between 0 and 31 inclusive.");
    return get_collision_mask() & (1 << p_bit);
}

Which you could write in GDScript like this:

func get_collision_mask_bit(bit:int) -> bool:
    if bit >= 32:
        push_error("Collision mask bit must be between 0 and 31 inclusive.")
        return

    return 0 != collision_mask & (1 << bit)

I bring this up to highlight that these are built ontop of the bitwise operators, and not the other way around.

It is also an example of use of a bit shift operator.

Upvotes: 3

Related Questions