4

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.

Ron Myschuk
  • 6,011
  • 2
  • 20
  • 32
Devang
  • 11,258
  • 13
  • 62
  • 100

2 Answers2

2

You are using 2 edge based bodies. Edge based bodies will always be isDynamic = false no matter if you set it or not. You need at least 1 volume based body to be able to perform a contact.

Plus on top of that you are constantly removing and adding a node, which is a terrible idea.

I would recommend adding your node on the touchesBegan only, then update only the path on touchesMoved

Knight0fDragon
  • 16,609
  • 2
  • 23
  • 44
1

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

Ron Myschuk
  • 6,011
  • 2
  • 20
  • 32