SpriteKit中精灵之间的碰撞

Posted

技术标签:

【中文标题】SpriteKit中精灵之间的碰撞【英文标题】:Collisions between sprites in SpriteKit 【发布时间】:2015-09-07 22:56:13 【问题描述】:

我正在使用 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】:

令人困惑的是collisionBitMask 用于定义在physicsModel 中交互的physicsBodies。你真正想要的是contactTestBitmask

您的物理也没有返回用于位掩码的正确值。作为纯整数,它们应该是 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()

【讨论】:

感谢您的回答,但它改变了一切!您(或其他人)能否向我解释一下如何使两枚导弹相互通过而不发生碰撞? 它并没有真正改变一切,你仍然可以保持你的 didBeginContact 功能,例如。如果您不想使用我的建议,那很好,但您仍然需要使用contactBitMask 而不是collisionBitMask。对于您的问题,这很简单:missileSprite.physicsBody.collisionBitMask = 0 因此,您需要从我的答案中删除的唯一内容是使用contact 而不是collisionBitMasks 来检查(您所指的)碰撞。此外,BitMask 需要具有适当的 BitMask 值 (1,2,4,8) 等,以便与 BitWise OR 正常工作... 我遵循了每一条指令,但这并不能防止两枚导弹相互碰撞并“弹跳”。很抱歉耽搁了,但感谢有关联系人的提示 它们应该有不同的 categoryBitmask,但它们的碰撞位掩码都应该为 0。您需要理清类别、接触和碰撞位掩码之间的区别...

以上是关于SpriteKit中精灵之间的碰撞的主要内容,如果未能解决你的问题,请参考以下文章

如何检测精灵套件中的碰撞?

在精灵套件中发生碰撞时停止对象

检测精灵套件中的碰撞

将任意信息附加到 SKSpriteNode

Spritekit:如何将玩家移动限制在某些瓷砖上

边缘检测 --> CGPath --> SpriteKite 碰撞