我想在SpriteKit中检测两种不同类型的碰撞:
当ballOne击中goalOne并且当ballTwo击中goalTwo时:
到目前为止,我已添加了不同的物理类别:
struct physicsCategory {
static let ballOne :UInt32 = 0x1 << 0
static let goalOne :UInt32 = 0x1 << 1
static let ballTwo :UInt32 = 0x1 << 2
static let goalTwo :UInt32 = 0x1 << 3
}
以下是我班级的相关部分:
class gameScene: SKScene, SKPhysicsContactDelegate {
var borderBody:SKPhysicsBody!
var myscore:Int = 0
var opponentScore:Int = 10
override func sceneDidLoad() {
super.sceneDidLoad()
physicsWorld.contactDelegate = self
}
func didBegin(_ contact: SKPhysicsContact) {
let firstBody = contact.bodyA.node as! SKSpriteNode
let secondBody = contact.bodyB.node as! SKSpriteNode
if ((firstBody.name == "ballOne") && (secondBody.name == "goalOne")) {
collisionGoalOne(BallOne: firstBody, GoalOne: secondBody)
}
else {
}
}
func collisionGoalOne(BallOne: SKSpriteNode, GoalOne: SKSpriteNode) {
addScore()
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch = touches.first
let touchLocation = touch!.location(in: self)
let ballOne = childNode(withName: "ballOne") as! SKSpriteNode
ballOne.physicsBody?.categoryBitMask = physicsCategory.ballOne
ballOne.physicsBody?.collisionBitMask = physicsCategory.goalOne
ballOne.physicsBody?.contactTestBitMask = physicsCategory.goalOne
ballOne.physicsBody?.isDynamic = true
let goalOne = childNode(withName: "goalOne") as! SKSpriteNode
goalOne.physicsBody?.categoryBitMask = physicsCategory.goalOne
goalOne.physicsBody?.collisionBitMask = physicsCategory.ballOne
goalOne.physicsBody?.contactTestBitMask = physicsCategory.ballOne
goalOne.physicsBody?.isDynamic = false
}
}
现在,当球与墙壁碰撞时,应用程序崩溃
let firstBody = contact.bodyA.node as! SKSpriteNode
“无法将类型'appName.gameScene'(0x105320)的值转换为'SKSpriteNode'(0x1877b5c)。”
很想明白为什么会发生这种崩溃,以及这是否是一种很好的碰撞处理方法。谢谢。
答案 0 :(得分:1)
FirstBody可能无法转换为SKSpriteNode,因此只有在检查了哪些节点发生碰撞后才创建该变量。
请注意,ballOne可以是bodyA或bodyB,因此请更改代码以检查两种可能性。
我改变了你的代码。希望这有帮助
if ((contact.bodyA.node?.name == "ballOne") && (contact.bodyB.node?.name == "goalOne")) {
let firstBody = contact.bodyA.node as! SKSpriteNode
let secondBody = contact.bodyB.node as! SKSpriteNode
collisionGoalOne(BallOne: firstBody, GoalOne: secondBody)
} else if ((contact.bodyA.node?.name == "goalOne") && (contact.bodyB.node?.name == "ballOne")) {
let firstBody = contact.bodyA.node as! SKSpriteNode
let secondBody = contact.bodyB.node as! SKSpriteNode
collisionGoalOne(BallOne: secondBody, GoalOne: firstBody)
}
答案 1 :(得分:1)
我认为您可能想要进行一些更改。
当您的球节点与墙壁接触时,我相信您的didBegin(_ contact: SKPhysicsContact)
方法会被调用,其中一个物体作为球(SKNode
)而另一个物体作为场景边界(SKScene
) 。
强迫SKScene投射到SKSpriteNode,let firstBody = contact.bodyA.node as! SKSpriteNode
崩溃,RT5754指出。
要解决此问题,您可以考虑以下事项:
为墙/边框添加物理类别。类似的东西:
static let sceneBorder :UInt32 = 0x1 << 4
更新边框和球节点以进行碰撞物理:
ballNode.physicsBody?.collisionBitMask = physicsCategory.sceneBorder
borderNode.physicsBody?.collisionBitMask = physicsCategory.ballOne + physicsCategory.ballTwo
处理其他联系逻辑时,我的模式为
didBegin(_ contact: SKPhysicsContact)
是这样的:
func didBegin(_ contact: SKPhysicsContact) {
var firstBody: SKPhysicsBody = contact.bodyA
var secondBody: SKPhysicsBody = contact.bodyB
//in did begin contact, order the bodies by physics category
if firstBody.categoryBitMask > secondBody.categoryBitMask {
let temp = secondBody
secondBody = firstBody
firstBody = temp
}
//logic to handle contact is based on physicsCategory
if secondBody.categoryBitMask == physicsCategory.whatever {
methodToHandleWhatever(thingOne: firstBody, thingTwo: secondBody)
}