How Does Collisionbitmask Work? Swift/Spritekit

How does collisionBitMask work? Swift/SpriteKit

You can't get desired behaviour because you haven't set category, contact and collision bit masks properly. Here is an example on how you can set this to work:

greenBall.physicsBody?.categoryBitMask = GreenBallCategory //Category is GreenBall
greenBall.physicsBody?.contactTestBitMask = RedBarCategory | WallCategory //Contact will be detected when GreenBall make a contact with RedBar or a Wall (assuming that redBar's masks are already properly set)
greenBall.physicsBody?.collisionBitMask = GreenBallCategory | RedBallCategory | WallCategory //Collision will occur when GreenBall hits GreenBall, RedBall or hits a Wall

redBall.physicsBody?.categoryBitMask = RedBallCategory //Category is RedBall
redBall.physicsBody?.contactTestBitMask = GreenBarCategory | GreenBallCategory | WallCategory //Contact will be detected when RedBall make a contact with GreenBar , GreenBall or a Wall
redBall.physicsBody?.collisionBitMask = RedBallCategory | GreenBallCategory | WallCategory //Collision will occur when RedBall meets RedBall, GreenBall or hits a Wall

let borderBody = SKPhysicsBody(edgeLoopFromRect: self.frame)
self.physicsBody = borderBody
self.physicsBody?.friction = 0
borderBody.contactTestBitMask = RedBallCategory | GreenBallCategory //Contact will be detected when red or green ball hit the wall
borderBody.categoryBitMask = WallCategory
borderBody.collisionBitMask = RedBallCategory | GreenBallCategory // Collisions between RedBall GreenBall and a Wall will be detected

I would recommend you to read docs about categoryBitMask which is a mask that defines which categories a physics body belongs to:

Every physics body in a scene can be assigned to up to 32 different
categories, each corresponding to a bit in the bit mask. You define
the mask values used in your game. In conjunction with the
collisionBitMask and contactTestBitMask properties, you define which
physics bodies interact with each other and when your game is notified
of these interactions.

contactTestBitMask - A mask that defines which categories of bodies cause intersection notifications with a current physics body.

When two bodies share the same space, each body’s category mask is
tested against the other body’s contact mask by performing a logical
AND operation. If either comparison results in a nonzero value, an
SKPhysicsContact object is created and passed to the physics world’s
delegate. For best performance, only set bits in the contacts mask for
interactions you are interested in.

collisionBitmask - A mask that defines which categories of physics bodies can collide with this physics body.

When two physics bodies contact each other, a collision may occur.
This body’s collision mask is compared to the other body’s category
mask by performing a logical AND operation. If the result is a nonzero
value, this body is affected by the collision. Each body independently
chooses whether it wants to be affected by the other body. For
example, you might use this to avoid collision calculations that would
make negligible changes to a body’s velocity.

So basically, to set up all these, you should ask your self something like:

Okay, I have a green ball, and a red ball , and wall objects on the scene. Between which bodies I want collisions to occur, or when I want to register contacts? I want a green and a red ball to collide with each other and to collide against the walls. Not a problem. I will first set up categories properly, and then I will set collision bit masks like this:

greenBall.collisionBitMask = GreenBallCategory | RedBallCategory | WallCategory; //greenBall will collide with greenBall, redBall and a wall
redBall.collisionBitMask = GreenBallCategory | RedBallCategory | WallCategory

wall.collisionBitMask = GreenBall | RedBall

Now, I want to detect when some contacts occur (in didBeginContact: method)... But I don't want to get notified about all possible contacts, but rather to be notified just about contacts between balls (contacts between balls and a wall will be ignored). So lets set contactTestBitMasks to achieve this:

greenBall.contactTestBitMask = GreenBallCategory | RedBallCategory;
redBall.contactTestBitMask = GreenBallCategory | RedBallCategory;

And that's it. The important thing is when you not using contact detection, you should not set contactTestBitMask. This is because of performance reasons. If you don't need collision detection, and you are interested only in detecting contacts, you can set collisionBitMask = 0.

Important:

Make sure you have set physics world's contact delegate in order to use didBeginContact and didEndContact methods:

self.physicsWorld.contactDelegate = self; //where self is a current scene

Hope this helps a bit.

How does the category bit mask work in SpriteKit?(0xFFFFFFFF)

Categories

You can have 32 different categories. Categories could be vessel, bullets, wall, enemies, etc). If you are interested in collisions and contacts then you need first to set a category for a given objet. For example, vessel category 0, bullets category 1, wall category 2, enemies category 3. As they are bitmask then you have (respectively) 1, 2, 4, 8.
Now categories are more a matter of behavior than identity. Some objects may behave like two different categories: rocks (no category per-se) behave like walls (you bounce on it) and enemies (you can throw bullet at them). Then the categories for rocks would be 2 and 3, as bit mask this give 12. It is not easy to imagine that an object is in different categories, but if you think about behavior sets and not identity sets, that ease to think about it.

