A better solution to drag a SKPhysicsBody around in Spritekit

Introduction

When asking to drag a SKPhysicsBody around in Spritekit, we may come up with an idea immediately that just set the touch position as the position of the node. However, this simple method has a couple of problems actually.[1]

Problems

  • While we are dragging the dynmaic body directly, gravity is still generating effect on it and is going to be dragging the body down. This will have the effect of making the body's position flicker noticeably as it's move around.

  • If you set the body's position directly, it is a possibility that this body will move through wall or through other objects,which may not be what you want.

Better Solution

There is a better solution to drag a SKPhysicsBody around in Spritekit; that is adding a pin joint at the point player touched and jointing with the body; then moving the joint around.
Here is example:

override func touchesBegan(touches: Set,
    withEvent event: UIEvent) {

    // We only care about one touch at a time
    if let touch = touches.first as? UITouch {
    // Work out what node got touched
        let touchPosition = touch.locationInNode(self)
        let touchedNode = self.nodeAtPoint(touchPosition)

        // Make sure that we're touching something that _can_ be dragged
        if touchedNode == dragNode || touchedNode.physicsBody == nil {
            return
        }

        // Create the invisible drag node, with a small static body
        let newDragNode = SKNode()
        newDragNode.position = touchPosition
        newDragNode.physicsBody =
            SKPhysicsBody(rectangleOfSize:CGSize(width: 10,
                                                 height: 10))
        newDragNode.physicsBody?.dynamic = false

        self.addChild(newDragNode)

        // Link this new node to the object that got touched
        let newDragJoint = SKPhysicsJointPin.jointWithBodyA(
            touchedNode.physicsBody,
            bodyB:newDragNode.physicsBody,
            anchor:touchPosition)

        self.physicsWorld.addJoint(newDragJoint)

        // Store the reference to the joint and the node
        self.dragNode = newDragNode
        self.dragJoint = newDragJoint

    }
}

override func touchesMoved(touches: Set,
    withEvent event: UIEvent) {

    if let touch = touches.first as? UITouch {
        // When the touch moves, move the static drag node.
        // The joint will drag node.
        // The joint will drag the connected
        // object with it.
        let touchPosition = touch.locationInNode(self)

        dragNode?.position = touchPosition
    }
}

override func touchesEnded(touches: Set,
    withEvent event: UIEvent) {

    stopDragging()
}

override func touchesCancelled(touches: Set,
    withEvent event: UIEvent) {

    stopDragging()
}

func stopDragging() {
    // Remove the joint and the drag node.
    self.physicsWorld.removeJoint(dragJoint!)
    dragJoint = nil

    dragNode?.removeFromParent()
    dragNode = nil
}

  1. this article is an summary of a chapter of iOS Swift Game Development Cookbook ↩

你可能感兴趣的:(A better solution to drag a SKPhysicsBody around in Spritekit)