Swift: выполнение команд при контакте между узлами - PullRequest
0 голосов
/ 26 февраля 2020

Прямо сейчас у меня есть кирпич, который падает на экран. Когда он попадает в мою клетку, ничего не происходит. Как вы можете видеть на изображении ниже, у меня есть четыре треугольника, которые составляют квадрат в том же месте, но с низкой непрозрачностью. Это поможет различить, с какой стороны квадрата происходит контакт. Тем не менее, ничто не возрождается и не исчезает, когда кирпич попадает в треугольник (треугольники, составляющие квадрат).

Изображение из игры

    func spawnBrick()  {
            let randomFunc = [self.spawnbrickTop, self.spawnbrickBottom, self.spawnbrickLeft, self.spawnbrickRight]
            let randomResult = Int(arc4random_uniform(UInt32(randomFunc.count)))
            randomFunc[randomResult]()
        }



    func spawnbrickTop() {

        brickTop.size = CGSize(width: 210, height: 105)
        brickTop.name = "BrickTop"
        brickTop.position = CGPoint(x: frame.midX, y: frame.maxY)
        brickTop.zPosition = 1.5
        //physics stuff begins here
        brickTop.physicsBody = SKPhysicsBody(circleOfRadius: max(brickTop.size.width / 2,
                                                                 brickTop.size.height / 2))
        brickTop.physicsBody?.categoryBitMask = PhysicsCategories.brickTopCategory
        brickTop.physicsBody?.contactTestBitMask = PhysicsCategories.basicTopCategory |
        PhysicsCategories.basicBottomCategory |
        PhysicsCategories.basicLeftCategory |
        PhysicsCategories.basicRightCategory
        brickTop.physicsBody?.collisionBitMask = PhysicsCategories.none
         //bye bye physics
        self.addChild(brickTop)

    }

    func spawnbrickBottom() {

        brickBottom.size = CGSize(width: 230, height: 101)
        brickBottom.name = "BrickBottom"
        brickBottom.position = CGPoint(x: frame.midX, y: frame.maxY)
        brickBottom.zPosition = 1.5
        //physics stuff begins here
        brickBottom.physicsBody = SKPhysicsBody(circleOfRadius: max(brickBottom.size.width / 2,
                                                                    brickBottom.size.height / 2))
        brickBottom.physicsBody?.categoryBitMask = PhysicsCategories.brickBottomCategory
        brickBottom.physicsBody?.contactTestBitMask = PhysicsCategories.basicTopCategory |
        PhysicsCategories.basicBottomCategory |
        PhysicsCategories.basicLeftCategory |
        PhysicsCategories.basicRightCategory
        brickBottom.physicsBody?.collisionBitMask = PhysicsCategories.none
         //bye bye physics
        self.addChild(brickBottom)
    }

    func spawnbrickLeft() {


        brickLeft.size = CGSize(width: 170, height: 80)
        brickLeft.name = "BrickLeft"
        brickLeft.position = CGPoint(x: frame.midX, y: frame.maxY)
        brickLeft.zPosition = 1.5
        //physics stuff begins here
        brickLeft.physicsBody = SKPhysicsBody(circleOfRadius: max(brickLeft.size.width / 2,
                                                                  brickLeft.size.height / 2))
        brickLeft.physicsBody?.categoryBitMask = PhysicsCategories.brickLeftCategory
        brickLeft.physicsBody?.contactTestBitMask = PhysicsCategories.basicTopCategory |
        PhysicsCategories.basicBottomCategory |
        PhysicsCategories.basicLeftCategory |
        PhysicsCategories.basicRightCategory
        brickLeft.physicsBody?.collisionBitMask = PhysicsCategories.none
         //bye bye physics
        self.addChild(brickLeft)

    }


    func spawnbrickRight() {

        brickRight.size = CGSize(width: 140, height: 95)
        brickRight.name = "BrickRight"
        brickRight.position = CGPoint(x: frame.midX, y: frame.maxY)
        brickRight.zPosition = 1.5
        //physics stuff begins here
        brickRight.physicsBody = SKPhysicsBody(circleOfRadius: max(brickRight.size.width / 2,
                                          brickRight.size.height / 2))
        brickRight.physicsBody?.categoryBitMask = PhysicsCategories.brickRightCategory
        brickRight.physicsBody?.contactTestBitMask = PhysicsCategories.basicTopCategory |
        PhysicsCategories.basicBottomCategory |
        PhysicsCategories.basicLeftCategory |
        PhysicsCategories.basicRightCategory
        brickRight.physicsBody?.collisionBitMask = PhysicsCategories.none
         //bye bye physics
        self.addChild(brickRight)

    }


    func spawnBasicBrick() {
            basicBrick.size = CGSize(width: 200, height: 177.6)
            basicBrick.position = CGPoint(x: frame.midX, y: frame.minY + basicBrick.size.width)
            basicBrick.zPosition = 1


            basicBrick.physicsBody = SKPhysicsBody(rectangleOf: basicBrick.size)
            basicBrick.physicsBody?.categoryBitMask = PhysicsCategories.basicBrickCategory
            basicBrick.physicsBody?.isDynamic = false
            basicBrick.physicsBody?.allowsRotation = true

            addChild(basicBrick)
        }
        func spawnBasicTop() {

            basicTop.size = CGSize(width: 400, height: 400)
            basicTop.position = CGPoint(x: 230, y: 200)
            basicTop.zPosition = 1.5
            basicTop.alpha = 0.3
            basicTop.name = "BasicTop"

            //physics stuff begins here
            basicTop.physicsBody = SKPhysicsBody(rectangleOf: basicTop.size)
            basicTop.physicsBody?.categoryBitMask = PhysicsCategories.basicTopCategory
            basicTop.physicsBody?.isDynamic = false
            basicTop.physicsBody?.allowsRotation = true
            //bye bye physics


            addChild(basicTop)
        }

        func spawnBasicBottom() {

            basicBottom.size = CGSize(width: 400, height: 400)
            basicBottom.position = CGPoint(x: 230, y: 200)
            basicBottom.zPosition = 1.5
            basicBottom.alpha = 0.3
            basicBottom.name = "BasicBottom"

            //physics stuff begins here
            basicBottom.physicsBody = SKPhysicsBody(rectangleOf: basicBottom.size)
            basicBottom.physicsBody?.categoryBitMask = PhysicsCategories.basicBottomCategory
            basicBottom.physicsBody?.isDynamic = false
            //bye bye physics


            addChild(basicBottom)
        }
        func spawnBasicLeft() {

            basicLeft.size = CGSize(width: 400, height: 400)
            basicLeft.position = CGPoint(x: 230, y: 200)
            basicLeft.zPosition = 1.5
            basicLeft.alpha = 0.3
            basicLeft.name = "BasicLeft"

            //physics stuff begins here
            basicLeft.physicsBody = SKPhysicsBody(rectangleOf: basicLeft.size)
            basicLeft.physicsBody?.categoryBitMask = PhysicsCategories.basicLeftCategory
            basicLeft.physicsBody?.isDynamic = false
            //bye bye physics


            addChild(basicLeft)
        }

        func spawnBasicRight() {

            basicRight.size = CGSize(width: 400, height: 400)
            basicRight.position = CGPoint(x: 230, y: 200)
            basicRight.zPosition = 1.5
            basicRight.alpha = 0.3
            basicRight.name = "BasicRight"

            //physics stuff begins here
            basicRight.physicsBody = SKPhysicsBody(rectangleOf: basicRight.size)
            basicRight.physicsBody?.categoryBitMask = PhysicsCategories.basicRightCategory
            basicRight.physicsBody?.isDynamic = false
            //bye bye physics


            addChild(basicRight)
        }



