0

任何帮助将不胜感激。我对此比较陌生,只是觉得我开始了解编码。

我的问题-----

我很难尝试使用 SpriteKit 教程解决问题,我一直在增强该教程作为磨练和提高新手技能的一种方式。

当我的播放器“坠毁”在地面上时,我遇到了多次接触。

不止一个生命被移除,这导致我的游戏生成“尝试添加一个已经有父节点的 SKNode:”错误,将玩家添加回场景。我在代码中能想到的任何地方都尝试过 player.removeFromParent。

只要我在空中“撞”上“敌人”,游戏就完美无缺。一旦玩家接触到地面,一切就结束了。如果我在与地面接触时“杀死”玩家,没有问题,但我希望游戏继续,只要玩家仍然有生命,无论是接触地面还是与敌人接触。

我真的相信如果可以解决多接触问题,这个问题就会得到解决。

class GameScene: SKScene, SKPhysicsContactDelegate {

// Set up the Texure Atlases
var images = SKSpriteNode()
var textureAtlas = SKTextureAtlas()
var textureArray = [SKTexture]()

var touchingScreen = false

var obstacle = SKSpriteNode()


// Generates a Random number between -350 and 350 (the center of the axis being 0)
let rand = GKRandomDistribution(lowestValue: -350, highestValue: 350)

var timer: Timer?


// This method is called when the Game Launches
override func didMove(to view: SKView) {

    // Adds a pixel perfect physicsBody to the player
    player.physicsBody = SKPhysicsBody(texture: player.texture!, size: player.texture!.size())
    player.physicsBody?.categoryBitMask = 1
    player.position = CGPoint(x: -400, y: 275)

    // Disables the affects of a collisions (+pushing, rotation etc.) on the player when a collision with another SKSpriteNode occurs
    player.physicsBody?.allowsRotation = false
    player.physicsBody?.collisionBitMask = 0

    addChild(player)

    physicsWorld.gravity = CGVector(dx: 0, dy: -2)
    physicsWorld.contactDelegate = self

    timer = Timer.scheduledTimer(timeInterval: 1.5, target: self, selector: #selector(createEnemy), userInfo: nil, repeats: true)
}

// This method is called when the User touches the Screen
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    touchingScreen = true
}

// This method is called when the User stops touching the Screen
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
    touchingScreen = false
}

// This method is called before each frame is rendered
override func update(_ currentTime: TimeInterval) {

    // Constrains the player to the scene area
    if player.position.y > 275 {
        player.position.y = 275
    }

    // Moves the player up when the screen is being touched
    if touchingScreen {
        player.physicsBody?.velocity = CGVector(dx: 0, dy: 200
        )
    }
}

func didBegin(_ contact: SKPhysicsContact) {
    // Exits the method if either node is nil (doesn't exist)
    guard let nodeA = contact.bodyA.node else { return }
    guard let nodeB = contact.bodyB.node else { return }

    // Check to see if either node is player and, if so, call the playerHit method and pass in the other node
    if nodeA == player {
        playerHit(nodeB)

    } else if nodeB == player {
        playerHit(nodeA)
    }
}

