SpriteKit & Swift: creating nodes through didBeginContact will interfere with positioning

I don’t know if this is a strange error in Xcode or something about the SpriteKit coordinate system I don’t understand.

The premise is that the position of a node is always relative to its parent. However, whenever I call a block that creates and positions a node with a physical body from SKPhysicsContactDelegate's “didBeginContact” body, the node is always positioned relative to the scene (instead of its parent). Note that calling the same block works as intended when it starts anywhere, but with "didBeginContact". Another thing is that if I remove the physical body of the mentioned node, the block will now work as intended, even when called from "didBeginContact".

I am stuck on this issue for two days and it will be too drag and drop to give other details about my actual code. Therefore, I made a very simple project demonstrating this anomaly. Just create a new project in Xcode 6 with the Spritekit template and replace GameViewController.swift and GameSwift.swift with the codes below. Just launch the iPad Air and everything else should be clear.

Concluding remarks:

  • When you press the first button and touch the second, look in the lower left corner of the screen. You will see that the boxes are "wrong" located there.
  • Try removing the physical body of the window in the "AddBox". Now he will work as intended.
  • Please let me know if you think this is a mistake or something in the coordinate system or in the physical world that I don’t understand.

GameViewController.swift:

import SpriteKit

class GameViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        let scene = GameScene()
        scene.size = view.frame.size
        let skView = self.view as SKView
        scene.scaleMode = .AspectFill
        skView.presentScene(scene)
    }
}

GameScene.swift:

import SpriteKit

let kButtonSize = CGSize(width: 500, height: 100)
let kContainerSize = CGSize(width: 500, height: 300)
let kBoxSize = CGSize(width: 25, height: 25)

class GameScene: SKScene, SKPhysicsContactDelegate {

    override func didMoveToView(view: SKView) {
        physicsWorld.contactDelegate = self
        addFirstButton()
        addSecondButton()
        addContainer()
    }

    func addFirstButton() {
        let button = SKSpriteNode(color: SKColor.blueColor(), size: kButtonSize)
        let label = SKLabelNode(text: "Call 'addBox' from didBeginContact")
        button.name = "firstButton"
        label.name = "firstLabel"
        button.position = CGPointMake(CGRectGetMidX(frame), CGRectGetMidY(frame))
        button.physicsBody = SKPhysicsBody(rectangleOfSize: button.size)
        button.physicsBody.allowsRotation = false
        button.physicsBody.affectedByGravity = false
        button.physicsBody.categoryBitMask = 0x1
        button.physicsBody.contactTestBitMask = 0x1
        button.addChild(label)
        addChild(button)
    }

    func addSecondButton() {
        let button = SKSpriteNode(color: SKColor.blueColor(), size: kButtonSize)
        let label = SKLabelNode(text: "Call 'addBox' from touchesBegan")
        button.name = "secondButton"
        label.name = "secondLabel"
        button.position = CGPointMake(CGRectGetMidX(frame), CGRectGetMidY(frame)-200)
        button.physicsBody = SKPhysicsBody(rectangleOfSize: button.size)
        button.physicsBody.dynamic = false
        button.physicsBody.categoryBitMask = 0x1
        button.physicsBody.contactTestBitMask = 0x1
        button.addChild(label)
        addChild(button)
    }

    func addContainer() {
        let container = SKSpriteNode(color: SKColor.greenColor(), size:kContainerSize)
        let label = SKLabelNode(text: "Created node should fall here")
        label.fontColor = SKColor.blackColor()
        container.name = "container"
        container.physicsBody = SKPhysicsBody(edgeLoopFromRect: container.frame)
        container.position = CGPointMake(CGRectGetMidX(frame), CGRectGetMidY(frame)+300)
        container.addChild(label)
        addChild(container)
    }

    func addBox() {
        let container = childNodeWithName("container")
        let box = SKSpriteNode(color: SKColor.blueColor(), size: kBoxSize)
        box.physicsBody = SKPhysicsBody(rectangleOfSize: box.size)
        box.position = CGPointMake(0, 100)
        container.addChild(box)
    }

    override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
        let touch = touches.anyObject() as UITouch
        let point = touch.locationInNode(self)
        let node = nodeAtPoint(point)
        if node.name == nil {return}

        switch node.name! {
        case "firstButton", "firstLabel":
            let button = childNodeWithName("firstButton") as SKSpriteNode
            button.physicsBody.applyImpulse(CGVectorMake(0, -500))
        case "secondButton", "secondLabel":
            addBox()
        default:
            break
        }
    }

    func didBeginContact(contact: SKPhysicsContact!) {
        addBox()
    }
}
+4
2

Apple Bug Report. , , . :

Apple24-Sep-2014 04:40

, :

, , .

+2

, ( , AndEngine). , , - bool, didSimulatePhysics didFinishUpdate - .

+1

All Articles