【问题标题】:Check if two nodes are the same color when they touch each other检查两个节点相互接触时的颜色是否相同
【发布时间】:2017-03-02 09:13:13
【问题描述】:

我是 Swift 新手,如果我犯了菜鸟错误,我深表歉意。如果两个盒子颜色相同,我试图让两个盒子在它们接触时消失。到目前为止,我有以下代码:

此代码设置游戏:

    import SpriteKit
    import GameplayKit

    class GameScene: SKScene, SKPhysicsContactDelegate {
        override func didMove(to view: SKView) {
            physicsBody = SKPhysicsBody(edgeLoopFrom: frame)
            physicsWorld.contactDelegate = self

            let background = SKSpriteNode(imageNamed: "background.jpg")
            background.size = self.frame.size;
            background.position = CGPoint(x: 0, y: 0)
            background.blendMode = .replace
            background.zPosition = -1
            addChild(background)

        }

生成随机颜色的代码:

        enum Color {
            case ColorRed
            case ColorGreen
            case ColorBlue

            public var color: UIColor {
                switch self {
                case .ColorRed: return UIColor(red: 255, green: 0, blue: 0, alpha: 1)
                case .ColorGreen: return UIColor(red: 0, green: 255, blue: 0, alpha: 1)
                case .ColorBlue: return UIColor(red: 0, green: 0, blue: 255, alpha: 1)
                }
            }

            static var all: [Color] = [.ColorRed, .ColorGreen, .ColorBlue]

            static var randomColor: UIColor {
                let randomIndex = Int(arc4random_uniform(UInt32(all.count)))
                return all[randomIndex].color
            }
        }

这是重要的部分 - 对象之间的实际接触:

    func didBegin(_ contact: SKPhysicsContact) {

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

            let firstBody = contact.bodyA.node as! SKSpriteNode!
            let secondBody = contact.bodyB.node as! SKSpriteNode!

            if firstBody!.color == secondBody!.color {
                firstBody!.removeFromParent()
                secondBody!.removeFromParent()
            }
        } else {

            let firstBody = contact.bodyB.node as! SKSpriteNode!
            let secondBody = contact.bodyA.node as! SKSpriteNode!

            if firstBody!.color == secondBody!.color {
                firstBody!.removeFromParent()
                secondBody!.removeFromParent()
            }
        }
    }

最后是用户触摸屏幕时的代码:

        override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
            if let touch = touches.first {
                let location = touch.location(in: self)
                let box = SKSpriteNode(color: UIColor.red, size: CGSize(width: 64, height: 64))
                box.color = Color.randomColor
                box.physicsBody = SKPhysicsBody(rectangleOf: CGSize(width: 64, height: 64))
                box.position = location
                addChild(box)
            }
        }

我已提供所有代码,以便您了解设置。提前感谢您的帮助。

【问题讨论】:

  • 运行代码时实际看到的内容以及它与您的预期有何不同。此外,您的 func didBegin 的一半是多余的,因为您删除了任何进入函数的节点。
  • 它与您的要求无关,但为什么要为 Color 创建枚举?为什么不在 UIColor 扩展中创建静态计算属性“randomColor”?

标签: ios swift sprite-kit swift3 skspritenode


【解决方案1】:

您没有正确设置contactBitMask,因此没有检测到联系人...默认情况下,由于性能原因,此掩码的默认值为零:

当两个 body 共享同一个空间时,每个 body 的类别掩码为 通过执行逻辑测试对另一个身体的接触面罩 与操作。如果任一比较结果为非零值,则 SKPhysicsContact 对象被创建并传递给物理世界的 代表。为获得最佳性能,仅在触点掩码中设置位 您感兴趣的互动。

默认值为 0x00000000(所有位清零)。

要解决此问题,请将联系人和类别位掩码设置为适当的值,如下所示:

class GameScene: SKScene,SKPhysicsContactDelegate {

    override func didMove(to view: SKView) {
        self.physicsWorld.contactDelegate = self

        physicsBody = SKPhysicsBody(edgeLoopFrom: frame)
        physicsWorld.contactDelegate = self


    }

