ios - SpriteKit 中 Sprite 之间的碰撞

标签 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???

    }

}

最佳答案

混淆是 collisionBitMask 用于定义在 physicsModel 中交互的 physicsBodies。您真正想要的是 contactTestBitmask

此外,您的 Physics 不会返回用于位掩码的正确值。作为纯整数,它们应该是 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()
}

关于ios - SpriteKit 中 Sprite 之间的碰撞,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32446973/

相关文章:

ios - 如何在初始化器中使用 Swift 扩展函数?

ios - 带参数的 SKAction 运行方法?

iOS:如何检测外部键盘上修饰键状态的变化?

swift - 了解同步 Realm 何时是最新的

swift - 为什么我尝试在 mac 终端中使用 $ swift 运行 swift 语言时出现错误

ios - 循环延迟的同步问题

ios - 触摸事件,多个游戏对象?

ios - QLPreviewController 不加载多个文件

ios - ics 文件 - 无法在 iOS7 中打开附加的 .ICS 文件

ios - 在 UITableView 中,如何在隐藏行之后关闭行的底部边框?