【问题标题】:swift sprite kit game when I shoot on a enemy sometimes the bullet goes trough the enemy, how can I fix this?swift spritekit 游戏当我向敌人射击时有时子弹会穿过敌人,我该如何解决这个问题?
【发布时间】:2016-06-28 10:25:11
【问题描述】:

我正在使用 sprite kit (2D) 制作游戏。

我有这个代码:

meteor.physicsBody = SKPhysicsBody(rectangleOfSize: enemy.size)

我有一个流星图像,你需要销毁它,但有时当我在我的设备上向流星射击时,子弹会穿过流星 这是一个错误还是我做错了什么? 和 我该如何解决这个问题?

感谢您阅读我的问题,我希望有人可以帮助我! 如果你不明白我的问题,请评论你不明白的地方。

func fireBullet() {

    let bullet = SKSpriteNode(imageNamed: "bullet")
    bullet.name = "Bullet"
    bullet.setScale(2.9)
    bullet.position = player.position
    bullet.zPosition = 1
    bullet.physicsBody = SKPhysicsBody(rectangleOfSize: bullet.size)
    bullet.physicsBody!.affectedByGravity = false
    bullet.physicsBody!.categoryBitMask = PhysicsCategories.Bullet
    bullet.physicsBody!.collisionBitMask = PhysicsCategories.None
    bullet.physicsBody!.contactTestBitMask = PhysicsCategories.Meteor
    self.addChild(bullet)

    let moveBullet = SKAction.moveToY(self.size.height + bullet.size.height, duration: 1)
    let deleteBullet = SKAction.removeFromParent()
    let bulletSequence = SKAction.sequence([bulletSound, moveBullet, deleteBullet])
    bullet.runAction(bulletSequence)        
}

func spawnMeteor(){

    let randomXStart = random(min: CGRectGetMinX(gameArea), max: CGRectGetMaxX(gameArea))
    let randomXEnd = random(min: CGRectGetMinX(gameArea), max: CGRectGetMaxX(gameArea))

    let startPoint = CGPoint(x: randomXStart, y: self.size.height * 1.2)
    let endPoint = CGPoint(x: randomXEnd, y: -self.size.height * 0.2)

    let Meteor = SKSpriteNode(imageNamed: "Meteor\(arc4random_uniform(2))")
    Meteor.name = "Meteor"
    Meteor.setScale(0.2)
    Meteor.position = startPoint
    Meteor.zPosition = 2
    Meteor.physicsBody = SKPhysicsBody(rectangleOfSize: meteor.size)
    Meteor.physicsBody!.affectedByGravity = false
    Meteor.physicsBody!.categoryBitMask = PhysicsCategories.Meteor
    Meteor.physicsBody!.collisionBitMask = PhysicsCategories.None
    Meteor.physicsBody!.contactTestBitMask = PhysicsCategories.Player | PhysicsCategories.Bullet

    self.addChild(Meteor)

    let moveMeteor = SKAction.moveTo(endPoint, duration: 2)
    let deleteMeteor = SKAction.removeFromParent()
    let loseALifeAction = SKAction.runBlock(loseALife)
    let MeteorSequence = SKAction.sequence([moveMeteor, deleteMeteor, loseALifeAction])



    if currentGameState == gameState.inGame{
    Meteor.runAction(MeteorSequence)
    }

    let dx = endPoint.x - startPoint.x
    let dy = endPoint.y - startPoint.y
    let amountToRotate = atan2(dy, dx)
    enemy.zRotation = amountToRotate 
}