    func didBegin(_ contact: SKPhysicsContact) {

        if let bodyA = contact.bodyA.node as? SKSpriteNode,
           let bodyB = contact.bodyB.node as? SKSpriteNode{
            //Of course this is simple example and you will have to do some "filtering" to determine what type of objects are collided.
           // But the point is , when appropriate objects have collided, you compare their color properties.
            if bodyA.color == bodyB.color {
                bodyA.run(SKAction.removeFromParent())
                bodyB.run(SKAction.removeFromParent())
            }
        }
    }

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        if let touch = touches.first {
            let location = touch.location(in: self)
            let box = SKSpriteNode(color: UIColor.red, size: CGSize(width: 64, height: 64))
            box.color = Color.randomColor

            box.physicsBody = SKPhysicsBody(rectangleOf: CGSize(width: 64, height: 64))
            box.physicsBody?.contactTestBitMask = 0b1
            box.physicsBody?.categoryBitMask = 0b1
            box.position = location
            addChild(box)
        }
    }
}

现在,当两个实体之间发生联系时,如文档中所述,每个实体的类别位掩码都会通过执行逻辑与运算与另一个实体的联系掩码进行测试。如果结果非零,则发生联系通知。在这种情况下,这将是 1 & 1 = 1。

【讨论】:

    【解决方案2】:

    首先,为categoryBitMask 声明一个struct

    struct ColorMask {
        static let Red: UInt32 = 0x1 << 0
        static let Green: UInt32 = 0x1 << 1
        static let Blue: UInt32 = 0x1 << 2
    }
    

    其次,将您的枚举声明更改为以下内容:

    enum Color {
        case ColorRed
        case ColorGreen
        case ColorBlue
    
        public var color: UIColor {
            switch self {
            case .ColorRed: return UIColor(red: 255, green: 0, blue: 0, alpha: 1)
            case .ColorGreen: return UIColor(red: 0, green: 255, blue: 0, alpha: 1)
            case .ColorBlue: return UIColor(red: 0, green: 0, blue: 255, alpha: 1)
            }
        }
    
        static var all: [Color] = [.ColorRed, .ColorGreen, .ColorBlue]
    
        static var randomColor: Color {
            let randomIndex = Int(arc4random_uniform(UInt32(all.count)))
            return all[randomIndex]
        }
    }
    

    我只是将上面的代码改成返回Color而不是UIColor

    三、修改didBegin为:

    func didBegin(_ contact: SKPhysicsContact) {
        if contact.bodyA.categoryBitMask == contact.bodyB.categoryBitMask {
            let firstBody = contact.bodyA.node as! SKSpriteNode!
            let secondBody = contact.bodyB.node as! SKSpriteNode!
    
            firstBody!.removeFromParent()
            secondBody!.removeFromParent()
        }
    }
    

    在上面的代码中,只需比较categoryBitMask就足够了,因为我稍后会将相同颜色的body设置为相同的categoryBitMask

    最后,使用以下代码将categoryBitMask 设置为框:

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        if let touch = touches.first {
            let location = touch.location(in: self)
            let box = SKSpriteNode(color: UIColor.red, size: CGSize(width: 64, height: 64))
            let color = Color.randomColor
            box.color = color.color
            box.physicsBody = SKPhysicsBody(rectangleOf: CGSize(width: 64, height: 64))
            if color == Color.ColorRed {
                box.physicsBody?.categoryBitMask = ColorMask.Red
            } else if color == Color.ColorGreen {
                box.physicsBody?.categoryBitMask = ColorMask.Green
            }else if color == Color.ColorBlue {
                box.physicsBody?.categoryBitMask = ColorMask.Blue
            }
            box.physicsBody?.contactTestBitMask = ColorMask.Red | ColorMask.Green | ColorMask.Blue
            box.position = location
            addChild(box)
        }
    }
    

    【讨论】:

    • 如果他想拥有 1000 种不同的颜色怎么办?或者只有 100 个,但你知道我要去的地方吗?您将没有足够的类别...并且在您当前的设置下,那些 if else 块很快就会变得一团糟。
    猜你喜欢
    • 2013-11-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-25
    • 1970-01-01
    • 1970-01-01
    • 2015-01-06
    相关资源
    最近更新 更多