func createEnemy() {

    // Check for Bonus Creation
    checkForBonusCreation()

    // Choose a Random Enemy
    let pickEnemy = Int(arc4random_uniform(3))

    switch pickEnemy {

    case 0:
        obstacle = SKSpriteNode(imageNamed: "enemy-balloon")
        animateBalloon()

    case 1:
        obstacle = SKSpriteNode(imageNamed: "enemy-bird")
        animateBird()

    case 2:
        obstacle = SKSpriteNode(imageNamed: "enemy-plane")
        animatePlane()

    default:
        return
    }

    // Positions the enemy
    obstacle.zPosition = -2
    obstacle.position.x = 768
    obstacle.size = (CGSize(width: obstacle.size.width * 0.7, height: obstacle.size.width * 0.7))

    // Prevents the obstacle from being spawned too low on the scene
    if obstacle.position.y < -150 {
        obstacle.position.y = -150
    }

    addChild(obstacle)

    // Adds pixel perfect collision detection to the enemies
    obstacle.physicsBody = SKPhysicsBody(texture: obstacle.texture!, size: obstacle.texture!.size())

    // Then we set isDynamic to false so grivty will not affect the obstacles
    obstacle.physicsBody?.isDynamic = false

    // Assigns 1 to it's contactTestBitMask so that it know to detect a collision with the player
    obstacle.physicsBody?.contactTestBitMask = 1

    // Names the obstacle so we can track collisions properly
    obstacle.name = "enemy"

    // Spawn an enemy at a random y-axis
    obstacle.position.y = CGFloat(rand.nextInt())

    // Moves the obstacles across to and off the left hand side of the screen over 9 seconds athen removes thier nodes so they don't chew up memory
    let move = SKAction.moveTo(x: -768, duration: 9)
    let remove = SKAction.removeFromParent()
    let action = SKAction.sequence([move, remove])
    obstacle.run(action)
}

func playerHit(_ node: SKNode) {

    if node.name == "enemy" {

        player.removeFromParent()
        node.removeFromParent()
        lives -= 1
        balloonPop()
        showLivesRemaining()

    } else if node.name == "ground" {

        player.removeFromParent()
        lives -= 1
        balloonPop()
        showLivesRemaining()
    }
}

func balloonPop() {

    player.removeFromParent()  
}

func showLivesRemaining() {

    if lives >= 3 {
        lives = 3

    } else if lives <= 0 {
        lives = 0
        player.removeFromParent()
    }
}

// Jump to the restart or quit scene
func restartGame() {

    player.removeFromParent()

    let wait = SKAction.wait(forDuration: 2.0)

    let showPlayer = SKAction.run {
        player.position = CGPoint(x: -400, y: 275)
        self.addChild(player)
    }

    let sequence = SKAction.sequence([wait, showPlayer])

    run(sequence)
}

// Displays GAME OVER and takes the player to the "Restart or Quit" choice scene
func endGame() {

    player.removeFromParent()

    let gameOver = SKSpriteNode(imageNamed: "game-over")
    gameOver.zPosition = 15
    addChild(gameOver)

    // Waits 2 seconds and fade into the Restart Scene
    DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {

        if let scene = RestartScene(fileNamed: "RestartScene") {
            scene.scaleMode = .aspectFill
            self.view?.presentScene(scene, transition: SKTransition.crossFade(withDuration: 1.5))
        }
    }
}

}

4

1 回答 1

0

许多游戏所做的是在玩家被击中后给玩家一个缓冲期,让玩家闪现或将玩家变成红色几秒钟。在此期间,玩家不容易受到更多的打击,并让玩家有机会移动到安全的地方。

func didBegin(_ contact: SKPhysicsContact) {

    let contactAName = contact.bodyA.node?.name
    let contactBName = contact.bodyB.node?.name

    //don't detect contact if the player is hit
    if ((contactAName == "player") || (contactBName == "player")) && !player.isHit {

         if (contactAName == "ground") || (contactBName == "ground") {
             print("groundcontact with player")

             player.isHit = true
             //good idea to flash player or pulse player to let user know player is hit
             self.run(.wait(forDuration: 3.0)) {
                 //wait for 3 seconds and make the player hittable again
                 self.player.isHit = false
             }
             return
        }
    }
}

编辑

接触检测代码每秒最多触发 60 次。当您的玩家击中敌人时,您会移除该敌人,从而无法与敌人进行更多接触。然而,当玩家撞到地面时,地面并没有被移除,因此玩家不断失去生命。在玩家撞到地面后,尝试将玩家撞到离地面 100px 的地方,看看这是否会阻止多接触问题。

于 2018-03-19T16:06:25.993 回答