我有一个在Swift 3中编码的iOS应用程序,在该应用程序中,球被射击并从屏幕上弹起。如果我的砖是一个物理机构(矩形),我将无法轻易确定砖的哪一侧/角都被击中。我决定做的不是这样做的是将砖的每一侧都是其自己的单独节点。我现在遇到的问题是,一个球不能一次与两个节点(例如左和底部)接触。与球的每次接触后,我正在降低砖的值,而这一命中又将值降低了2。我该怎么做,以便如果一个球命中两个节点,则只能执行一个联系人?
有时以下代码被执行两次,球两次都与两个砖块接触。
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
}
}
}
}
因此,与史蒂夫(Steve)所说的那样,我实现了下面的代码,并且每个更新都不再具有双重联系人:
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()
}
我会用多个身体刮下多个节点,如果您有很多块,这将产生可怕的性能。
相反,您应该按步骤处理工作。
在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个物理体之间有多个同时的联系点,SK将为每个接触点致电didBegin
,从而导致相同物理体的多个呼叫(在SAM游戏循环中)。p>处理它的方法(在某些情况下,您无法多次拨打sprite-kit,请勿多次致电didbegin)是为了确保您的联系代码适应此情况,并且多次处理合同不会引起问题(例如多次增加分数,删除多个生命,试图访问已删除的节点或物理机构等)。
您可以做的一些事情包括:
- 如果您删除了与已联系的节点,请检查它是零之前的您将其删除(用于重复的联系人)
-
将节点添加到集合中,然后删除
didFinishUpdate
中的集合中的所有节点 向节点的UserData
添加一个"非活动"标志'使节点成为SKSpriteNode的子类,并添加"非活动"属性(或类似)
等等。
请参阅此问题,并回答有关SK多次致电didBegin
以获取单个联系人:
Sprite-Kit注册了单个联系人的多个碰撞
SkphysicsContact不仅包含碰撞的两个物理体的细节,还包含接触点。由此,以及涉及的两个节点的位置属性,您确实可以计算砖的哪一侧/角。