func didBeginContact(contact: SKPhysicsContact) {

    var body1 = SKPhysicsBody()
    var body2 = SKPhysicsBody()


    if contact.bodyA.collisionBitMask < contact.bodyB.categoryBitMask{
        body1 = contact.bodyA
        body2 = contact.bodyB
    }
    else{
        body1 = contact.bodyB
        body2 = contact.bodyA
    }

    if body1.categoryBitMask == PhysicsCategories.Player && body2.categoryBitMask == PhysicsCategories.Meteor{
        //if the player has hit the meteor

        if body1.node != nil {
        spawnExplosion(body1.node!.position)
        }



        if body2.node != nil {
        spawnExplosion(body2.node!.position)
        }


        body1.node?.removeFromParent()
        body2.node?.removeFromParent()


        runGameOver()


    }

    if body1.categoryBitMask == PhysicsCategories.Bullet && body2.categoryBitMask == PhysicsCategories.Meteor && body2.node?.position.y < self.size.height {
        //if the bullet has hit the meteor



        addScore()


        if body2.node != nil{
        spawnExplosion(body2.node!.position)
        spawnPlusScore(body2.node!.position)
        }


        body1.node?.removeFromParent()
        body2.node?.removeFromParent()


    }

【问题讨论】:

    标签: swift sprite-kit skphysicsbody


    【解决方案1】:

    SpriteKit 不执行精确的碰撞检测,因为它旨在实现更快的性能。您可以将physicsBody 的属性usesPreciseCollisionDetection 设为true,如下所示:

        bullet.physicsBody!.usesPreciseCollisionDetection = true
    

    https://developer.apple.com/reference/spritekit/skphysicsbody/1520014-usesprecisecollisiondetection

    我不知道它是否有效,请告诉我。

    【讨论】:

    • 我加了,但有时我还能射穿流星
    • 如果您有兴趣,我正面临一个类似的问题,有时我可以通过我在游戏中制作的绳索射击。我相信这是一个 iOS 9.x 错误,因为这只是最近才开始发生的。在我的情况下,设置精确的碰撞也没有帮助。
    【解决方案2】:

    不要将您的 collisionBitMasks 设置为零,而是尝试将它们设置为:

    bullet.physicsBody!.collisionBitMask = PhysicsCategories.Meteor
    Meteor.physicsBody!.collisionBitMask = PhysicsCategories.Bullet
    

    并尝试将您的 didBeginContact 方法的开头更改为:

        var body1 = contact.bodyA.node as! SKSpriteNode
        var body2 = contact.bodyB.node as! SKSpriteNode
    
     if (body1.categoryBitMask == PhysicsCategories.Player && body2.categoryBitMask == PhysicsCategories.Meteor) || (body2.categoryBitMask == PhysicsCategories.Player && body1.categoryBitMask == PhysicsCategories.Meteor) {
            //if the player has hit the meteor
            spawnExplosion(body1.position)
            spawnExplosion(body2.position)
    
            body1.removeFromParent()
            body2.removeFromParent()
    
            runGameOver()
        }
    

    我不能说 spawnExplosion 会起作用,因为我看不到它的作用,但这应该会删除节点。

    【讨论】:

    • 子弹不再穿过。但是现在如果我向敌人射击,子弹有时会反弹。 ://
    • 当他们击中时你想达到什么目的?你的问题只问了他们彼此之间的关系。
    • o 对不起,我忘了打电话。当流星被正确击中时,流星会爆炸并从场景中移除(子弹也被移除)。
    • didBeginContact 方法应该处理游戏中的碰撞。你会发布那个代码吗?
    【解决方案3】:

    我认为您的问题在项目符号代码中:

        let moveBullet = SKAction.moveToY(self.size.height + bullet.size.height, duration: 1)
        let deleteBullet = SKAction.removeFromParent()
        let bulletSequence = SKAction.sequence([bulletSound, moveBullet, deleteBullet])
        bullet.runAction(bulletSequence)
    

    尝试替换为bullet.physicsBody?.applyImpulse(CGVectorMake( 0, 20)) 而不是SKAction.moveToY 并在屏幕消失时删除项目符号

    【讨论】:

      【解决方案4】:

      我认为对 didBeginContact 进行编码的一种更简洁的方法如下:

      func didBeginContact(contact: SKPhysicsContact) {
      
         let contactMask = contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask
      
         switch contactMask
      
         case PhysicsCategories.Player | PhysicsCategories.Meteor :
      
            // The player and the meteor have contacted
      
            spawnExplosion(contact.contactPoint) //Create explosion where they touch
            contact.bodyA.node.removeFromParent()
            contact.bodyB.node.removeFromParent()
            runGameOver()
      
         case PhysicsCategories.Bullet| PhysicsCategories.Meteor :
      
            // The bullet and meteor have contacted
            // body2.node?.position.y < self.size.height // ?? Not sure what this is
      
            addScore()
            spawnExplosion(contact.contactPoint) //Create explosion where they touch
            contact.bodyA.node.removeFromParent()
            contact.bodyB.node.removeFromParent()
      
         default:
            print("Other contact detected")
      }
      

      我更改了您的代码以创建两个身体接触的爆炸;如果你想要 2 个爆炸,每个爆炸都以接触的节点为中心,请使用:

      spawnExplosion(contact.bodyA.node.position)
      spawnExplosion(contact.bodyB.node.position)
      

      或:

      for node in [contact.bodyA.node, contact.bodyB.node] {
         spawnExplosion(node.position)
         }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-08-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多