Битовая маска категории SpriteKit работает неправильно

В моем проекте xcode я пытаюсь создать функцию, которая вызывается, когда SKShapeNode достигает границы мира (края экрана), которую я создал. SKShapeNode ударяется о край экрана и катится вправо из-за гравитации, но когда происходит контакт, функция didBeginContact не вызывается. вот мой код

import SpriteKit

class GameScene: SKScene, SKPhysicsContactDelegate {

struct PhysicsCategory {

    static let redBall: UInt32 =  0x1 << 1
    static let blueBall:  UInt32 = 0x1 << 2
    static let worldBorder: UInt32 = 0x1 << 3

}

let slimeBall = SKSpriteNode(imageNamed: "slimeBall")
let lilyPete = SKSpriteNode(imageNamed:"golden")



override func didMoveToView(view: SKView) {

    self.physicsBody = SKPhysicsBody(edgeLoopFromRect: self.frame)
    self.physicsWorld.gravity = CGVectorMake(1, 5)
    self.physicsBody?.categoryBitMask = PhysicsCategory.worldBorder
    self.physicsBody!.node?.name = "world"


    self.backgroundColor = UIColor.darkGrayColor()

    let playerCircle = SKShapeNode(circleOfRadius: 15)
    playerCircle.name = "blueCircle"
    playerCircle.fillColor = UIColor.blueColor()
    playerCircle.strokeColor = UIColor.blackColor()
    playerCircle.position = CGPointMake(self.frame.size.width / 2, self.frame.size.height / 2)
    playerCircle.physicsBody?.categoryBitMask = PhysicsCategory.redBall
    playerCircle.physicsBody?.contactTestBitMask = PhysicsCategory.worldBorder | PhysicsCategory.redBall
    playerCircle.physicsBody?.collisionBitMask = PhysicsCategory.blueBall | PhysicsCategory.worldBorder

    addChild(playerCircle)

    let enemyCircle = SKShapeNode(circleOfRadius: 50)
    enemyCircle.name = "redCircle"
    enemyCircle.fillColor = UIColor.redColor()
    enemyCircle.strokeColor = UIColor.blackColor()
    enemyCircle.physicsBody = SKPhysicsBody(circleOfRadius: 50)
    enemyCircle.position = CGPointMake(self.frame.size.width / 3, self.frame.size.height / 2)
    enemyCircle.physicsBody?.affectedByGravity = true
    enemyCircle.physicsBody?.dynamic = true
    enemyCircle.physicsBody!.mass = 0.05
    enemyCircle.physicsBody?.categoryBitMask = PhysicsCategory.blueBall
    enemyCircle.physicsBody?.contactTestBitMask = PhysicsCategory.worldBorder | PhysicsCategory.blueBall
    enemyCircle.physicsBody?.collisionBitMask = PhysicsCategory.worldBorder | PhysicsCategory.blueBall

    addChild(enemyCircle)
    enemyCircle.physicsBody?.applyForce(CGVectorMake(-2, -3))



  }


func didBeginContact(contact: SKPhysicsContact) {

    let firstBody = contact.bodyA
    let secondBody = contact.bodyB

    if(contact.bodyA.node?.name == "redCircle") && (contact.bodyB.node?.name == "world") || (contact.bodyA.node?.name == "world") && (contact.bodyB.node?.name == "redCircle"){

        print("Contact Made")


    }






}


override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {


    let touch = touches.first! as UITouch
    let touchLocation = touch.locationInNode(self)




}
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {


    let touch = touches.first! as UITouch
    let touchLocation = touch.locationInNode(self)

}


}

person Charles    schedule 07.05.2016    source источник


Ответы (2)


Ваш красный круг имеет битовую маску категории blueBall и битовую маску контакта для взаимодействия только с worldBorder и другими blueBall. Ваш синий кружок имеет битовую маску категории redBall и будет связываться только с worldBorder и другими blueBall.

Установите категорию вашего красного круга на redBall, и вы установите категорию вашего синего круга на blueBall, тогда все ваши коллизии должны работать. Возможно, вы захотите снова просмотреть свои битовые маски теперь, когда эти две маски были поменяны местами, чтобы убедиться, что все сталкивается со всем остальным, как и должно, поскольку вы не упомянули, как это должно быть настроено.

Тем не менее, одно быстрое примечание в вашем методе didBeginContact: вы неправильно выполняете проверку операторов if (IMO). На самом деле, вы совсем не знаете. Я рекомендую обернуть ваши чеки следующим образом:

if ((contact.bodyA.node?.name == "redCircle") && (contact.bodyB.node?.name == "world")) || ((contact.bodyA.node?.name == "world") && (contact.bodyB.node?.name == "redCircle")) {

Это проверит все на одной стороне || на все на другой стороне, что затем позволит вашему && находиться отдельно, только проверяя все в своей паре скобок.

person Gliderman    schedule 07.05.2016

В DidMoveToView вам нужно позвонить

physicsWorld.contactDelegate = self

в противном случае метод Contact никогда не сработает.

Кроме того, для вашего круга игроков вы не даете ему физического тела, такого как

 playerCircle.physicsBody = SKPhysicsBody(...)

Затем измените свой метод DidBeginContact на это, чтобы вам не приходилось делать 2 проверки для каждого столкновения. Также используйте PhysicsCategory для их идентификации вместо имен.

func didBeginContact(contact: SKPhysicsContact) {

    var firstBody: SKPhysicsBody
    var secondBody: SKPhysicsBody

    if contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask {
        firstBody = contact.bodyA
        secondBody = contact.bodyB
    } else {
        firstBody = contact.bodyB
        secondBody = contact.bodyA
    }

    if (firstBody.categoryBitMask == PhysicsCategory.redBall) && (secondBody.categoryBitMask == PhysicsCategory.worldBorder) {

        // red ball hit world border, do something
    }

    if (firstBody.categoryBitMask == PhysicsCategory.blueBall) && (secondBody.categoryBitMask == PhysicsCategory.worldBorder) {

        // blue ball hit world border, do something
    }
}

Также в качестве подсказки: на некоторых физических телах вы принудительно разворачиваете с помощью !

self.physicsBody!.node?.name = "world"
enemyCircle.physicsBody!.mass = 0.05.

что может привести к сбою, если physicsBody не найдено.

Лучше всегда использовать ? всякий раз, когда вы можете, что вы уже делаете для большинства из них.

Также постарайтесь указать спрайту их позицию, прежде чем давать им physicsBody, потому что в противном случае вы можете получить неожиданные результаты.

 enemyCircle.position = CGPointMake(self.frame.size.width / 3, self.frame.size.height / 2)
 enemyCircle.physicsBody = SKPhysicsBody(circleOfRadius: 50)
 enemyCircle.physicsBody.categoryBitMask = ...
 ...

Надеюсь это поможет

person crashoverride777    schedule 08.05.2016