(三)宇宙大戰 Space Battle -- 場景SCENE切換、UserDefaults統計分數、Particle粒子效果

此《宇宙大戰 Space Battle》SpirteKit手機遊戲教程共分爲三系列:javascript

(一)宇宙大戰 Space Battle -- 新建場景Scene、精靈節點、Particle粒子及背景音樂
(二)宇宙大戰 Space Battle -- 無限循環背景Endless、SpriteKit物理碰撞、CoreMotion加速計
(三)宇宙大戰 Space Battle — 場景SCENE切換、UserDefaults統計分數、Particle粒子效果(你正在此處進行學習)php

1、如何進行各個場景之間的切換java

 
場景SCENE切換

如上圖所示,共分爲三個場景:
一、MainScene.sks -- 用戶打開APP時一開始看到的畫面,等待用戶點擊"Play"按鈕;
二、GameScene.sks -- 遊戲進行中的場景畫面,用於建立無限循環背景Endless、監測SpriteKit物理碰撞、應用CoreMotion加速計,判斷遊戲的業務邏輯;
三、LoseScene.sks -- 遊戲結束時的場景畫面,記錄當屆分數,記錄最高分並應用UserDefaults儲存分數在手機沙盒當中,點擊"Tap to play"按鈕回到GameScene遊戲場景畫面;node

 
目錄文件在工程項目中的Scenes文件夾中

咱們依據第一節所學到的知識,新建一個文件,在Scenes文件夾中,Mouse右建 -> New File -> 選擇 iOS -> SpriteKit Scene -> Next 命名一個新的場景爲 MainScene.sksgit

 
新建一個文件
 
SpriteKit Scene
 
分別拖動三個ColorSprite到MainScene.sks場景中
 
三個精靈Spirte節點的Zposition爲1,位於背景的上方

另新建一個文件,也是在Scenes文件夾中,Mouse右建 -> New File -> 選擇 iOS -> Swift File -> Next 命名爲 MainScene.swfit ,關聯 MainScene.sks的 Custom Class 爲 MainScene.swiftgithub

 
關聯 MainScene.sks的 Custom Class 爲 MainScene.swift

在Game ViewController設置開始場景爲 MainScene.sksswift

if let scene = MainScene(fileNamed: "MainScene") { scene.size = CGSize(width: 1536, height: 2048) scene.scaleMode = .aspectFill view.presentScene(scene) } 

設置好啓動場景後,咱們再來MainScene.swfit編寫代碼:api

在didMove(to view: SKView)裏,緩存

override func didMove(to view: SKView) { /// Play爲場景命名的節點名稱 play = childNode(withName: "Play") as! SKSpriteNode learnTemp = childNode(withName: "learnTemp") as! SKSpriteNode // 背景音樂 let bgMusic = SKAudioNode(fileNamed: "spaceBattle.mp3") bgMusic.autoplayLooped = true addChild(bgMusic) } 

接下來,咱們就要來判斷用戶的觸摸位置,是否是按到 Play 按鈕
在 override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) 函數裏:bash

/// 判斷用戶是否有點擊 guard let touch = touches.first else { return } let touchLocation = touch.location(in: self) /// 得到點擊的位置 if play.contains(touchLocation) { /// 表示觸摸點擊在play按鈕當中 } 

把切換進入GameScene.sks的代碼寫在 play.contains(){}函數裏

let reveal = SKTransition.doorsOpenVertical(withDuration: TimeInterval(0.5)) ///場景切換 let mainScene = GameScene(fileNamed: "GameScene") mainScene?.size = self.size mainScene?.scaleMode = .aspectFill self.view?.presentScene(mainScene!, transition: reveal) 

這樣子,咱們就完成了場景之間的切換了!

一樣,GameScene切換到LoseScene、LoseScene切換爲GameScene 也是應用 self.view?.presentScene的方法,具體代碼以下:

在外星人Alien撞擊到飛船,遊戲結束,GameScene切換到LoseScene:

