Swift / SpriteKit多碰撞检测?

你好。

我有多个碰撞问题。有一颗子弹击中了敌人(红色矩形)。然后,它+分数。有一个螺旋线(红色圆圈)

被推测为当敌人(红色矩形)触摸场景时触发场景结束。

在这种情况下,当敌人击中螺旋桨时,螺旋桨将起作用,场景结束,然后我们进入菜单屏幕。但是,当子弹击中敌人时,同样的事情也会发生,我也不知道为什么。

现在,这是我的代码:

struct PhysicsCategory {

static let None : UInt32 = 0

static let All : UInt32 = UInt32.max

static let enemyOne : UInt32 = 0b1

static let enemyTwo : UInt32 = 0b1

static let bullet : UInt32 = 0b10

static let spiral : UInt32 = 0b111

}

spiral.physicsBody = SKPhysicsBody(rectangleOfSize: spiral.size)

spiral.physicsBody?.categoryBitMask = PhysicsCategory.spiral

spiral.physicsBody?.contactTestBitMask = PhysicsCategory.enemyOne

spiral.physicsBody?.collisionBitMask = PhysicsCategory.None

...

enemyOne.physicsBody = SKPhysicsBody(rectangleOfSize: enemyOne.size)

enemyOne.physicsBody?.dynamic = true

enemyOne.physicsBody?.categoryBitMask = PhysicsCategory.enemyOne

enemyOne.physicsBody?.contactTestBitMask = PhysicsCategory.bullet | PhysicsCategory.spiral

enemyOne.physicsBody?.collisionBitMask = PhysicsCategory.None

...

bullet.physicsBody = SKPhysicsBody(circleOfRadius: bullet.size.width / 2)

bullet.physicsBody?.dynamic = true

bullet.physicsBody?.categoryBitMask = PhysicsCategory.bullet

bullet.physicsBody?.contactTestBitMask = PhysicsCategory.enemyOne

bullet.physicsBody?.collisionBitMask = PhysicsCategory.None

bullet.physicsBody?.usesPreciseCollisionDetection = true

...

func bulletDidCollideWithEnemy(bullet: SKSpriteNode, enemyOne: SKSpriteNode) {

scoreOnScreen.text = String(score)

score++

bullet.removeFromParent()

enemyOne.removeFromParent()

}

func enemyDidCollideWithSpiral(enemyOne: SKSpriteNode, spiral: SKSpriteNode) {

let transition = SKTransition.revealWithDirection(SKTransitionDirection.Down, duration: 1.0)

let skView = self.view! as SKView

let scene = MenuScene(size: skView.bounds.size)

scene.scaleMode = SKSceneScaleMode.AspectFill

skView.presentScene(scene, transition: SKTransition.crossFadeWithDuration(0.5))

}

// Did Begin Contact

