Beginner Swift Sprite Kit - Node Collision Detection Help (Skphysicscontact)

beginner swift sprite kit - node collision detection help (SKPhysicsContact)

First you should set your firstBody & secondBody to the order of their collisionBitMask:

if contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask 
{
firstBody = contact.bodyA
secondBody = contact.bodyB
}
else {
firstBody = contact.bodyB
secondBody = contact.bodyA
}

if firstBody.categoryBitMask=0 && secondBody.categoryBitMask=1 {
secondBody.removeFromParent()
}

This will prevent your sprites from colliding with anything (including each other). Set this where you set the other BitMask properties:

alpha.physicsBody.collisionBitMask = 0
beta.physicsBody.collisionBitMask = 0

How to Detect collision in Swift, Sprite kit

  1. Define unique categories, ensure your class is a SKPhysicsContactDelegate and make yourself the physics contact delegate:

//Physics categories

let enemyCategory:    UInt32 = 1 << 1
let bulletCategory: UInt32 = 1 << 2

class GameScene: SKScene, SKPhysicsContactDelegate {
physicsWorld.contactDelegate = self

  1. Assign the categories (usually in didMove(to view:) :

    enemy.physicsBody.catgeoryBitMask = enemyCategory
    bullet.physicsBody.catgeoryBitMask = bulletCategory

(Make sure you've created physics bodies for each node)


  1. Set up collisions:

enemy.physicsBody?.collisionBitMask = 0 // enemy collides with nothing
bullet.physicsBody?.collisionBitMask = 0 // bullet collides with nothing

or even:

for node in [enemy, bullet] {
node.physicsBody?.collisionBitMask = 0 // collides with nothing
}

  1. Set up contacts

    bullet.physicsBody?.collisionBitMask = enemyCategory // bullet contacts enemy

Make sure that at least one of the objects involved in each potential contact has the isDynamic property on its physics body set to true, or no contact will be generated. It is not necessary for both of the objects to be dynamic.

You should now get didBegin called when the bullet and the enemy make contact. You could code didBegin like this:

  func didBegin(_ contact: SKPhysicsContact) {
print("didBeginContact entered for \(String(describing: contact.bodyA.node!.name)) and \(String(describing: contact.bodyB.node!.name))")

let contactMask = contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask

switch contactMask {
case bulletCategory | enemyCategory:
print("bullet and enemy have contacted.")
let bulletNode = contact.bodyA.categoryBitMask == bulletCategory ? contact.bodyA.node : contact.bodyB.node
enemyHealth -= 10
bulletNode.removeFromParent
default:
print("Some other contact occurred")
}

}

How to detect when two objects touch in SpriteKit

Not to be a stickler but you shouldn't start of a question with "I couldn't find anything on the internet" when thats blatantly not true. There is a million tutorials on collision detection around as its one of the basics in SpriteKit.

Now to your question. You did not give your sprites an actual physics body and your physics categories are set up weird. Change your code to this

 struct PhysicsCategory {
static let cat:UInt32 = 0x1 << 0
static let ground:UInt32 = 0x1 << 1
}

class GameScene: SKScene, SKPhysicsContactDelegate {


override func didMoveToView(view: SKView) {
/* Setup your scene here */

physicsWorld.contactDelegate = self


cat.physicsBody = SKPhysicsBody(rectangleOfSize: cat.size) // FORGOT THIS
cat.physicsBody?.categoryBitMask = PhysicsCategory.cat
cat.physicsBody?.contactTestBitMask = PhysicsCategory.ground

ground.physicsBody = SKPhysicsBody(rectangleOfSize: ground.size) // FORGOT THIS
ground.physicsBody?.categoryBitMask = PhysicsCategory.ground
ground.physicsBody?.contactTestBitMask = PhysicsCategory.cat // You dont really need this line as long as you have set it on the other body.
}

func didBeginContact(contact: SKPhysicsContact) {
var firstBody: SKPhysicsBody
var secondBody: SKPhysicsBody

if contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask {
firstBody = contact.bodyA
secondBody = contact.bodyB
} else {
firstBody = contact.bodyB
secondBody = contact.bodyA
}

if firstBody.categoryBitMask == PhysicsCategory.cat && secondBody.categoryBitMask == PhysicsCategory.ground {
print("contact")
}
}
}

If you dont want your objects to fall you have to turn gravity off, which is on by default.

 cat.physicsBody?.affectedByGravity = false
ground.physicsBody?.affectedByGravity = false

Hope this helps

Avoiding collision in spriteKit on iOS while maintaining contact

You might have a different problem in your code elsewhere, because this is working for me. The bodies do not collide and the contact happens.

Sample playground code:

import PlaygroundSupport
import SpriteKit

class GameScene: SKScene, SKPhysicsContactDelegate {

var stoneNode: SKShapeNode!
var birdNode: SKShapeNode!

override func didMove(to view: SKView) {

let stoneCategory : UInt32 = 0x1 << 1
let birdCategory : UInt32 = 0x1 << 2

physicsWorld.contactDelegate = self

stoneNode = SKShapeNode(circleOfRadius: 30)
stoneNode.name = "stone"
stoneNode.position = CGPoint(x: 0, y: 100)
addChild(stoneNode)
stoneNode.physicsBody = SKPhysicsBody(circleOfRadius: 30)
stoneNode.physicsBody?.categoryBitMask = stoneCategory
stoneNode.physicsBody?.contactTestBitMask = birdCategory
stoneNode.physicsBody?.collisionBitMask = 0

birdNode = SKShapeNode(circleOfRadius: 40)
birdNode.name = "bird"
birdNode.position = CGPoint(x: 0, y: -100)
addChild(birdNode)
birdNode.physicsBody = SKPhysicsBody(circleOfRadius: 40);
birdNode.physicsBody?.categoryBitMask = birdCategory
birdNode.physicsBody?.contactTestBitMask = stoneCategory
birdNode.physicsBody?.collisionBitMask = 0
birdNode.physicsBody?.isDynamic = false;
}

func didBegin(_ contact: SKPhysicsContact) {
print("Contact between "+contact.bodyA.node!.name!+" and "+contact.bodyB.node!.name!); // --> Never called
}
}

// Load the SKScene from 'GameScene.sks'
let sceneView = SKView(frame: CGRect(x:0 , y:0, width: 640, height: 480))
if let scene = GameScene(fileNamed: "GameScene") {
// Set the scale mode to scale to fit the window
scene.scaleMode = .aspectFill

// Present the scene
sceneView.presentScene(scene)
}

PlaygroundSupport.PlaygroundPage.current.liveView = sceneView

And in the console, when the first body drops, being affected by gravity, it's printed:

Contact between stone and bird

Swift/SpriteKit - Collisions and Objects

The SKPhyicsBody class has a node property which points to the SKNode instance it is attached to.

Your collision detection code can look something like this:

func didBeginContact(contact: SKPhysicsContact) {

var item: SKSpriteNode
var character: SKSpriteNode

//Change this on the basis of the order of your categoryBitMask values
if (contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask)
{
item = contact.bodyA.node as SKSpriteNode
character = contact.bodyB.node as SKSpriteNode
}
else
{
item = contact.bodyB.node as SKSpriteNode
character = contact.bodyA.node as SKSpriteNode
}

//Perform necessary operations on item and character
}

EDIT:
In order to get access to the Item instance that declares the node, you will have to store a variable within the node which points to the Item instance. For this, you can either subclass SKSpriteNode and include a property, or use the userData
property of SKNode

Subclassing:

//New Class
class ItemNode: SKSpriteNode {

static var itemInstance
}

//In the Item class declare the itemNode using this class
let itemNode = ItemNode()
itemNode.itemInstance = self

UserData property:

item.userData = NSMutableDictionary(object: self, forKey: "ItemInstance"))


Related Topics



Leave a reply



Submit