ios - 将 Game over 实现到 swift 游戏中

标签 ios swift sprite-kit

我已经在 Xcode 中创建了一个游戏,但是我想在玩家失败时切换到游戏结束屏幕,此时 main.storyboard 文件是空白的。我找到了这个解决方案 Using a view controller for a game over scene

但是,我不确定如何将其实现到我的代码中。我在下面附上了我的代码,如果有人可以帮助我,我将不胜感激。

import SpriteKit
import GameplayKit

class GameScene: SKScene, SKPhysicsContactDelegate {

var bird = SKSpriteNode()

var bg = SKSpriteNode()

var scoreLabel = SKLabelNode()

var score = 0

var gameOverLabel = SKLabelNode()

var timer = Timer()

enum ColliderType: UInt32 {

    case Bird = 1
    case Object = 2
    case Gap = 4

}

var gameOver = false

func makePipes() {

    let movePipes = SKAction.move(by: CGVector(dx: -2 * self.frame.width, dy: 0), duration: TimeInterval(self.frame.width / 100))

    let gapHeight = bird.size.height * 4

    let movementAmount = arc4random() % UInt32(self.frame.height / 2)

    let pipeOffset = CGFloat(movementAmount) - self.frame.height / 4

    let pipeTexture = SKTexture(imageNamed: "pipe1.png")

    let pipe1 = SKSpriteNode(texture: pipeTexture)

    pipe1.position = CGPoint(x: self.frame.midX + self.frame.width, y: self.frame.midY + pipeTexture.size().height / 2 + gapHeight / 2 + pipeOffset)

    pipe1.run(movePipes)

    pipe1.physicsBody = SKPhysicsBody(rectangleOf: pipeTexture.size())
    pipe1.physicsBody!.isDynamic = false

    pipe1.physicsBody!.contactTestBitMask = ColliderType.Object.rawValue
    pipe1.physicsBody!.categoryBitMask = ColliderType.Object.rawValue
    pipe1.physicsBody!.collisionBitMask = ColliderType.Object.rawValue

    pipe1.zPosition = -1

    self.addChild(pipe1)

    let pipe2Texture = SKTexture(imageNamed: "pipe2.png")

    let pipe2 = SKSpriteNode(texture: pipe2Texture)

    pipe2.position = CGPoint(x: self.frame.midX + self.frame.width, y: self.frame.midY - pipe2Texture.size().height / 2 - gapHeight / 2 + pipeOffset)

    pipe2.run(movePipes)

    pipe2.physicsBody = SKPhysicsBody(rectangleOf: pipeTexture.size())
    pipe2.physicsBody!.isDynamic = false

    pipe2.physicsBody!.contactTestBitMask = ColliderType.Object.rawValue
    pipe2.physicsBody!.categoryBitMask = ColliderType.Object.rawValue
    pipe2.physicsBody!.collisionBitMask = ColliderType.Object.rawValue

    pipe2.zPosition = -1

    self.addChild(pipe2)

    let gap = SKNode()

    gap.position = CGPoint(x: self.frame.midX + self.frame.width, y: self.frame.midY + pipeOffset)

    gap.physicsBody = SKPhysicsBody(rectangleOf: CGSize(width: pipeTexture.size().width, height: gapHeight))

    gap.physicsBody!.isDynamic = false

    gap.run(movePipes)

    gap.physicsBody!.contactTestBitMask = ColliderType.Bird.rawValue
    gap.physicsBody!.categoryBitMask = ColliderType.Gap.rawValue
    gap.physicsBody!.collisionBitMask = ColliderType.Gap.rawValue

    self.addChild(gap)

}

func didBegin(_ contact: SKPhysicsContact) {

    if gameOver == false {

    if contact.bodyA.categoryBitMask == ColliderType.Gap.rawValue || contact.bodyB.categoryBitMask == ColliderType.Gap.rawValue {

        score += 1

        scoreLabel.text = String(score)

    } else {

    self.speed = 0

    gameOver = true

    timer.invalidate()

    gameOverLabel.fontName = "Helvetica"

    gameOverLabel.fontSize = 30

    gameOverLabel.text = "Game Over! Tap to play again."

    gameOverLabel.position = CGPoint(x: self.frame.midX, y: self.frame.midY)

    self.addChild(gameOverLabel)

        }
    }

}


override func didMove(to view: SKView) {

    self.physicsWorld.contactDelegate = self

    setupGame()


}

func setupGame() {

    timer = Timer.scheduledTimer(timeInterval: 3, target: self, selector: #selector(self.makePipes), userInfo: nil, repeats: true)

    let bgTexture = SKTexture(imageNamed: "bg.png")

    let moveBGAnimation = SKAction.move(by: CGVector(dx: -bgTexture.size().width, dy: 0), duration: 7)
    let shiftBGAnimation = SKAction.move(by: CGVector(dx: bgTexture.size().width, dy: 0), duration: 0)
    let moveBGForever = SKAction.repeatForever(SKAction.sequence([moveBGAnimation, shiftBGAnimation]))

    var i: CGFloat = 0

    while i < 3 {

        bg = SKSpriteNode(texture: bgTexture)

        bg.position = CGPoint(x: bgTexture.size().width * i, y: self.frame.midY)

        bg.size.height = self.frame.height

        bg.run(moveBGForever)

        bg.zPosition = -2

        self.addChild(bg)

        i += 1

    }


    let birdTexture = SKTexture(imageNamed: "flappy1.png")
    let birdTexture2 = SKTexture(imageNamed: "flappy2.png")

    let animation = SKAction.animate(with: [birdTexture, birdTexture2], timePerFrame: 0.1)
    let makeBirdFlap = SKAction.repeatForever(animation)

    bird = SKSpriteNode(texture: birdTexture)

    bird.position = CGPoint(x: self.frame.midX, y: self.frame.midY)

    bird.run(makeBirdFlap)

    bird.physicsBody = SKPhysicsBody(circleOfRadius: birdTexture.size().height / 2)

    bird.physicsBody!.isDynamic = false

    bird.physicsBody!.contactTestBitMask = ColliderType.Object.rawValue
    bird.physicsBody!.categoryBitMask = ColliderType.Bird.rawValue
    bird.physicsBody!.collisionBitMask = ColliderType.Bird.rawValue

    self.addChild(bird)

    let ground = SKNode()

    ground.position = CGPoint(x: self.frame.midX, y: -self.frame.height / 2)

    ground.physicsBody = SKPhysicsBody(rectangleOf: CGSize(width: self.frame.width, height: 1))

    ground.physicsBody!.isDynamic = false

    ground.physicsBody!.contactTestBitMask = ColliderType.Object.rawValue
    ground.physicsBody!.categoryBitMask = ColliderType.Object.rawValue
    ground.physicsBody!.collisionBitMask = ColliderType.Object.rawValue


    self.addChild(ground)

    scoreLabel.fontName = "Helvetica"

    scoreLabel.fontSize = 60

    scoreLabel.text = "0"

    scoreLabel.position = CGPoint(x: self.frame.midX, y: self.frame.height / 2 - 220)

    self.addChild(scoreLabel)





}

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

    if gameOver == false {


     bird.physicsBody!.isDynamic = true

     bird.physicsBody!.velocity = CGVector(dx: 0, dy: 0)

     bird.physicsBody!.applyImpulse(CGVector(dx: 0, dy: 80))

    } else {

        gameOver = false

        score = 0

        self.speed = 1

        self.removeAllChildren()

        setupGame()

    }

    }


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



}

