Spritekit: Sprites Are Moving Through Each Other with a Physicsbody Already Set

iOS SpriteKit - collisions and contacts not working as expected

To help diagnose these types of problems, I have written a function that can be called from anywhere and which will analyse the current scene and produce a list of what nodes with collide with which others and which collisions my scene will be notified for.

The function is stand-alone and does not need to be told anything about the nodes in the scene.

The function is as follows:

            //MARK: - Analyse the collision/contact set up.
func checkPhysics() {

// Create an array of all the nodes with physicsBodies
var physicsNodes = [SKNode]()

//Get all physics bodies
enumerateChildNodesWithName("//.") { node, _ in
if let _ = node.physicsBody {
physicsNodes.append(node)
} else {
print("\(node.name) does not have a physics body so cannot collide or be involved in contacts.")
}
}

//For each node, check it's category against every other node's collion and contctTest bit mask
for node in physicsNodes {
let category = node.physicsBody!.categoryBitMask
// Identify the node by its category if the name is blank
let name = node.name != nil ? node.name : "Category \(category)"
let collisionMask = node.physicsBody!.collisionBitMask
let contactMask = node.physicsBody!.contactTestBitMask

// If all bits of the collisonmask set, just say it collides with everything.
if collisionMask == UInt32.max {
print("\(name) collides with everything")
}

for otherNode in physicsNodes {
if (node != otherNode) && (node.physicsBody?.dynamic == true) {
let otherCategory = otherNode.physicsBody!.categoryBitMask
// Identify the node by its category if the name is blank
let otherName = otherNode.name != nil ? otherNode.name : "Category \(otherCategory)"

// If the collisonmask and category match, they will collide
if ((collisionMask & otherCategory) != 0) && (collisionMask != UInt32.max) {
print("\(name) collides with \(otherName)")
}
// If the contactMAsk and category match, they will contact
if (contactMask & otherCategory) != 0 {print("\(name) notifies when contacting \(otherName)")}
}
}
}
}

You also need to check these 3 things:

  1. the scene must be a SKPhysicsContactDelegate
  2. You must set physicsWorld.contactDelegate = self
  3. You need to implement one of the optional methods of
    SKPhysicsContactDelegate:

didBeginContact

didEndcontact

The function should be called once you have set up all of your pics - usually at the end of didMoveToView works:

checkPhysics()

When I call this function from the end of my didMoveToView in my practice Swift project, I get the following output:

Optional("shape_blueSquare") collides with Optional("Category
2147483648") Optional("shape_blueSquare") collides with
Optional("shape_redCircle") Optional("shape_blueSquare") collides with
Optional("shape_purpleSquare") Optional("shape_blueSquare") collides
with Optional("shape_yellowTriangle") Optional("shape_redCircle")
collides with Optional("Category 2147483648")
Optional("shape_redCircle") collides with Optional("shape_blueSquare")
Optional("shape_redCircle") notifies when contacting
Optional("shape_purpleSquare") Optional("shape_redCircle") collides
with Optional("shape_yellowTriangle") Optional("shape_redCircle")
notifies when contacting Optional("shape_yellowTriangle")
Optional("shape_purpleSquare") collides with Optional("Category
2147483648") Optional("shape_purpleSquare") collides with
Optional("shape_yellowTriangle") Optional("shape_yellowTriangle")
collides with everything didBeginContact entered for
Optional("shape_purpleSquare") and Optional("shape_redCircle")
didBeginContact entered for Optional("shape_purpleSquare") and
Optional("shape_redCircle") didBeginContact entered for
Optional("shape_yellowTriangle") and Optional("shape_redCircle")

Category 2147483648 is my edge boundary and it does not have a name. I gave it this category to match its collisionBitMask

Please feel free to try this function and let me know if it's useful or if there are any situations it does not handle.

Stop Sprites from Pushing Each Other in SpriteKit

Set a collisionBitMask to 0, so all collisions of this particular object to others will be ignored.

iOS SpriteKit make random moving of sprites and something like collision in space

You have to use forces and velocities instead of SKActions to move the sprites. You also have to set properties like restitution, linearDamping and friction to prevent the lost of speed on collision and movement.

sprite.physicsBody?.restitution = 1.0
sprite.physicsBody?.friction = 0.0
sprite.physicsBody?.linearDamping = 0.0

You can apply a random force to each sprite.

// randomX and randomY are two random numbers.
sprite.physicsBody?.applyForce(CGVectorMake(randomX, randomY))

The sprite also needs a categoryBitMask and collisionBitMask. Each sprite can collide with each other or the edge.

sprite.categoryBitMask = spriteCategory
sprite.collisionBitMask = spriteCategory | edgeCategory

restitution : This property is used to determine how much energy the physics body loses when it bounces off another object. The
property must be a value between 0.0 and 1.0. The default value is
0.2. Availability

friction : The roughness of the surface of the physics body. This property is used to apply a frictional force to physics bodies in
contact with this physics body. The property must be a value between
0.0 and 1.0. The default value is 0.2.

linearDamping : A property that reduces the body’s linear velocity. This property is used to simulate fluid or air friction
forces on the body. The property must be a value between 0.0 and 1.0.
The default value is 0.1. If the value is 0.0, no linear damping is
applied to the object.

How to prevent Spritekit physicsbodies from intersecting during collision?

Not sure if this constitutes as an answer per se, but I've decided to implement my own physics for the platformer.

And to anyone who may be facing a similar issue as I was, I would suggest you do the same. In one of my other games, Piston Flip, I used the Spritekit physics because the game included some variation of the physics bodies and I never needed to exactly recreate the same physics interaction twice. So if you're making something that requires a little more complex physics and you don't require exact replication, go with spritekit physics.

Now if you need precision for something like a platformer, I suggest implementing it yourself. I used this tutorial as a starting point and customized from there. The irritating initial implementation aside, I am now really glad that I can control everything so accurately.

Why are sprites in contact with each other although they do not collide ?

So I had the exact same issue. I don't exactly know what the exact problem is but I fixed it by changing the hitbox of the sprites to circles instead of rectangles.
Try changing you declaration of the sprites Physic Bodies to this instead.

sprite.physicsBody = SKPhysicsBody(circleOfRadius: sprite.size)

sprite02.physicsBody = SKPhysicsBody(circleOfRadius: sprite.size)

laser.physicsBody = SKPhysicsBody(circleOfRadius: CGSize(width: laser.size.width * 2, height: laser.size.height*2))

I believe the issue lies in how the rectangular hitbox is placed around the sprite but if you change it to a circle it should work.



Related Topics



Leave a reply



Submit