swift sprite kit game when I shoot on a enemy some

2019-04-02 19:30发布

I'm making a game in sprite kit (2D).

I have this code:

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

and I have a meteor image that you need to destroy but sometimes when I shoot on my device to the meteor the bullet goes through the meteor is this a bug or did I do something wrong? and How can I fix this issue?

thanks for reading my problem, I hope someone can help me! if you don't understand my question plz comment what you don't understand.

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条回答
我欲成王,谁敢阻挡
2楼-- · 2019-04-02 19:59

Instead of setting your collisionBitMasks to zero, try setting them to this:

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

And try changing your the beginning of your didBeginContact method to this:

    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()
    }

I can't say the spawnExplosion will work since I can't see what it does, but this should remove the nodes.

查看更多
倾城 Initia
3楼-- · 2019-04-02 20:08

I think a neater way to code didBeginContact is as follows:

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")
}

I changed your code to create one explosion wwhere the 2 bodies touch; if you want 2 explosions, each centered on the nodes that touch, use:

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

or:

for node in [contact.bodyA.node, contact.bodyB.node] {
   spawnExplosion(node.position)
   }
查看更多
Animai°情兽
4楼-- · 2019-04-02 20:09

I think your problem is inside the bullet code:

    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)

Try to replace with bullet.physicsBody?.applyImpulse(CGVectorMake( 0, 20)) instead of SKAction.moveToY and remove bullet if go out the screen

查看更多
该账号已被封号
5楼-- · 2019-04-02 20:13

SpriteKit doesn't perform precise collision detection because it aims to achieve faster performance. You can make the physicsBody's property usesPreciseCollisionDetection to true, like this:

    bullet.physicsBody!.usesPreciseCollisionDetection = true

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

I don't know if it works, please let me know.

查看更多
登录 后发表回答