SpriteKit中精灵之间的碰撞

时间:2015-09-07 22:56:14

标签: ios swift sprite-kit collision-detection

我正在使用SpriteKit在XCode中制作游戏。游戏中有一个玩家和他必须避免的不同类型的射弹。当玩家与射弹碰撞时,分数改变并且射弹消失。然而,当两个射弹碰撞时,它们会反弹。 我希望每当两个射弹碰撞时,它们就像没有发生任何事情一样,并且它们继续沿着原始路径行进。我该怎么办?

*注意:这不是整个代码,重要的是它。

    import SpriteKit

    struct Physics {
        static let player : UInt32 = 1
        static let missileOne : UInt32 = 2
        static let missileTwo : UInt32 = 3
    }

class GameScene: SKScene, SKPhysicsContactDelegate {

    var player = SKSpriteNode(imageNamed: "p1.png")

    override func didMoveToView(view: SKView) {

        physicsWorld.contactDelegate = self

        player.position = CGPointMake(self.size.width/2, self.size.height/5)
        player.physicsBody = SKPhysicsBody(rectangleOfSize: player.size)
        player.physicsBody?.affectedByGravity = false
        player.physicsBody?.dynamic = false
        player.physicsBody?.categoryBitMask = Physics.player
        player.physicsBody?.collisionBitMask = Physics.missileOne
        player.physicsBody?.collisionBitMask = Physics.missileTwo

        var missileOneTimer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: Selector("SpawnMissileOne"), userInfo: nil, repeats: true)
        var missileTwoTimer = NSTimer.scheduledTimerWithTimeInterval(1.2, target: self, selector: Selector("SpawnMissileTwo"), userInfo: nil, repeats: true)

        self.addChild(player)
    }

    //When contact happens
func didBeginContact(contact: SKPhysicsContact) {
    var firstBody : SKPhysicsBody = contact.bodyA
    var secondBody : SKPhysicsBody = contact.bodyB

    if ((firstBody.categoryBitMask == Physics.player) && (secondBody.categoryBitMask == Physics.missileOne)) {

        CollisionWithMissileOne(firstBody.node as SKSpriteNode, missileOne: secondBody.node as SKSpriteNode)

    } else if ((firstBody.categoryBitMask == Physics.player) && (secondBody.categoryBitMask == Physics.missileTwo)){

        CollisionWithMissileTwo(firstBody.node as SKSpriteNode, missileTwo: secondBody.node as SKSpriteNode)

    } else if ((firstBody.categoryBitMask == Physics.missileOne)&&(secondBody.categoryBitMask == Physics.missileTwo)) {

        CollisionBetweenMissiles(firstBody.node as SKSpriteNode, missileTwo: secondBody.node as SKSpriteNode)

        } 

    }

//For Player and MissileOne
    func CollisionWithMissileOne(player: SKSpriteNode, missileOne: SKSpriteNode) {

        missileOne.removeFromParent()
    }

//For Player and MissileTwo
    func CollisionWithMissileOne(player: SKSpriteNode, missileTwo: SKSpriteNode) {

        missileTwo.removeFromParent()
    }

//For MissileOne and MissileTwo
        func CollisionBetweenMissiles(missileOne: SKSpriteNode, missileTwo: SKSpriteNode) {

        ???WHAT SHOULD I CODE HERE???

    }

}

1 个答案:

答案 0 :(得分:2)

混淆是collisionBitMask用于定义在physicsModel中交互的物理实体。你真正想要的是contactTestBitmask

此外,您的物理学不会返回用于位掩码的正确值。作为纯粹的Ints,他们应该是1,2,4,8等。

以下是您的代码更改为(希望)有效的内容,无论我在何处制作,我都会对其进行评论。

 struct Physics {
        static let player : UInt32 = 1
        static let missileOne : UInt32 = 2
        static let missileTwo : UInt32 = 4 // to work properly as bit masks
    }

如果要检查与多种physicsBody.categoryBitMask类型的联系,则必须进行此更改。查看didMoveToView中的player.physicsBody?.contactTestBitMask = ...

override func didMoveToView(view: SKView) {
    physicsWorld.contactDelegate = self
    // All your existing player-stuff is fine until...
    // contactTest, not collision but contact, also: use bitwise OR
    player.physicsBody?.contactTestBitMask = Physics.missileOne | Physics.missileTwo
    self.addChild(player)

    // It is not recommended to use NSTimer for SpriteKit, use SKActions instead
    let missileOneWait = SKAction.waitForDuration(1)
    let callSpawnOneAction = SKAction.runBlock({ self.spawnMissileOne() })
    let missileOneRepeat = SKAction.repeatActionForever(SKAction.sequence([missileOneWait, callSpawnOneAction]))
    runAction(missileOneRepeat)

    let missileTwoWait = SKAction.waitForDuration(1.2)
    let callSpawnTwoAction = SKAction.runBlock({ self.spawnMissileTwo() })
    let missileTwoRepeat = SKAction.repeatActionForever(SKAction.sequence([missileTwoWait, callSpawnTwoAction]))
    runAction(missileTwoRepeat)
}

几乎重写了didBeginContact到我认为读取的内容并且扩展更好:

func didBeginContact(contact: SKPhysicsContact) {
    var firstBody = contact.bodyA
    var secondBody = contact.bodyB

    // Rewritten with dynamic variables
    var playerNode : SKSpriteNode? {
        if firstBody.categoryBitMask == Physics.player {
            return firstBody.node as? SKSpriteNode
        } else if secondBody.categoryBitMask == Physics.player {
            return secondBody.node as? SKSpriteNode
        }
        return nil
    }

    // If you want to handle contact between missiles you need to split this 
    // into two different variables
    var missileNode : SKSpriteNode? {
        let bitmask1 = firstBody.categoryBitMask
        let bitmask2 = secondBody.categoryBitMask

        if bitmask1 == Physics.missileOne || bitmask1 == Physics.missileTwo {
            return firstBody.node as? SKSpriteNode
        } else if bitmask2 == Physics.missileOne || bitmask2 == Physics.missileTwo {
            return secondBody.node as? SKSpriteNode
        }
        return nil
    }

    if playerNode != nil {
        collisionBetweenPlayer(playerNode, missile: missileNode)
    }
} 

然后你只需要一个导弹和玩家之间接触的功能:

func collisionBetweenPlayer(player: SKSpriteNode?, missile: SKSpriteNode?) {
    missile?.removeFromParent()
}