extension GameScene: SKPhysicsContactDelegate {

    func didBegin(_ contact: SKPhysicsContact) {
        //01
        //10
        //11
        let contactMask = contact.bodyA.categoryBitMask |
            contact.bodyB.categoryBitMask

        if contactMask == PhysicsCategories.brickTopCategory |
            (PhysicsCategories.basicTopCategory) {
            if let brickTop = contact.bodyA.node?.name == "BrickTop" ? contact.bodyA.node
                as? SKSpriteNode : contact.bodyB.node as? SKSpriteNode {
            if contact.bodyA.node?.name == "BrickTop" &&
               contact.bodyB.node?.name == "BasicTop" {

                    print("Correct!")
                    brickTop.run(SKAction.fadeOut(withDuration: 0.05), completion: {
                        self.brickTop.removeFromParent()
                        self.spawnBrick()
                    })
            }
    }
           else if contactMask == PhysicsCategories.brickBottomCategory |
                    (PhysicsCategories.basicBottomCategory) {
            if let brickBottom = contact.bodyA.node?.name == "BrickBottom" ? contact.bodyA.node
            as? SKSpriteNode : contact.bodyB.node as? SKSpriteNode {
                    if contact.bodyA.node?.name == "BrickBottom" &&
                       contact.bodyB.node?.name == "BasicBottom" {

                            print("Correct!")
                            brickBottom.run(SKAction.fadeOut(withDuration: 0.05), completion: {
                                self.brickBottom.removeFromParent()
                                self.spawnBrick()
                            })
                    }
            }
       else if contactMask == PhysicsCategories.brickLeftCategory |
                (PhysicsCategories.basicLeftCategory) {
        if let brickLeft = contact.bodyA.node?.name == "BrickLeft" ? contact.bodyA.node
        as? SKSpriteNode : contact.bodyB.node as? SKSpriteNode {
                if contact.bodyA.node?.name == "BrickLeft" &&
                   contact.bodyB.node?.name == "BasicLeft" {

                        print("Correct!")
                        brickLeft.run(SKAction.fadeOut(withDuration: 0.05), completion: {
                            self.brickLeft.removeFromParent()
                            self.spawnBrick()
                        })
                }
        }
       else if contactMask == PhysicsCategories.brickRightCategory |
                (PhysicsCategories.basicRightCategory) {
        if let brickRight = contact.bodyA.node?.name == "BrickRight" ? contact.bodyA.node
        as? SKSpriteNode : contact.bodyB.node as? SKSpriteNode {
                if contact.bodyA.node?.name == "BrickRight" &&
                   contact.bodyB.node?.name == "BasicRight" {

                        print("Correct!")
                        brickRight.run(SKAction.fadeOut(withDuration: 0.05), completion: {
                            self.brickRight.removeFromParent()
                            self.spawnBrick()
                        })
                }
        }
        else {
            gameOver()
        }
  }
 }
}
}
}
}