func didBeginContact(contact: SKPhysicsContact) {

var firstBody : SKPhysicsBody

var secondBody : SKPhysicsBody

var thirdBody : SKPhysicsBody

var fourthBody : SKPhysicsBody

if contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask {

firstBody = contact.bodyA

secondBody = contact.bodyB

} else {

firstBody = contact.bodyB

secondBody = contact.bodyA

}

if contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask {

thirdBody = contact.bodyA

fourthBody = contact.bodyB

} else {

thirdBody = contact.bodyB

fourthBody = contact.bodyA

}

if (firstBody.categoryBitMask & PhysicsCategory.enemyOne != 0) && (secondBody.categoryBitMask & PhysicsCategory.bullet != 0) {

bulletDidCollideWithEnemy(firstBody.node as SKSpriteNode, enemyOne : secondBody.node as SKSpriteNode)

}

if (thirdBody.categoryBitMask & PhysicsCategory.enemyOne != 0) && (fourthBody.categoryBitMask & PhysicsCategory.spiral != 0) {

enemyDidCollideWithSpiral(thirdBody.node as SKSpriteNode, spiral : fourthBody.node as SKSpriteNode)

}

现在,我知道那是一团糟,但是有人可以帮助我吗?我认为问题与bodyA.categoryBitMask和bodyB设置为不同的东西有关,甚至认为它们是相同的(?)。我不知道。任何人?

回答:

这里有几个问题。

您在定义类别时要避免对其进行轻松测试。

您正在以无法获得所需唯一答案的方式测试类别。

您已经通过尝试在一个联系人中跟踪多达四个主体来混淆了代码。任何接触都将始终只有两个实体。

让我们一次解决一个问题…

1.定义类别

您想要定义碰撞类别,以便游戏中的每种身体都在

遮罩中使用自己的位。(使用Swift的二进制

文字表示法是个好主意,但是您要定义重叠的类别。)以下

是非重叠类别的示例:

struct PhysicsCategory: OptionSet {

let rawValue: UInt32

init(rawValue: UInt32) { self.rawValue = rawValue }

static let enemy = PhysicsCategory(rawValue: 0b001)

static let bullet = PhysicsCategory(rawValue: 0b010)

static let spiral = PhysicsCategory(rawValue: 0b100)

}

我OptionSet为此使用Swift 类型,因为它使创建

和测试唯一值的组合变得容易。

与an相比,它确实使定义我的类型及其成员的语法有点笨拙enum,但这

也意味着我以后不必做很多装箱和拆箱原始值的工作,

特别是如果我还像这样使便捷访问器:

extension SKPhysicsBody {

var category: PhysicsCategory {

get {

return PhysicsCategory(rawValue: self.categoryBitMask)

}

set(newValue) {

self.categoryBitMask = newValue.rawValue

}

}

}

另外,我在代码中使用了二进制文字表示法,额外的空格和零,

以便轻松地确保每个类别都有自己的位-

enemy仅获得最低有效位,bullet下一个等等。

2&3.测试和跟踪类别

我喜欢使用两层方法来联系处理程序。首先,我要检查

碰撞的类型-是子弹/敌人碰撞还是子弹/螺旋

碰撞或螺旋/敌人碰撞?然后,如有必要,我检查

一下碰撞中的哪个身体。就

计算而言,这并不会花费太多,而且在我的代码的每一点上都非常清楚正在发生什么

func didBegin(_ contact: SKPhysicsContact) {

// Step 1. To find out what kind of contact we have,

// construct a value representing the union of the bodies' categories

// (same as the bitwise OR of the raw values)

let contactCategory: PhysicsCategory = [contact.bodyA.category, contact.bodyB.category]

if contactCategory.contains([.enemy, .bullet]) {

// Step 2: We know it's an enemy/bullet contact, so there are only

// two possible arrangements for which body is which:

if contact.bodyA.category == .enemy {

self.handleContact(enemy: contact.bodyA.node!, bullet: contact.bodyB.node!)

} else {

self.handleContact(enemy: contact.bodyB.node!, bullet: contact.bodyA.node!)

}

} else if contactCategory.contains([.enemy, .spiral]) {

// Here we don't care which body is which, so no need to disambiguate.

self.gameOver()

} else if contactCategory.contains([.bullet, .spiral]) {

print("bullet + spiral contact")

// If we don't care about this, we don't necessarily

// need to handle it gere. Can either omit this case,

// or set up contactTestBitMask so that we

// don't even get called for it.

} else {

// The compiler doesn't know about which possible

// contactCategory values we consider valid, so

// we need a default case to avoid compile error.

// Use this as a debugging aid:

preconditionFailure("Unexpected collision type: \(contactCategory)")

}

}

回答:

为什么要使用if语句和OptionSet类型的contains()方法?为什么不这样做switch,使测试值的语法短很多呢?

switch contactCategory {

case [.enemy, .bullet]:

// ...

case [.enemy, .spiral]:

// ...

// ...

default:

// ...

}

使用switch此处的问题在于它会测试您的OptionSets是否相等 -也就是说,案例1会在if触发contactCategory == [.enemy, .bullet],而在if则不会触发[.enemy, .bullet, .somethingElse]。

对于在此示例中定义的联系人类别,这不是问题。但是类别/接触式位掩码系统的一个不错的功能之一

是您可以在单个项目上编码多个类别。例如:

struct PhysicsCategory: OptionSet {

// (don't forget rawValue and init)

static let ship = PhysicsCategory(rawValue: 0b0001)

static let bullet = PhysicsCategory(rawValue: 0b0010)

static let spiral = PhysicsCategory(rawValue: 0b0100)

static let enemy = PhysicsCategory(rawValue: 0b1000)

}

friendlyShip.physicsBody!.category = [.ship]

enemyShip.physicsBody!.category = [.ship, .enemy]

friendlyBullet.physicsBody!.category = [.bullet]

enemyBullet.physicsBody!.category = [.bullet, .enemy]

在这种情况下,您可能有一个类别为[.ship,.bullet,.enemy]—的联系人,并且如果您的联系人处理逻辑专门针对进行测试[.ship, .bullet],您会错过它。如果contains改为使用,则可以

测试您关心的特定标志,而无需关心是否存在其他标志。

以上是 Swift / SpriteKit多碰撞检测? 的全部内容, 来源链接: utcz.com/qa/403745.html

回到顶部