我有一个在Swift 3中编码的iOS应用程序,其中一个球被射击并在屏幕上弹出砖块。如果我将砖块作为一个PhysicsBody(一个矩形),我就不能轻易确定砖块的哪个侧面/角落被击中。我决定做的不是这个,而是让砖块的每一面都是它自己独立的节点。我现在面临的问题是球不能同时与两个节点(比如左边和底部)接触。我每次接触球后都会降低砖的值,这反过来又会使这一击中的值减少2。我怎样才能做到这样,如果一个球击中两个节点,只执行一个联系人的代码?
有时下面的代码会执行两次,两次都会与两个brickNodes接触。
func didBegin(_ contact: SKPhysicsContact) {
var firstBody:SKPhysicsBody
var secondBody:SKPhysicsBody
let countPoint = true
if contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask {
firstBody = contact.bodyA
secondBody = contact.bodyB
} else {
firstBody = contact.bodyB
secondBody = contact.bodyA
}
if (firstBody.categoryBitMask & ballCategory) != 0 {
if (firstBody.node != nil && secondBody.node != nil){
if (secondBody.categoryBitMask & brickCategory) != 0 {
ballDidHitBrick(ballNode: firstBody.node as! SKShapeNode, brickNode: secondBody.node as! SKShapeNode, decreasePoint: countPoint)
} else if (secondBody.categoryBitMask & roofCategory) != 0 || (secondBody.categoryBitMask & rightWallCategory) != 0 || (secondBody.categoryBitMask & leftWallCategory) != 0 || (secondBody.categoryBitMask & bottomCategory) != 0 {
ballDidHitWall(ballNode: firstBody.node as! SKShapeNode, wallNode: secondBody.node as! SKShapeNode)
} else {
//Nothing as of yet
}
}
}
}
答案 0 :(得分:1)
顺便说一下史蒂夫上面所说的,我实现了下面的代码,我不再每次更新都有双联系人:
if !bricksHit.contains("\(secondBody.node?.name ?? ""), \(firstBody.node?.name ?? "")") {
//If ball hasnt hit the object more than once
bricksHit.append("\(secondBody.node?.name ?? ""), \(firstBody.node?.name ?? "")")
ballDidHitBrick(ballNode: firstBody.node as! SKShapeNode, brickNode: secondBody.node as! SKShapeNode, decreasePoint: countPoint, contact: contact)
}
我还在下面添加了我的代码,它会在每次更新后清除bircksHit:
override func didFinishUpdate() {
bricksHit.removeAll()
}
答案 1 :(得分:0)
我会废弃多个体的多个节点,如果你有很多块,那将会产生糟糕的性能。
相反,您应该分步处理您的工作。
在didBegin
阶段,您需要跟踪联系点的位置。这可以使用userData
func didBegin(_ contact: SKPhysicsContact) {
var firstBody:SKPhysicsBody
var secondBody:SKPhysicsBody
let countPoint = true
if contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask {
firstBody = contact.bodyA
secondBody = contact.bodyB
} else {
firstBody = contact.bodyB
secondBody = contact.bodyA
}
if (firstBody.categoryBitMask & ballCategory) != 0, (secondBody.categoryBitMask & brickCategory) != 0 {
let userData = firstBody.node!.userData ?? [String,AnyObject]()
let contactPoints = userData["contactPoints"] as? [CGPoint] ?? [CGPoint]()
contactPoints.append(contact.contactPoint) //if need be add other info like the vector or relative to the node
userData["contactPoints"] = contactPoints
}
}
然后在稍后的过程中,像didSimulatePhysics
您可以评估联系的节点,确定接触的优先级(如底部将取代侧面,或者如果速度x>速度y,侧面,无论你需要做什么)并以这种方式作出反应。
请注意,这只是示例代码,不会逐字逐句。您需要将其构建到代码中才能使其正常工作。
答案 2 :(得分:-1)
didBegin
,从而导致同一对物理对的多次调用(在sam游戏循环中)体。
处理它的方法(你不能让sprite-kit在某些情况下多次调用didBegin)是为了确保你的联系代码适应这一点,多次处理合同不会导致问题(例如多次添加分数,删除多个生命,尝试访问已被删除的节点或物理等。)
您可以做的一些事情包括:
将节点添加到集合中,然后删除didFinishUpdate
将“非活动”标志添加到节点的userData
使节点成为SKSpriteNode的子类并添加“非活动”属性(或类似)
Etc等。
对于单个联系人,请多次查看有关SK致电didBegin
的问题和答案:
Sprite-Kit registering multiple collisions for single contact
此外,SKPhysicsContact不仅包含已碰撞的2个物理实体的细节,还包含接触点。由此,以及所涉及的2个节点的位置属性,您确实可以计算出砖块的哪个边/角被击中。