快速精灵套件游戏当我向敌人射击有时子弹穿过敌人时,我该如何解决这个问题呢?

时间:2016-06-28 10:25:12

标签: swift sprite-kit skphysicsbody

我正在使用精灵工具包(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()


    }

4 个答案:

答案 0 :(得分:1)

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

    bullet.physicsBody!.usesPreciseCollisionDetection = true

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

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

答案 1 :(得分:0)

不要将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会起作用,因为我看不到它的作用,但这应该删除节点。

答案 2 :(得分:0)

我认为你的问题在子弹代码中:

    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,如果屏幕显示则删除子弹

答案 3 :(得分:0)

我认为编写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)
   }