【问题标题】:Collisions between sprites in SpriteKitSpriteKit中精灵之间的碰撞
【发布时间】: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???

    }

}

【问题讨论】:

    标签: ios swift sprite-kit collision-detection


    【解决方案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。您需要理清类别、接触和碰撞位掩码之间的区别...
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-04-02
    • 1970-01-01
    • 1970-01-01
    • 2017-08-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多