2015-02-13 5 views
1

Следующий код дает ошибку - кажется, что в массиве суставов физики есть класс PKPhysicsJoint. У кого-нибудь есть идеи, как я могу проходить через суставы в Свифте?node.physicsBody.joints ошибка понижающего преобразования

documentation действительно говорит, что физикаBody.joints должна возвращать массив SKPhysicsJoint.

import SpriteKit 

let scene = SKScene(size: CGSize(width: 200, height: 200)) 
let nodeA = SKNode() 
let nodeB = SKNode() 

nodeA.physicsBody = SKPhysicsBody(circleOfRadius: 20) 
nodeB.physicsBody = SKPhysicsBody(circleOfRadius: 20) 

scene.addChild(nodeA) 
scene.addChild(nodeB) 

let joint = SKPhysicsJointFixed.jointWithBodyA(nodeA.physicsBody, bodyB: nodeB.physicsBody, anchor: CGPointZero) 
scene.physicsWorld.addJoint(joint) 

for joint in nodeA.physicsBody!.joints as [SKPhysicsJoint] { 
    // do something else here 
} 

дает ошибку:

Execution was interrupted. reason: EXC_BAD_INSTRUCTION... 
+0

Попробуйте следующее: 'для соединения в узлеA.physicsBody! .joints { ..} ' – LearnCocos2D

ответ

3

Update: Этот был ошибки, и это зафиксировано в прошивке 9/OS X 10.11 - код в вопросе только работает сейчас.

Оставляя оригинальный текст ответа для потомству/людей с использованием старых SDKs/и т.д.


Это выглядит как ошибка - you should file it. Следует ли считать ошибкой SpriteKit или ошибкой Swift трудно сказать, но это проблема Apple, а не ваша. :)

Проблема понятна, если вы вставляете код в игровое поле - ваш joint на самом деле является PKPhysicsJointWeld за кулисами. Это некоторый внутренний класс, который должен быть деталью реализации. В ObjC это не проблема, потому что кастинг на C - это просто вопрос компилятора: «Поверьте мне, этот указатель действительно SKPhysicsJoint, поэтому позвольте мне назвать физику совместными методами (и ничего больше) на нем, и никто не будет мудрее ". Кастинг в Swift требует наличия отношения иерархии типов между литыми типами - и PKPhysicsJointWeld не является подтипом/подклассом SKPhysicsJoint, поэтому сбой выполняется.

Вы можете обойти эту проблему, избегая бросание на [SKPhysicsJoint]:

for joint in nodeA.physicsBody!.joints { 
    // do something else here 
} 

При этом, вы теряете некоторую типовую безопасность - joint является AnyObject, так как id типа ObjC в компилятор позволяет вызывать любой метод в теме. (И он может не работать во время выполнения, если этот объект не реализует метод.) Но по крайней мере он работает.

Дальнейшее обходное решение: внутри петли вы можете отливать joint в SKPhysicsJoint. Но так как приведение по иерархии типов, вы должны использовать unsafeBitCast:

for joint in nodeA.physicsBody!.joints { 
    let skJoint = unsafeBitCast(joint, SKPhysicsJoint.self) 
    // do stuff with skJoint 
} 

Это заставляет вас немного назад типа компиляции «безопасности», в том, что после этого компилятор будет требовать, что вы делаете с skJoint, чтобы быть совместимым с SKPhysicsJoint, но он по-прежнему по своей сути является небезопасным в том смысле, что это зависит от того, как вручную размахивать вокруг типов времени выполнения, которые могут не всегда выполняться. И вам нужно снова unsafeBitCast, чтобы добраться до конкретного совместного подкласса, не зная, какой из подклассов он может быть. (. Опять же, this would be a good time to file a bug)


(Вы можете заметить из оклейки в игровую площадку, что physicsWorld имеет внутренний класс, тоже:. PKPhysicsWorld Так почему же это не удастся, слишком При использовании physicsWorld недвижимости? , все литье типов происходит на стороне ObjC, а Swift доверяет тому, что ObjC сообщает об этом.Однако, когда вы имеете дело с массивом joints, вам нужно сделать тип на стороне Swift, а Swift гораздо более строг в отношении проверки типов.)

Смежные вопросы