didBeginContact 未被调用 Swift

didBeginContact not being called Swift

我正在开发一个应用程序,当中心球的颜色与飞向中心球颜色的较小球相匹配时,玩家得分。 因此,为了使其正常工作,我需要在 "enemy" 和 "mainBall" 发生碰撞时调用 didBeginContact 函数。唯一在移动的是敌人的球,因为它飞向静止的主球 我相信我已经正确设置了位掩码,但是没有调用 didBeginContact 函数。 有人可以帮忙吗?

这是我的代码

struct bitMasks{
static let mainBallMask:UInt32 = 0x1 << 0
static let enemyBall:UInt32 = 0x1 << 1
}
class GameScene: SKScene,SKPhysicsContactDelegate {

var mainBall = SKSpriteNode()
var ballSetToMainColor = true
var enemyTimer = Timer()
var hits = 0

override func didMove(to view: SKView) {
    self.physicsWorld.contactDelegate = self
    mainBall = childNode(withName: "centralBall") as! SKSpriteNode
    mainBall.zPosition = 1.0
    mainBall.physicsBody = SKPhysicsBody(circleOfRadius: mainBall.size.width/2)

    mainBall.physicsBody?.categoryBitMask = bitMasks.mainBallMask
    mainBall.physicsBody?.collisionBitMask = bitMasks.enemyBall
    mainBall.physicsBody?.contactTestBitMask = bitMasks.enemyBall

    mainBall.physicsBody?.isDynamic = false
    mainBall.physicsBody?.affectedByGravity = false
    enemyTimer = Timer.scheduledTimer(timeInterval: 1.5, target: self, selector: #selector(enemies), userInfo: nil, repeats: true)
}


override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    touchesCheckForChangedBall(touches: touches)
}

func didBegin(_ contact: SKPhysicsContact) {
    let firstBody = contact.bodyA.node as! SKSpriteNode
    let secondBody = contact.bodyB.node as! SKSpriteNode
    if firstBody.name == "enemy" && secondBody.name == "centralBall"{
        collisionMain(enemy: firstBody)
    }else if firstBody.name == "centralBall" && secondBody.name == "enemy"{
        collisionMain(enemy: secondBody)
    }
}

func collisionMain(enemy: SKSpriteNode){
    hits += 1
    enemy.removeAllActions()
    enemy.removeFromParent()
    print(hits)

}

func touchesCheckForChangedBall(touches: Set<UITouch>){
    for t in touches {
        let location = t.location(in: self)
        let nodes = self.nodes(at: location)
        if nodes.isEmpty == false {
            if let name = nodes[0].name{
                if name == "centralBall"{
                    changeMainBallColor()
                }
            }
        }
    }
}

func changeMainBallColor(){
    ballSetToMainColor = !ballSetToMainColor
    if ballSetToMainColor == true{
        mainBall.texture = SKTexture(imageNamed: "ball-mainColor")
    }else{
        mainBall.texture = SKTexture(imageNamed: "ball-secondaryColor")
    }
}

override func update(_ currentTime: TimeInterval) {
    // Called before each frame is rendered
}

func getRandomImageColor()->String{
    let randVal = arc4random_uniform(2)
    if randVal == 0{
       return "ball-secondaryColor"
    }else{
        return "ball-mainColor"
    }
}

func enemies(){
    let color = getRandomImageColor()
    let enemy = SKSpriteNode(imageNamed: color)
    enemy.size = CGSize(width: 30, height: 30)
    enemy.physicsBody = SKPhysicsBody(circleOfRadius: enemy.size.width/2)
    enemy.physicsBody?.categoryBitMask = bitMasks.enemyBall
    enemy.physicsBody?.collisionBitMask = bitMasks.mainBallMask
    enemy.physicsBody?.contactTestBitMask = bitMasks.mainBallMask
    enemy.name = "enemyBall"
    enemy.physicsBody?.isDynamic = true
    enemy.physicsBody?.affectedByGravity = false
    let randomPositionNumber = arc4random() % 3
    switch randomPositionNumber{
    case 0:
        enemy.position.x = 0
        let posY = arc4random_uniform(UInt32(frame.size.height))
        enemy.position.y = CGFloat(posY)
        self.addChild(enemy)
        break
    case 1:
        enemy.position.y = frame.size.height
        let posX = arc4random_uniform(UInt32(frame.size.width))
        enemy.position.x = CGFloat(posX)
        self.addChild(enemy)
        break
    case 2:
        enemy.position.x = frame.size.width
        let posY = arc4random_uniform(UInt32(frame.size.height))
        enemy.position.y = CGFloat(posY)
        self.addChild(enemy)
        break
    default:
        break
    }
    enemy.run(SKAction.move(to: mainBall.position, duration: 3))
}
}

如上所述,您似乎拼错了节点名称。您在碰撞方法中寻找 "enemy",但将您的敌人命名为 "enemyBall"。这就是为什么我们应该始终创建常量来避免这种情况,例如

let enemyName = "Enemy"

然后像这样使用它

enemy.name = enemyName

您也可以尝试像这样编写您的碰撞方法,这样应该会稍微好读一些,而且每次碰撞只需要 1 个 if 语句。同样,这样您就不需要节点名称来比较主体。

func didBegin(_ contact: SKPhysicsContact) {

    let firstBody: SKPhysicsBody
    let secondBody: SKPhysicsBody

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

    // Main ball with enemy or enemy with main ball
    if (firstBody.categoryBitMask == bitMasks.mainBall) && (secondBody.categoryBitMask == bitMasks.enemy) {
        // do something
    }
}

我也会尝试遵循 swift 指南,类,枚举和结构应该以大写字母开头。

希望对您有所帮助

问题是他将他的敌人命名为 "enemyBall",但在他的 didBeginContact 中查找 "enemy" 这个词。

这就是为什么使用字符串比较不是一个好主意(而且它比其他比较慢)

我建议首先检查 categoryBitmask,然后是名称或 class,具体取决于您需要的检查的具体程度。