在完成了上篇 “飛翔的小鳥”簡易款 之后,就試著在網上找了一套UI做了一套升級款“游曳的小藍”。
先關閉音效,看一下運行效果圖吧,哈哈~
在原來的基礎簡易修改后,大概增加了三個功能點~
1.音效播放
對于音效的播放,主要采用兩種方式:AVAudioPlayer 和 SKAction.playSoundFileNamed。
首先我們新建一個Swift類用于AVAudioPlayer 播放音效的封裝,再類中導入 AVFoundation 庫 ,在聲明的MusicPlayer Class 類中實現音效的初始化、播放和停止。
enum MusicPlayerError : Error {
case resourceNotFound
}
class MusicPlayer {
/// 單例
fileprivate var player: AVAudioPlayer? = nil
/// 初始化
init(fileName:String,type:String) throws {
if let resource = Bundle.main.path(forResource: fileName, ofType: type) {
let url = URL(fileURLWithPath: resource)
player = try AVAudioPlayer(contentsOf: url)
player?.numberOfLoops = -1
player?.prepareToPlay()
}else{
throw MusicPlayerError.resourceNotFound
}
}
/// 播放
func play(){
player?.play()
}
/// 停止
func stop() {
player?.stop()
}
}
然后,在 GameViewController 類中,添加上背景音效:
do {
player = try MusicPlayer(fileName: "Pamgaea", type: "mp3")
player?.play()
} catch _ {
print("Error Play")
}
在 GameScene 類中,小鳥受到向上的力時、通過管道時和碰撞時,利用SkAction 分別播放不同的音效
self.run(SKAction.playSoundFileNamed("xxx.mp3", waitForCompletion: false))
2.計分板
計分板主要功能點:最新得分、歷史最高分、確認鍵、動畫展示
首先我們要利用靜態化存儲,來儲存和獲得分數,寫定兩個方法如下
func setBestScore(score:Int) {
UserDefaults.standard.set(score, forKey: "bestScore")
UserDefaults.standard.synchronize()
}
func bestScore()->Int{
return UserDefaults.standard.integer(forKey: "bestScore")
}
接著, 我們聲明一個SKNode變量scoreCards,用來存儲計分板視圖
/// 儲存計分板視圖
var scoreCards:SKNode!
然后,設置計分板UI圖:
func setupScoreCard() {
if score > bestScore() {
setBestScore(score: score)
}
let whiteNode = SKSpriteNode(color: SKColor.white, size: size)
whiteNode.alpha = 0
whiteNode.zPosition = 100
whiteNode.position = CGPoint(x: size.width/2, y: size.height/2)
scoreCards.addChild(whiteNode)
// 1 得分面板背景
let scorecard = SKSpriteNode(imageNamed: "scoreCard")
scorecard.position = CGPoint(x: size.width * 0.5, y: size.height * 0.5)
scorecard.name = "scorecard"
scorecard.zPosition = 101
scoreCards.addChild(scorecard)
// 2 本次得分
let lastScore = SKLabelNode(fontNamed: "MarkerFelt-Wide")
lastScore.fontColor = SKColor.white
lastScore.position = CGPoint(x: scorecard.size.width * 0.30, y:0)
lastScore.text = String(score)
lastScore.zPosition = 102
scorecard.addChild(lastScore)
// 3 最好成績
let bestScoreLabel = SKLabelNode(fontNamed: "MarkerFelt-Wide")
bestScoreLabel.fontColor = SKColor.white
bestScoreLabel.position = CGPoint(x: scorecard.size.width * 0.30, y: -scorecard.size.height * 0.32)
bestScoreLabel.zPosition = 102
bestScoreLabel.text = String(bestScore())
scorecard.addChild(bestScoreLabel)
// 4 游戲結束
let gameOver = SKSpriteNode(imageNamed: "game_over")
gameOver.position = CGPoint(x: size.width/2, y: size.height/2 + scorecard.size.height/2 + 50 + gameOver.size.height/2)
gameOver.zPosition = 101
scoreCards.addChild(gameOver)
// 5 ok按鈕背景以及ok標簽
let okButton = SKSpriteNode(imageNamed: "confirm")
okButton.position = CGPoint(x: size.width * 0.5, y: size.height/2 - scorecard.size.height/2 - 50 - okButton.size.height/2)
okButton.zPosition = 101
// 作用于按鈕事件
okButton.name = "ok"
scoreCards.addChild(okButton)
}
在已結束狀態,調用 setupScoreCard 方法,運行效果圖如下:
最后動畫展示,在 setupScoreCard()最下面,添加以下動作:
//添加一個常量 用于定義動畫時間
let animDelay = 0.3
let whiteNodeIn = SKAction.sequence([SKAction.wait(forDuration: 1.0),SKAction.fadeAlpha(to: 0.3, duration: 0.3)])
whiteNode.run(whiteNodeIn)
gameOver.setScale(0)
let group = SKAction.scale(to: 1.0, duration: animDelay)
group.timingMode = .linear
gameOver.run(SKAction.sequence([SKAction.wait(forDuration: 1),group]))
scorecard.position = CGPoint(x: size.width * 0.5, y: -scorecard.size.height/2)
let moveTo = SKAction.moveTo(y: size.height/2, duration: animDelay)
moveTo.timingMode = .linear
scorecard.run(SKAction.sequence([SKAction.wait(forDuration: 1),moveTo]))
okButton.position = CGPoint(x: size.width * 0.5, y: -scorecard.size.height - 50 - okButton.size.height/2)
let moveTo2 = SKAction.moveTo(y: size.height/2 - scorecard.size.height/2 - 50 - okButton.size.height/2, duration: animDelay)
moveTo2.timingMode = .linear
okButton.run(SKAction.sequence([SKAction.wait(forDuration: 1),moveTo2]))
在初始化狀態調用移除計分板方法:
/// 移除計分板
func removeScoreCard() {
scoreCards.removeAllChildren()
}
根據計分板的確認鍵,仿寫一個按鈕。在點擊屏幕的時候,我們判斷點擊的位置是否是確認鍵的位置。
因為上面我們UI視圖中,已經給“ okButton”的“ name”屬性賦值,所以我們在點擊屏幕時,在當前已經是已結束狀態下,書寫以下代碼:
/// 防按鈕事件
for touch in touches{
let location = touch.location(in: self)
for node in nodes(at:location){
if node.name == "ok"{
idleStatus()
}
}
}
3.引導提示圖
類比計分板,先聲明一個SKNode變量tutorials,用來存儲計分板視圖,然后書寫創建計分板和移除計分板方法:
/// 創建引導提示圖
func setupTutorial() {
let tutorial = SKSpriteNode(imageNamed: "taptap")
tutorial.position = CGPoint(x: size.width * 0.5, y: size.height * 0.5)
tutorial.name = "Tutorial"
tutorial.zPosition = 100
tutorials.addChild(tutorial)
let ready = SKSpriteNode(imageNamed: "get_ready")
ready.position = CGPoint(x: size.width * 0.5, y: size.height * 0.5 + 100)
ready.name = "Tutorial"
ready.zPosition = 100
tutorials.addChild(ready)
}
/// 移除引導提示圖
func removeTutorial() {
tutorials.removeAllChildren()
}
在初始化狀態,創建引導提示圖;
在運行中狀態,移除引導提示圖。
效果如下:
OK,現在“飛翔的小鳥”升級款->“游曳的小藍”,就已經做好了,可以好好地玩耍了~