iosswiftsprite-kitskphysicsbodyskphysicscontact

Spritkit : Detect collision while drawing line using finger


I am trying to detect collision contactPoint between existing line and line which user currently drawing using finger.

Here is my code :

let padding: CGFloat = 100
override func didMove(to view: SKView) {

    physicsWorld.contactDelegate = self

    let startPoint1 = CGPoint(x: self.frame.minX + padding , y: self.frame.minY + padding)
    let leftHorizontalPoint = CGPoint(x: self.frame.minX + padding, y: self.frame.maxY - padding)

    let line1 = SKShapeNode()
    let line_path:CGMutablePath = CGMutablePath()
    line_path.move(to: startPoint1)
    line_path.addLine(to: leftHorizontalPoint)
    line1.path = line_path
    line1.lineWidth = 3
    line1.strokeColor = UIColor.white
    addChild(line1)

    line1.physicsBody = SKPhysicsBody(edgeLoopFrom: line1.frame)
    line1.physicsBody?.isDynamic = true
    line1.physicsBody?.categoryBitMask = PhysicsCategory.solidLine
    line1.physicsBody?.collisionBitMask = PhysicsCategory.currentLine
    line1.physicsBody?.contactTestBitMask = PhysicsCategory.currentLine
}

Then on touchBegin, touchMove & touchEnd I am having following code :

var currentLineNode: SKShapeNode!
var startPoint: CGPoint = CGPoint.zero
func touchDown(atPoint pos : CGPoint) {
    startPoint = pos
}

func touchMoved(toPoint pos : CGPoint) {
    if currentLineNode != nil {
        currentLineNode.removeFromParent()
    }
    currentLineNode = SKShapeNode()
    currentLineNode.zPosition = 1
    let line_path:CGMutablePath = CGMutablePath()
    line_path.move(to: startPoint)
    line_path.addLine(to: pos)
    currentLineNode.path = line_path
    currentLineNode.lineWidth = 3
    currentLineNode.strokeColor = UIColor.red
    addChild(currentLineNode)

    currentLineNode.physicsBody = SKPhysicsBody(edgeLoopFrom: currentLineNode.frame)
    currentLineNode.physicsBody?.isDynamic = true
    currentLineNode.physicsBody?.categoryBitMask = PhysicsCategory.currentLine
    currentLineNode.physicsBody?.collisionBitMask = PhysicsCategory.solidLine
    currentLineNode.physicsBody?.contactTestBitMask = PhysicsCategory.solidLine
}

func touchUp(atPoint pos : CGPoint) {
    if currentLineNode != nil {
        currentLineNode.removeFromParent()
    }
    currentLineNode = SKShapeNode()
    let line_path:CGMutablePath = CGMutablePath()
    line_path.move(to: startPoint)
    line_path.addLine(to: pos)
    currentLineNode.path = line_path
    currentLineNode.lineWidth = 3
    currentLineNode.strokeColor = UIColor.red
    addChild(currentLineNode)

    currentLineNode.physicsBody = SKPhysicsBody(edgeLoopFrom: currentLineNode.frame)
    currentLineNode.physicsBody?.isDynamic = true
    currentLineNode.physicsBody?.categoryBitMask = PhysicsCategory.currentLine
    currentLineNode.physicsBody?.collisionBitMask = PhysicsCategory.solidLine
    currentLineNode.physicsBody?.contactTestBitMask = PhysicsCategory.solidLine
}

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {

    for t in touches { self.touchDown(atPoint: t.location(in: self)) }
}

override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
    for t in touches { self.touchMoved(toPoint: t.location(in: self)) }
}

override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
    for t in touches { self.touchUp(atPoint: t.location(in: self)) }
}

override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
    for t in touches { self.touchUp(atPoint: t.location(in: self)) }
}

physicsWorld's contactDelegate as follow : (Delegate not even executed)

extension GameScene : SKPhysicsContactDelegate {
    func didBegin(_ contact: SKPhysicsContact) {
       // This never get detected :(
       print(contact.contactPoint)
       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
       }
    }
}

Here is my output where even though passing from white colored line its not detecting collision.

enter image description here

What could be wrong? Any suggestion on this will be helpful.


Solution

  • you are creating your physics body with an edge loop. Apple defines edge loops as...

    An edge has no volume or mass and is always treated as if the isDynamic property is equal to false. Edges may only collide with volume-based physics bodies.

    changing your physics body to this works

    currentLineNode.physicsBody = SKPhysicsBody(rectangleOf: currentLineNode.frame.size, center: CGPoint(x: startPoint.x + currentLineNode.frame.size.width / 2, y: startPoint.y + currentLineNode.frame.size.height / 2)) 
    

    also should be noted that changing your physics body in touchesEnded is redundant and adds nothing. I removed it from touchesEnded and it works fine