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.
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)
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
Can't understand how collision bit mask works
That is not how collision handling works. When two bodies are in intersection, physics engine performs logical AND
operator between current's body collisionBitMask
and other's body categoryBitMask
:
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.
The source.
So the result depending on how you set categoryBitMask
on those two bodies. A default value for categoryBitMask
is 0xFFFFFFFF
, means all bits set. So when you perform & between 0xFFFFFFFF
and 0b10
or 0b01
, the result would be non-zero value, thus the collision.
So for example, setting your bodies like this:
spriteA.physicsBody?.categoryBitMask = 0b01
spriteA.physicsBody?.collisionBitMask = 0b01
and
spriteB.physicsBody?.categoryBitMask = 0b10
spriteB.physicsBody?.collisionBitMask = 0b10
will give you the result you want. Also, this is probably not the exact setup you need, it is just a simple example, and you will have to change values according to your needs. In this case, spriteA will collide only with bodies which have categoryBitMask
set to 0b01
. Same goes for spriteB, it will collide with bodies which have categoryBitMask
set to 0b10
.
Also, in the case if you don't want these sprites to be able to collide with anything, simply set their collisionBitMask
properties to 0.
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.
Using SKPhysics body for detecting collisions
The bullet is ‘moving around’ the player instead of through it because you have collisions turned on. All physics bodies collide with all others by default, whereas by default there are no contacts registered between physics bodies.
The first thing to do is to turn off collisions between the player and the bullet and vice-versa whilst leaving all other collisions unaffected:
playerNode.physicsBody?.collisionBitMask &= ~physicsCategory.bullet
bullet.physicsBody?.collisionBitMask &= ~physicsCategory.player
Edit: my step-by-step guide for collisions and contacts:
https://stackoverflow.com/a/51041474/1430420
A guide to collision and contactTest bit masks:
https://stackoverflow.com/a/40596890/1430420
Manipulating bit masks to turn individual collisions and contacts off and on.
https://stackoverflow.com/a/46495864/1430420
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.
Related Topics
Any Way to Replace Characters on Swift String
Swift 2 - Unsafemutablepointer≪Void≫ to Object
Why Is Swift Compile Time So Slow
Swift Beta Performance: Sorting Arrays
Swift Optional Escaping Closure Parameter
Check Password String Strength Criteria in Swift
What Is the Meaning of the '#' Mark in Swift Language
Swift Function Object Wrapper in Apple/Swift
How to Convert a Decimal Number to Binary in Swift
Shall We Always Use [Unowned Self] Inside Closure in Swift
Alamofire Get API Request Not Working as Expected
Segue and Button Programmatically Swift
Xcode 8 Beta 3 Use Legacy Swift Issue
What Is the "Some" Keyword in Swift(Ui)