最佳答案

您应该设置一个 GameOverScene 并在需要时显示该场景。 RayWenderlich 站点有很多教程可以向您展示如何执行此操作,这里可能解释得太多了

这是 Apple Game Frameworks Section 的链接

This page向您展示如何实现关卡完整叠加)

但基本上您只需创建一个新场景,向其中添加您需要的任何 UI 元素,然后您可以从 View Controller 调用 PresentScene,就像这样

view.presentScene(scene)

示例代码:

class GameScene: SKScene {

    var notificationLabel = SKLabelNode(text: "Tap the screen to win")
    override func didMove(to view: SKView) {

        self.backgroundColor = SKColor.black

        addChild(notificationLabel)
        notificationLabel.fontSize = 32.0
        notificationLabel.color = SKColor.white
        notificationLabel.fontName = "Thonburi-Bold"
        notificationLabel.position = CGPoint(x: size.width / 2, y: size.height / 2)
    }

    func displayGameOver() {

        let gameOverScene = GameOverScene(size: size)
        gameOverScene.scaleMode = scaleMode

        let reveal = SKTransition.flipHorizontal(withDuration: 0.5)
        view?.presentScene(gameOverScene, transition: reveal)
    }

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

        displayGameOver()
    }
}

class GameOverScene: SKScene {

    var notificationLabel = SKLabelNode(text: "You Won")

    override init(size: CGSize) {
        super.init(size: size)

        self.backgroundColor = SKColor.darkGray

        addChild(notificationLabel)
        notificationLabel.fontSize = 32.0
        notificationLabel.color = SKColor.white
        notificationLabel.fontName = "Thonburi-Bold"
        notificationLabel.position = CGPoint(x: size.width / 2, y: size.height / 2)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

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

        let gameScene = GameScene(size: size)
        gameScene.scaleMode = scaleMode

        let reveal = SKTransition.flipHorizontal(withDuration: 0.5)
        view?.presentScene(gameScene, transition: reveal)
    }
}

在任一场景中点击屏幕将呈现另一个场景。您还应该能够通过 View Controller 来管理它并做几乎相同的事情,但我还没有这样做,我自己对 SpriteKit 还是很陌生。

希望对你有帮助

关于ios - 将 Game over 实现到 swift 游戏中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40651727/

相关文章:

ios - Swift:删除所有数组元素

swift - 如何在文本标签上显示当前时间?

swift - 变量在其自己的初始值内使用,而变量在 init 之后的闭包内使用

ios - 如何在自动布局中强制更新约束

swift - 当两个 Sprite 碰撞时没有减速? Swift/Spritekit

ios - UITableView 中的单元格重用

iphone - 如何从 NSData 对象中获取值

swift - Sprite 节点不检测触摸?

ios - SKNode "origin"是什么?

ios - Segues 之后弹出或删除模态框