SpriteKit& Swift:通过didBeginContact创建节点会弄乱定位

时间:2014-09-19 13:51:19

标签: ios objective-c swift sprite-kit xcode6

我不知道这是否是Xcode中的一个奇怪的错误,或者有些关于SpriteKit的坐标系我不明白。

前提是节点的位置始终相对于其父节点。但是,每当我调用一个块来创建和定位一个带有来自SKPhysicsContactDelegate的“didBeginContact”的物理体的节点时,该节点总是相对于场景(而不是它的父节点)定位。请注意,除了“didBeginContact”之外,在触发任何地方时调用此相同的块都可以正常工作。另一件事是,如果我删除所述节点的物理主体,即使从“didBeginContact”调用,该块现在也可以正常工作。

我已经坚持这个问题两天了,如果提供有关我实际代码的其他详细信息,那就太过于拖延了。所以我做了一个非常简单的项目来证明这种异常现象。只需使用Spritekit模板在Xcode 6中创建一个新项目,并将GameViewController.swift和GameSwift.swift替换为下面发布的代码。只需在iPad Air中运行,其他一切都应该是自我解释的。

最后的笔记:

  1. 当您按下第一个按钮并与第二个按钮联系时 按钮,查看屏幕的左下角。你会看见 盒子被“错误地”定位在那里。
  2. 尝试删除“AddBox”中框的物理主体。现在它将按预期工作。
  3. 如果您认为这是一个错误,或者在我不理解的坐标系或物理世界中有什么东西,请告诉我。
  4. 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()
        }
    }
    

2 个答案:

答案 0 :(得分:2)

我已经向Apple Bug Report报告了这个问题。我希望这可以帮助任何遇到同样问题的人。以下是他们的回复:

  

Apple Developer Relations 24-Sep-2014 04:40 AM

     

工程已确定这是您需要解决的问题   基于以下内容:

     

您无法修改正在模拟的树,这是   在编程指南中明确说明。

答案 1 :(得分:1)

您似乎无法在联系人委托中创建物理主体(这类似于其他引擎,例如AndEngine)。不要将新身体直接写入代表,在那里标记一些bool标志并在didSimulatePhysics或didFinishUpdate中进行创建 - 对我有效。