swiftsprite-kitskspritenodeskphysicsbodyskphysicscontact

collision not detected between SKSpitekit nodes


I am building a maze and I have added some SKSpritekit nodes for the walls and a dot for the player. however when the dot and the walls collide, there is no detection of collision. my code is as follows:

import UIKit
import SpriteKit
import GameplayKit
import Foundation
import GameplayKit


class level1: SKScene, SKPhysicsContactDelegate {
    var entities = [GKEntity]()
    var graphs = [String : GKGraph]()
    var dot = SKSpriteNode()

override func sceneDidLoad () {
    buildMaze()
    addDot()

    func addDot() {
    let startNum = x * (y - 1)
    startCoord = coordArray[startNum]
    dot = SKSpriteNode(imageNamed: "redDot")
    dot.physicsBody?.isDynamic = true
    dot.size = CGSize(width: 20, height: 20)
    dot.position = startCoord
    dot.physicsBody = SKPhysicsBody(circleOfRadius: 10)
    dot.physicsBody?.mass = 0
    dot.physicsBody?.usesPreciseCollisionDetection = true
    self.addChild(dot)
}

 func buildMaze() {
    let difference =  coordArray[1].x - coordArray[0].x 
    let wallDistance = difference/2
    let thickness = CGFloat(3)
    let length = difference  - CGFloat(thickness)/2



    var count = 0
    for point in coordArray {

        let northWall = SKSpriteNode(color: SKColor.black, size : CGSize (width: length, height: thickness))
        northWall.physicsBody = SKPhysicsBody(rectangleOf: CGSize(width: length, height: thickness))
        northWall.physicsBody?.mass = 200000

        let southWall = SKSpriteNode(color: SKColor.black, size : CGSize (width: length, height: thickness))
        southWall.physicsBody = SKPhysicsBody(rectangleOf: CGSize(width: length, height: thickness))
        southWall.physicsBody?.mass = 200000

        let eastWall = SKSpriteNode(color: SKColor.black, size : CGSize (width: thickness, height: length ))
        eastWall.physicsBody = SKPhysicsBody(rectangleOf: CGSize(width: thickness, height: length))
        eastWall.physicsBody?.mass = 200000

        let westWall = SKSpriteNode(color: SKColor.black, size : CGSize (width: thickness, height: length ))
        westWall.physicsBody = SKPhysicsBody(rectangleOf: CGSize(width: thickness, height: length))
        westWall.physicsBody?.mass = 200000


        if !instructions[count].contains("N")  {
            //print("added north wall")
            northWall.position = CGPoint (x: point.x , y: point.y + wallDistance)
            if nodes(at: northWall.position) == [] {

                addChild(northWall)}
            else {print("north wall already there")}

        }
        if !instructions[count].contains("S")  {
            //print("added south wall")
            southWall.position = CGPoint (x: point.x , y: point.y - wallDistance)
            if nodes(at: southWall.position) == [] {

                addChild(southWall)}
            else {//print("southwall already there")

            }

        }
        if !instructions[count].contains("E")  {
            //print("added east wall")
            eastWall.position = CGPoint (x: point.x + wallDistance , y: point.y)
            if nodes(at: eastWall.position) == [] {

                addChild(eastWall)}
            else {//print("east already there")

            }

        }
        if !instructions[count].contains("W")  {
            //print("added west wall")
            westWall.position = CGPoint (x: point.x - wallDistance , y: point.y)
            if nodes(at: westWall.position) == [] {

                addChild(westWall)}
            else {//print("west wall already there")

            }

        }
        count = count + 1

    }
}


    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
        for t in touches {
            let location = t.location(in: self)
            dot.position.x = location.x
            dot.position.y = location.y
        }
    }

func didBegin(_ contact: SKPhysicsContact) {
    print("contact!")


}

The walls appear just as I wanted them, and the dot is also in the right position.

I added a masso of 20000 for each of them so that when I move the dot, the walls stay in place. however, when I move the dot with my finger, it just goest straight through the walls of the maze instead of being stopped by them.

I added a print statement to the didBegin function to see if at least it was detecting any contact between the sprites, but it does not.

Why is this?

cheers!


Solution

  • First in your didMoveTo or sceneDidLoad, you need to set the physicsContactDelegate:

    override func sceneDidLoad () {
        physicsWorld.contactDelegate = self
        buildMaze()
        addDot()
    }
    

    To set the contact/collision mask, you have to do it this way, because they're based on bitwise operation:

    Let's suppose you want collision between dot and walls

    struct PhysicsCategory {
        static let wall: UInt32 = 0x1 << 1
        static let dot: UInt32 = 0x1 << 2
    }
    

    You can put the struct above you class if you want

    Then, when you assign physics body, you have to set the bitmask:

    For dots:

        dot.physicsBody?.categoryBitMask = PhysicsCategory.dot
        dot.physicsBody?.contactTestBitMask = PhysicsCategory.wall
        dot.physicsBody?.collisionBitMask = PhysicsCategory.wall 
    
        //Collision is different from contact, so if you want to avoid collision
        //dot.physicsBody?.collisionBitMask = PhysicsCategory.dot 
    

    Collision is different from contact, check apple documentation about it

    For walls:

        northWall.physicsBody?.categoryBitMask = PhysicsCategory.wall
        northWall.physicsBody?.contactTestBitMask = PhysicsCategory.dot
        northWall.physicsBody?.collisionBitMask = PhysicsCategory.dot
    
        //Do the same for all walls
    

    If you want walls to contact or collide with more than one object:

        northWall.physicsBody?.contactTestBitMask = PhysicsCategory.dot | PhysicsCategory.other
        northWall.physicsBody?.collisionBitMask = PhysicsCategory.dot | PhysicsCategory.other
    

    For walls are valid all consideration as per dots