SpriteKit&Swift:通过doBeginContact创build节点会弄乱定位

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

前提是节点的位置总是相对于其父节点。 然而,无论何时我调用一个块来创build和定位一个物理主体的节点,该主体从SKPhysicsContactDelegate的“didBeginContact”开始,节点总是相对于场景(而不是它的父节点)定位。 请注意,调用此相同的块在任何地方触发,但“didBeginContact”时按预期工作。 另一件事是,如果我删除了所述节点的物理体,那么即使从“didBeginContact”调用该块,该块现在也能按预期工作。

我一直坚持这个问题两天,这将是太draggy给我的实际代码的其他细节。 所以我做了一个非常简单的项目来certificate这个exception。 只需在Xcode 6中用Spritekit Template创build一个新项目,并用下面的代码replaceGameViewController.swift和GameSwift.swift。 只需在iPad Air中运行,其他一切都应该是自我解释。

最后说明:

  1. 当您按下第一个button并与第二个button进行联系时,请查看屏幕的左下angular。 你会看到这些盒子被“错误地”定位在那里。
  2. 尝试删除“AddBox”框中的物理主体。 它现在将按预期工作。
  3. 请让我知道,如果你认为这是一个错误,或者在坐标系统或物理世界有东西,我不明白

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() } } 

我已经提交了关于Apple Bug报告这个问题的一张票。 我希望这可以帮助遇到同样问题的任何人。 这是他们的回应:

苹果开发者关系24-Sep-2014 04:40 AM

工程部门根据以下内容确定了您需要解决的问题:

您不能修改正在模拟的树,这在编程指南中已经清楚说明。

看起来你不能在联系人委托中创build物理实体(这与其他引擎相似,例如AndEngine)。 不要将新身体直接放入代表,在那里标记一些布尔标志,并在didSimulatePhysics或didFinishUpdate中进行创build – 适用于我。