Game Engine Collison Bitmask... Why 0X01 etc

Game Engine Collison Bitmask... Why 0x01 etc?

The reason for the bitmasks is that it enables you / the program to easily and very quickly compute wether a collision between two objects occurs or does not occur. Therefore: yes it is some sort of optimization.

Assuming we have the three categories

  • missile 0x1 << 0
  • player 0x1 << 1
  • wall 0x1 << 2

Now we have a Player instance, its category is set to player. Its collision bitmask is set to missile | player | wall (+ instead of | works too) since we want to be able to collide with all three types: other players, the level walls and the bullets / missiles flying around.

Now we have a Missile with category set to missile and collision bitmask set to player | wall: it does not collide with other missiles but hits players and walls.

If we now want to evaluate wether two objects can collide with each other we take the category bitmask of the first one and the collision bitmask of the second one and simply & them:

The setup described above looks like the following in code:

let player : UInt8 = 0b1 << 0  // 00000001 = 1
let missile : UInt8 = 0b1 << 1 // 00000010 = 2
let wall : UInt8 = 0b1 << 2 // 00000100 = 4

let playerCollision = player | missile | wall // 00000111 = 7
let missileCollision = player | wall // 00000101 = 5

The subsequent reasoning is basically:

if player & missileCollision != 0 {
print("potential collision between player and missile") // prints
}
if missile & missileCollision != 0 {
print("potential collision between two missiles") // does not print
}

We are using some bit arithmetics here, each bit represents a category.
You could simply enumerate the bitmasks 1,2,3,4,5... but then you could not do any math on them. Because you do not know if a 5 as category bitmask is really a category 5 or it was an object of both categories 1 and 4.

However using only bits we can do just that: the only representation in terms of powers of 2 of a 7 is 4 + 2 + 1: therefore whatever object posses collision bitmask 7 collides with category 4, 2 and 1. And the one with bitmask 5 is exactly and only a combination of category 1 and 4 - there is no other way.

Now since we are not enumerating - each category uses one bit and the regular integer has only 32 (or 64) bits we can only have 32 (or 64) categories.

Take a look at the following and a bit more extensive code which demonstrates how the masks are used in a more general term:

let playerCategory : UInt8 = 0b1 << 0
let missileCategory : UInt8 = 0b1 << 1
let wallCategory : UInt8 = 0b1 << 2

struct EntityStruct {
var categoryBitmask : UInt8
var collisionBitmask : UInt8
}

let player = EntityStruct(categoryBitmask: playerCategory, collisionBitmask: playerCategory | missileCategory | wallCategory)
let missileOne = EntityStruct(categoryBitmask: missileCategory, collisionBitmask: playerCategory | wallCategory)
let missileTwo = EntityStruct(categoryBitmask: missileCategory, collisionBitmask: playerCategory | wallCategory)
let wall = EntityStruct(categoryBitmask: wallCategory, collisionBitmask: playerCategory | missileCategory | wallCategory)

func canTwoObjectsCollide(first:EntityStruct, _ second:EntityStruct) -> Bool {
if first.categoryBitmask & second.collisionBitmask != 0 {
return true
}
return false
}

canTwoObjectsCollide(player, missileOne) // true
canTwoObjectsCollide(player, wall) // true
canTwoObjectsCollide(wall, missileOne) // true
canTwoObjectsCollide(missileTwo, missileOne) // false

The important part here is that the method canTwoObjectsCollide does not care about the type of the objects or how many categories there are. As long as you stick with bitmasks that is all you need to determine wether or not two objects can theoretically collide (ignoring their positions, which is a task for another day).

Cocos2d-x v3.0rc1 PhysicsBody Contact Issue

From the Box2D Manual:

-------- Quoted

Collision filtering allows you to prevent collision between fixtures.
For example, say you make a character that rides a bicycle. You want
the bicycle to collide with the terrain and the character to collide
with the terrain, but you don't want the character to collide with the
bicycle (because they must overlap). Box2D supports such collision
filtering using categories and groups. Box2D supports 16 collision
categories. For each fixture you can specify which category it belongs
to. You also specify what other categories this fixture can collide
with. For example, you could specify in a multiplayer game that all
players don't collide with each other and monsters don't collide with
each other, but players and monsters should collide. This is done with
masking bits. For example:

playerFixtureDef.filter.categoryBits = 0x0002; 
monsterFixtureDef.filter.categoryBits = 0x0004;
playerFixtureDef.filter.maskBits = 0x0004;
monsterFixtureDef.filter.maskBits = 0x0002;

Here is the rule for a collision to occur:

uint16 catA = fixtureA.filter.categoryBits; 
uint16 maskA = fixtureA.filter.maskBits;
uint16 catB = fixtureB.filter.categoryBits;
uint16 maskB = fixtureB.filter.maskBits;
if ((catA & maskB) != 0 && (catB & maskA) != 0)
{
// fixtures can collide
}

-------- End of Quote

So the bottom line is that if you want two things to react the same way with each other in terms of collisions, they both must have the same category and mask bits.

For some more a (very good) in-depth discussion of this, go ahead and look at this site (no, it is not mine).

For some other interesting Box2D stuff, look here (this one is mine).

Finding the location of ones in a bit mask - Julia

The best approach probably depends on how you want to handle vectors of hex-values. But here's an approach for processing a single hex which is much faster than the one in the OP:

 function readmsg(x::UInt16)
N = count_ones(x)
inds = Vector{Int}(undef, N)
if N == 0
return inds
end
k = trailing_zeros(x)
x >>= k + 1
i = N - 1
inds[N] = n = 16 - k
while i >= 1
(x, r) = divrem(x, 0x2)
n -= 1
if r == 1
inds[i] = n
i -= 1
end
end
return inds
end


Related Topics



Leave a reply



Submit