Reputation: 1938
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
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
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 int
s 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