// MARK: 外星人Alien撞擊到飛船,遊戲結束 func alienHitSpaceShip(nodeA:SKSpriteNode,nodeB:SKSpriteNode){ // 切換遊戲結束場景 let reveal = SKTransition.doorsOpenHorizontal(withDuration: TimeInterval(0.5)) let loseScene = LoseScene(fileNamed: "LoseScene") loseScene?.size = self.size loseScene?.scaleMode = .aspectFill self.view?.presentScene(loseScene!, transition: reveal) } 

2、應用UserDefaults儲存遊戲分數和最高分

咱們在GameScene.swift裏

private var currentScore:SKLabelNode! // 當前分數節點 private var cScore:Int = 0 /// Int 存當前分數 private var highScore:SKLabelNode! // 最高分數 private var hScore:Int = 0 /// Int 存最高分數 

在子彈擊中外星人時記錄分數
func bulletHitAlien(nodeA:SKSpriteNode,nodeB:SKSpriteNode){}

func bulletHitAlien(nodeA:SKSpriteNode,nodeB:SKSpriteNode){ // 分數統計 cScore += 1 currentScore.text = "SCORE:\(cScore)" // 保存當前分數 UserDefaults.standard.set(cScore, forKey: "CURRENTSCORE") if cScore > hScore { hScore = cScore highScore.text = "High:\(hScore)" // 保存最高分數 UserDefaults.standard.set(cScore, forKey: "HIGHSCORE") } } 

咱們應用UserDefaults.standard.set方法,分別儲存當前分數和最高分數對應的鍵值forKey:CURRENTSCORE和HIGHSCORE,而後,在遊戲結束的場景LoseScene.swift經過UserDefaults.standard.integer(forKey: "CURRENTSCORE")取出存在手機沙盒裏的值;

currentScore.text = "SCORE:\(UserDefaults.standard.integer(forKey: "CURRENTSCORE"))" // 取出當前分數 highScore.text = "HIGH SCORE:\(UserDefaults.standard.integer(forKey: "HIGHSCORE"))" // 取出沙盒中的最高分數 
 
取出沙盒中的分數,並分別把當前分數、最高分數顯示在LoseScene場景當中

代碼以下:

private var currentScore:SKLabelNode! // 當局分數 private var highScore:SKLabelNode! // 最高分數 override func didMove(to view: SKView) { // 找到 名稱爲Play的節點 play = childNode(withName: "Play") as! SKSpriteNode currentScore = childNode(withName: "currentScore") as! SKLabelNode highScore = childNode(withName: "highScore") as! SKLabelNode currentScore.text = "SCORE:\(UserDefaults.standard.integer(forKey: "CURRENTSCORE"))" // 取出當前分數 highScore.text = "HIGH SCORE:\(UserDefaults.standard.integer(forKey: "HIGHSCORE"))" // 取出沙盒中的最高分數 } 

咱們補充一下有關Swift數據儲存方式的相關知識,數據儲存是存在iOS沙盒的當中,沙盒,顧名思義,即各個app之間是沒法互相訪問數據的,其目錄結構爲:

 
每一個應用程序都有對應的私有目錄,其根目錄爲Home目錄。該目錄下又三個文件夾:Documents、Library、tmp
 
UserDefaults的存放位置

每一個iOS應用都有本身的應用沙盒(應用沙盒就是文件系統目錄),與其餘文件系統隔離。應用必須待在本身的沙盒裏,其餘應用不能訪問該沙盒。沙盒下的目錄以下:

Documents: 保存應⽤運行時生成的須要持久化的數據,iTunes同步設備時會備份該目錄。例如,遊戲應用可將遊戲存檔保存在該目錄。

tmp: 保存應⽤運行時所需的臨時數據,使⽤完畢後再將相應的文件從該目錄刪除。應用 沒有運行時,系統也可能會清除該目錄下的文件。iTunes同步設備時不會備份該目錄。

Library/Caches: 保存應用運行時⽣成的須要持久化的數據,iTunes同步設備時不會備份 該目錄。⼀通常存儲體積大、不須要備份的非重要數據,好比網絡數據緩存存儲到Caches下。

Library/Preference: 保存應用的全部偏好設置,如iOS的Settings(設置) 應⽤會在該目錄中查找應⽤的設置信息。iTunes同步設備時會備份該目錄。

UserDefaults能夠存儲的數據類型:NSData、NSString、NSNumber、NSDate、NSArray、NSDictionary,若是把有null的value放入userDefaults,程序會崩。

//存儲基礎類型,以Int爲例。 UserDefaults.standard.set(15, forKey:"theKey") //讀取基礎類型,以Int爲例。 let num = UserDefaults.standard.integer(forKey: "theKey") 

注意:不要用UserDefaults儲存用戶的密碼。

3、SpirteKit Particle粒子效果

咱們選中Explosion.sks來查看Particle粒子效果,右側爲粒子效果的屬性面板,咱們能夠修改屬性中的相關值,來觀察爆炸的變化。

 
Particle粒子效果

在代碼中引入,外星人Alien撞擊到飛船引入粒子特效。

// 擊中粒子效果 Particle func alienHitSpaceShip(nodeA:SKSpriteNode,nodeB:SKSpriteNode){ if (nodeA.physicsBody?.categoryBitMask == PhysicsCategory.Alien || nodeB.physicsBody?.categoryBitMask == PhysicsCategory.Alien) && (nodeA.physicsBody?.categoryBitMask == PhysicsCategory.SpaceShip || nodeB.physicsBody?.categoryBitMask == PhysicsCategory.SpaceShip) { let explosion = SKEmitterNode(fileNamed: "Explosion")! explosion.position = nodeA.position self.addChild(explosion) } } 

子彈擊中外星飛船的粒子特效

// MARK: 子彈vs外星人 func bulletHitAlien(nodeA:SKSpriteNode,nodeB:SKSpriteNode){ // 擊中粒子效果 Particle let explosion = SKEmitterNode(fileNamed: "ExplosionBlue")! explosion.position = nodeA.position self.addChild(explosion) explosion.run(SKAction.sequence([ SKAction.wait(forDuration: 0.3), SKAction.run { explosion.removeFromParent() }])) } 

子彈引入粒子特效,在func spawnBulletAndFire(){}裏

/* * 粒子效果 * 1.新建一個SKNode => trailNode * 2.新建粒子效果SKEmitterNode,設置tragetNode = trailNode * 3.子彈加上emitterNode */ let trailNode = SKNode() trailNode.zPosition = 1 trailNode.name = "trail" addChild(trailNode) let emitterNode = SKEmitterNode(fileNamed: "ShootTrailBlue")! // particles文件夾存放粒子效果 emitterNode.targetNode = trailNode // 設置粒子效果的目標爲trailNode => 跟隨新建的trailNode bulletNode.addChild(emitterNode) // 在子彈節點Node加上粒子效果; 

若是去除 emitterNode.targetNode = trailNode,則子彈沒有拖影特效

其中特別要注意的是要判斷哪一個是子彈精靈節點,並移除全部子彈精靈的子節點的特效。

nodeA.removeAllChildren() // 移除全部子效果 emitter

// 判斷哪一個是子彈節點bulletNode,碰撞didBegin沒有比較大小時,則會相互切換,也就是A和B互相切換; if nodeA.physicsBody?.categoryBitMask == PhysicsCategory.BulletBlue { nodeA.removeAllChildren() // 移除全部子效果 emitter nodeA.isHidden = true // 子彈隱藏 nodeA.physicsBody?.categoryBitMask = 0 // 設置子彈不會再發生碰撞 nodeB.removeFromParent() // 移除外星人 }else if nodeB.physicsBody?.categoryBitMask == PhysicsCategory.BulletBlue { nodeA.removeFromParent() // 移除外星人 nodeB.removeAllChildren() nodeB.isHidden = true nodeB.physicsBody?.categoryBitMask = 0 } 

至此,咱們就完成了Space Battle宇宙大戰SpirteKit遊戲的全部章節了。

很感謝你們的閱讀,若是有疑問能夠在文章下方的評論欄提問,也請你們多多指出文中的不足之處,一塊兒努力,一塊兒從開發遊戲當中得到滿滿的樂趣,收穫滿滿的自豪感。

遊戲源碼傳送門:https://github.com/apiapia/SpaceBattleSpriteKitGame
更多遊戲教程:http://www.iFIERO.com

相關文章
相關標籤/搜索