enum PhysicsCategories {
    static let none: UInt32 = 0
    static let brickCategory: UInt32 = 1//01
    static let brickTopCategory: UInt32 = 1 //01
    static let brickBottomCategory: UInt32 = 1//01
    static let brickLeftCategory: UInt32 = 1//01
    static let brickRightCategory: UInt32 = 1//01

    static let basicTopCategory: UInt32 = 1 //10; shifts all bits to the left
    static let basicBottomCategory: UInt32 = 1 //10; shifts all bits to the left
    static let basicLeftCategory: UInt32 = 1 //10; shifts all bits to the left
    static let basicRightCategory: UInt32 = 1 //10; shifts all bits to the left

    static let basicBrickCategory: UInt32 = 1
}

1 Ответ

0 голосов
/ 26 февраля 2020

Проблема, вероятно, в следующих строках:

brickTop.physicsBody?.contactTestBitMask = PhysicsCategories.basicTopCategory
brickTop.physicsBody?.contactTestBitMask = PhysicsCategories.basicBottomCategory
brickTop.physicsBody?.contactTestBitMask = PhysicsCategories.basicLeftCategory
brickTop.physicsBody?.contactTestBitMask = PhysicsCategories.basicRightCategory

В этом коде битовая маска контакта заканчивается просто как basicRight. Вы хотите объединить их. Предполагается, что вы правильно настроили категории для начала (как 1, 2, 4, 8 и т. Д. c)

Вы хотите, чтобы это было больше похоже на это:


brickTop.physicsBody?.contactTestBitMask = PhysicsCategories.basicTopCategory |
   PhysicsCategories.basicBottomCategory |
   PhysicsCategories.basicLeftCategory |
   PhysicsCategories.basicRightCategory

Вот как это должно работать

  1. У вас есть несколько узлов в вашей сцене
  2. Вы группируете их по категориям с похожим поведением
  3. Вы создаете перечисление / значение категории для каждой категории в виде бита в маске (1, 2, 4 и т. д. c), который равен (0x1 << 0, 0x1 << 1, 0x1 << 2) </li>
  4. Вы помещаете узлы в категории (используя | для объединения значений категорий)
  5. Вы устанавливаете битовые маски contactTest и collisionDetect (используя | для объединения значений категорий)

Я не знаю, как должна работать ваша игра, но есть несколько вещей, которые выглядят странно в вашем коде.

  1. Вы используете одно и то же число для разных категорий
  2. Вы не объединяйте их в битовые маски.

Представьте, что у меня есть игра Понг. Я хочу определить, когда мяч ударяется о

  1. Боковые стенки, чтобы отскочить от него
  2. Верх и низ экрана, чтобы записать
  3. Весла, чтобы отскочить от него

Узлы

  1. шар
  2. левая стена
  3. правая стена
  4. низ
  5. верх
  6. верхнее весло
  7. нижнее весло
  8. игрок 1 счет
  9. игрок 2 счет

Категории (это только пример - это не единственный способ)

  1. CategoryNone: 0
  2. CategoryGamePiece: 1
  3. CategoryOutDetector: 2
  4. CategoryNonInteractive: 4 (используется для узлы счета)

Мяч отскакивает от лопастей и боковых стенок. Он также взаимодействует с невидимыми извещателями сверху и снизу. Он подразделяется на две категории (используя |)

ball.categoryBitMask = CategoryGamePiece | CategoryOutDetector
ball.collisionBitMask = CategoryGamePiece
ball.contactTestBitMask = CategoryOutDetector

Весло и боковая стенка взаимодействуют только с мячом как игровой элемент (столкновение)

paddleTop.categoryBitMask = CategoryGamePiece
paddleTop.collisionBitMask = CategoryGamePiece
paddleTop.contactTestBitMask = CategoryNone

leftWall.categoryBitMask = CategoryGamePiece
leftWall.collisionBitMask = CategoryGamePiece
leftWall.contactTestBitMask = CategoryNone

Дно взаимодействует только с мячом в качестве контактного теста (не меняет своего движения)

bottomOut.categoryBitMask = CategoryOutDetector
bottomOut.collisionBitMask = CategoryNone
bottomOut.contactTestBitMask = CategoryOutDetector
...