检查两个节点相互接触时的颜色是不是相同

Posted

技术标签:

【中文标题】检查两个节点相互接触时的颜色是不是相同【英文标题】: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”? 【参考方案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 块很快就会变得一团糟。

以上是关于检查两个节点相互接触时的颜色是不是相同的主要内容,如果未能解决你的问题,请参考以下文章

uva10054

碰撞检测导致颜色检测? [复制]

如何统一检查最近物体的颜色?

为树中的节点添加颜色

Codeforces 1244F. Chips

这是一个字谜程序,我正在检查两个相同长度的字符串是不是相互字谜