Default value for masks are 0xFFFFFFFF meanings that every object is in every possible category and every object collides with every other.
Fine tuning these values can seriously improve the physical engine.

Collisions

Collisions are used to define which objects collides in the physical world. Some objects may cross to each other while other bounce. Example: a magical bullet may travel walls, while ordinary ones are stopped at walls.

magicBullet.physicsBody.categoryBitMask = 1
ordinaryBullet.physicsBody.categoryBitMask = 1 // both bullets behave as bullets
wall.physicsBody.categoryBitMask = 2

ordinaryBullet.physicsBody.collisionBitMask = 2 // hits walls
magicBullet.physicsBody.collisionBitMask = 0 // do not physically see walls

Collisions are declared as bit masks because you have to declare which other category a given object is able to physically interact with or not.

Contacts

Contacts are exactly the same as collisions but to capture in your code the fact that two objects are in contact. So if you are interested in ordinary bullets hitting a wall (for magical it is not necessarily interesting):

ordinaryBullet.physicsBody.contactTestBitMask = 2 // want to catch wall hit
magicBullet.physicsBody.contactTestBitMask = 0 // don't bother

A slightly more complex example

Now if you add another kind of object say hard wall, that could give:

magicBullet.physicsBody.categoryBitMask = 1
ordinaryBullet.physicsBody.categoryBitMask = 1 // both bullets behave as bullets
wall.physicsBody.categoryBitMask = 2 // some bullets may travel through
hardWall.physicsBody.categoryBitMask = 4 // nothing can travel through thses

ordinaryBullet.physicsBody.collisionBitMask = 6 // hits walls and hard walls
magicBullet.physicsBody.collisionBitMask = 4 // do not physically see walls but only hard walls

ordinaryBullet.physicsBody.contactTestBitMask = 6 // want to catch all wall hit
magicBullet.physicsBody.contactTestBitMask = 4 // just want to catch hard wall hitting

collisionBitMask values not working in SpriteKit

You are overwriting collisionBitMask when you set it up for the second time. You should set up an OR bitmask with the symbol |.

Replace

self.physicsBody?.collisionBitMask = UInt32(PhysicsCategory.Obstacle)
self.physicsBody?.collisionBitMask = UInt32(PhysicsCategory.Ground)

with:

self.physicsBody?.collisionBitMask = UInt32(PhysicsCategory.Obstacle) | UInt32(PhysicsCategory.Ground)

and

self.physicsBody?.collisionBitMask = UInt32(PhysicsCategory.Player)
self.physicsBody?.collisionBitMask = UInt32(PhysicsCategory.Ground)

with:

self.physicsBody?.collisionBitMask = UInt32(PhysicsCategory.Player) | UInt32(PhysicsCategory.Ground)

collisionBitMask doesn't work

If I understood correctly, you want the player and the NPC to "bounce off the walls", but not bounce off each other. The solution would be to not set their collisionBitMasks to each other‘s categoryBitMasks, but only their contactTestBitMasks.

As to why the NPC needs to be dynamic to bounce off the walls: One participant must be dynamic for a collision to show effect: the one that bounces off.

SpriteKit: why node in collision has category bit mask of 4294967295 when this category was never assigned to a node

categoryBitMask is a UInt32 and its max value is 4294967295 which is also its default value (all bits set). Quote from docs:

Every physics body in a scene can be assigned to up to 32 different
categories, each corresponding to a bit in the bit mask. You define
the mask values used in your game. In conjunction with the
collisionBitMask and contactTestBitMask properties, you define which
physics bodies interact with each other and when your game is notified
of these interactions.

The default value is 0xFFFFFFFF (all bits set).

Swift Sprite kit Collision Bitmask

You are not understanding how didBeginContact works. Basically what is happening is when any 2 nodes make a contact, the first thing that the system will do is make sure that the category and contact bit masks line up to make a valid contact. If it does, then didBeginContact gets called. now inside this function, you have the 2 arbitrary nodes that made contact, called bodyA, and bodyB. What you need to do first, is figure out what bodyA and bodyB are. So the first thing you do, is check the categoryBitMask.

   if(contact.bodyA.categoryBitMask == HERO) then contact.bodyA is a hero

Now that we know what categories these nodes refer to, we can then check what the node actually is. To do this, you can either check the name of the node

  if(contact.bodyA.node.name == "Hero") then bodyA is the hero 

Or compare the node itself

  if(contact.bodyA.node == heroNode) then bodyA is the hero

Now do the same for bodyB.

You have established at this point what your nodes are, you can proceed with the outcome results that you need based on this information.

If Hero hits both enemy nodes at the same time, then you need to handle this as well. What is going to happen is 2 calls to didBeginContact will happen, you need to find a way to remember this, and do your contact code in either the didEvaluateActions, or didSimulatePhysicsMethod. I do not remember which of these follows didBeginContact, so you will have to test it out on your own.



Related Topics



Leave a reply



Submit