日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
基于SpriteKit+Swift開(kāi)發(fā)打竹塊游戲(下篇)

一、  簡(jiǎn)介

SpriteKit是蘋(píng)果公司推出的iOS和OS X游戲開(kāi)發(fā)框架。這個(gè)工具不僅提供了強(qiáng)有力的圖形功能,而且還包括一個(gè)易于使用的物理引擎。最重要的是,你可以使用你熟悉的工具 ——swift,Xcode和Interface Builder完成所有的工作!你可以用SpriteKit做很多的事情;但是,想了解它是如何工作的***方法就是使用它開(kāi)發(fā)一個(gè)簡(jiǎn)單的游戲。

做網(wǎng)站、成都網(wǎng)站建設(shè),成都做網(wǎng)站公司-成都創(chuàng)新互聯(lián)已向近1000家企業(yè)提供了,網(wǎng)站設(shè)計(jì),網(wǎng)站制作,網(wǎng)絡(luò)營(yíng)銷等服務(wù)!設(shè)計(jì)與技術(shù)結(jié)合,多年網(wǎng)站推廣經(jīng)驗(yàn),合理的價(jià)格為您打造企業(yè)品質(zhì)網(wǎng)站。

在本系列教程(2部分)中,你將要學(xué)習(xí)如何使用SpriteKit來(lái)開(kāi)發(fā)一款Breakout游戲。在上篇中,我們?cè)谟螒驁?chǎng)景中成功地添了擋板與小球;在本篇中,我們要往游戲場(chǎng)景中添加竹塊,并實(shí)現(xiàn)游戲的所有其他邏輯。

二、  加入竹塊

現(xiàn)在,既然你已經(jīng)讓小球跳躍起來(lái)并實(shí)現(xiàn)了接觸方面的控制,那么接下來(lái)讓我們添加一些竹塊用于小球擊打之用。畢竟這是一款打竹塊游戲,是不是?

好,切換到文件GameScene.swift,然后在方法didMoveToView(_:)中添加以下代碼:

 
 
 
 
  1. // 1
  2. let numberOfBlocks = 8
  3. let blockWidth = SKSpriteNode(imageNamed: "block").size.width
  4. let totalBlocksWidth = blockWidth * CGFloat(numberOfBlocks)
  5. // 2
  6. let xOffset = (CGRectGetWidth(frame) - totalBlocksWidth) / 2
  7. // 3
  8. for i in 0..
  9.   let block = SKSpriteNode(imageNamed: "block.png")
  10.   block.position = CGPoint(x: xOffset + CGFloat(CGFloat(i) + 0.5) * blockWidth,
  11.     y: CGRectGetHeight(frame) * 0.8)
  12.   block.physicsBody = SKPhysicsBody(rectangleOfSize: block.frame.size)
  13.   block.physicsBody!.allowsRotation = false
  14.   block.physicsBody!.friction = 0.0
  15.   block.physicsBody!.affectedByGravity = false
  16.   block.physicsBody!.dynamic = false
  17.   block.name = BlockCategoryName
  18.   block.physicsBody!.categoryBitMask = BlockCategory
  19.   block.zPosition = 2
  20.   addChild(block)
  21. }

此代碼在屏幕上將創(chuàng)建居中的八塊竹塊。具體來(lái)說(shuō),上面代碼段實(shí)現(xiàn)了:

(1)建立了一些有用的常量,用于保存竹塊數(shù)量及寬度值等。

(2)計(jì)算x偏移量,它對(duì)應(yīng)于屏幕的左邊框和***個(gè)竹塊之間的距離。這里使用屏幕寬度減去所有竹塊的寬度,然后除以2來(lái)計(jì)算。

(3)創(chuàng)建竹塊并配置每個(gè)竹塊適當(dāng)?shù)奈锢韺傩?,并使?blockWidth和xOffset變量來(lái)安排每一個(gè)的位置。

現(xiàn)在,構(gòu)建并運(yùn)行一下你的游戲,并注意觀察!請(qǐng)參考下圖。

現(xiàn)在,竹塊已到位。但是,為了監(jiān)聽(tīng)小球和竹塊之間的碰撞,你必須更新小球的 contactTestBitMask掩碼。仍然在 GameScene.swift文件中,編輯didMoveToView(_:)方法中現(xiàn)有的代碼行即可——向它添加一個(gè)額外的類別:

 
 
 
 
  1. ball.physicsBody!.contactTestBitMask = BottomCategory | BlockCategory

上述代碼執(zhí)行了BottomCategory和BlockCategory兩個(gè)掩碼間的按位或操作。其結(jié)果是,這兩個(gè)特定類別的位都設(shè)置為1,而所有其他位仍均為零?,F(xiàn)在,球與地板以及球和塊之間的碰撞信息都會(huì)被發(fā)送給代理以便進(jìn)一步處理。

三、  打竹塊

現(xiàn)在,你已經(jīng)準(zhǔn)備好塊與球之間的碰撞檢測(cè)了。讓我們將一個(gè)幫助方法添加到 GameScene.swift文件中,以便實(shí)現(xiàn)從場(chǎng)景中刪除竹塊:

 
 
 
 
  1. func breakBlock(node: SKNode) {
  2.   let particles = SKEmitterNode(fileNamed: "BrokenPlatform")!
  3.   particles.position = node.position
  4.   particles.zPosition = 3
  5.   addChild(particles)
  6.   particles.runAction(SKAction.sequence([SKAction.waitForDuration(1.0), SKAction.removeFromParent()]))
  7.   node.removeFromParent()
  8. }

此方法使用了參數(shù)SKNode。首先,它從 BrokenPlatform.sks 文件中創(chuàng)建SKEmitterNode的一個(gè)實(shí)例,然后將它的位置設(shè)置為該節(jié)點(diǎn)相同的位置。發(fā)射器節(jié)點(diǎn)的 zPosition 設(shè)置為 3;這樣,粒子就能夠顯示在剩余的竹塊上面。把粒子添加到場(chǎng)景后,節(jié)點(diǎn)(竹塊)將被刪除。

[注意]發(fā)射器節(jié)點(diǎn)是一種特殊類型的節(jié)點(diǎn),它用于顯示在場(chǎng)景編輯器中創(chuàng)建的粒子系統(tǒng)。若要檢查它是如何配置的,你可以打開(kāi)文件BrokenPlatform.sks,這是我為本教程專門創(chuàng)建的粒子系統(tǒng)。

剩下要做的唯一事情是根據(jù)情況相應(yīng)地處理委托通知。在didBeginContact(_:) 的末尾添加以下內(nèi)容:

 
 
 
 
  1. if firstBody.categoryBitMask == BallCategory && secondBody.categoryBitMask == BlockCategory {
  2.   breakBlock(secondBody.node!)
  3.   //TODO: check if the game has been won
  4. }

上面這些代碼行檢查是否小球和竹塊間存在碰撞。如果是這樣,你將節(jié)點(diǎn)傳遞給 breakBlock(_:) 方法并隨著播放粒子動(dòng)畫(huà)從場(chǎng)景中刪除竹塊!

現(xiàn)在,生成并運(yùn)行工程。你會(huì)注意到當(dāng)小球擊中竹塊時(shí)竹塊應(yīng)該分開(kāi)。

四、  游戲控制邏輯

現(xiàn)在,你已經(jīng)創(chuàng)建了打竹塊游戲所需要的所有元素,輪到玩家體驗(yàn)一下激動(dòng)人心的勝利或是失敗的痛苦的時(shí)候了!

(一)構(gòu)建狀態(tài)機(jī)

大多數(shù)游戲邏輯受游戲的當(dāng)前狀態(tài)所控制。例如,如果游戲是在“主菜單”狀態(tài)下,那么玩家就不能移動(dòng),但如果游戲是在“播放”狀態(tài),玩家應(yīng)該能移動(dòng)。

大量的簡(jiǎn)單游戲都是通過(guò)使用布爾型變量并結(jié)合更新循環(huán)來(lái)管理游戲狀態(tài)。通過(guò)使用狀態(tài)機(jī),隨著你的游戲變得更加復(fù)雜你可以更好地組織代碼。

一個(gè)狀態(tài)機(jī)用來(lái)管理一組狀態(tài)。其中,只有一個(gè)當(dāng)前狀態(tài),并且有一套規(guī)則用于狀態(tài)之間的過(guò)渡。隨著游戲狀態(tài)的變化,在退出前一個(gè)狀態(tài)并進(jìn)入下一狀態(tài)時(shí)狀態(tài)機(jī)都會(huì)運(yùn)行某些方法。這些方法可用于從每個(gè)狀態(tài)內(nèi)部來(lái)控制游戲。在狀態(tài)更改成功后,狀態(tài)機(jī)將執(zhí)行當(dāng)前狀態(tài)的更新循環(huán)。

蘋(píng)果公司在iOS 9中推出了GameplayKit框架,此框架內(nèi)置支持狀態(tài)機(jī),從而使使用狀態(tài)機(jī)的工作非常容易。有關(guān)GameplayKit的使用細(xì)節(jié),已經(jīng)超出了本教程的范圍;但在本教程中,你將使用其中的兩個(gè)類:GKStateMachine 和 GKState 類。

(二)添加狀態(tài)

在我們的打竹塊游戲中,共有三種游戲狀態(tài):

  • WaitingForTap:意味著游戲已完成加載并準(zhǔn)備開(kāi)始啟動(dòng)。
  • Playing:處于玩游戲狀態(tài)。
  • GameOver:游戲結(jié)束(或者輸或者贏)。

為了節(jié)省時(shí)間,已經(jīng)有三個(gè) GKState 類添加到項(xiàng)目中(如果好奇的話,你可以查看一下Game States組)。為了創(chuàng)建狀態(tài)機(jī),首先在 GameScene.swift 文件的頂部添加以下的導(dǎo)入語(yǔ)句:

 
 
 
 
  1. import GameplayKit

接下來(lái),在語(yǔ)句var isFingerOnPaddle = false:下面插入這個(gè)類變量:

 
 
 
 
  1. lazy var gameState: GKStateMachineGKStateMachine = GKStateMachine(states: [
  2.   WaitingForTap(scene: self),
  3.   Playing(scene: self),
  4.   GameOver(scene: self)])

通過(guò)定義此變量,你可以有效地創(chuàng)建打竹塊游戲的狀態(tài)機(jī)。注意:你正在使用GKState子類數(shù)組初始化 GKStateMachine。

(三)實(shí)現(xiàn)WaitingForTap狀態(tài)

WaitingForTap狀態(tài)意味著游戲已完成加載并準(zhǔn)備開(kāi)始啟動(dòng)了。玩家在屏幕上會(huì)看到“Tap to Play”的提示,在游戲進(jìn)入播放狀態(tài)之前將等待觸摸事件。

現(xiàn)在,在didMoveToView(_:) 方法的末尾添加以下代碼︰

 
 
 
 
  1. let gameMessage = SKSpriteNode(imageNamed: "TapToPlay")
  2. gameMessage.name = GameMessageName
  3. gameMessage.position = CGPoint(x: CGRectGetMidX(frame), y: CGRectGetMidY(frame))
  4. gameMessage.zPosition = 4
  5. gameMessage.setScale(0.0)
  6. addChild(gameMessage)
  7. gameState.enterState(WaitingForTap)

這將創(chuàng)建顯示“Tap to Play”的提示消息,后來(lái)它也將用于顯示“Game Over”消息。接下來(lái),你需要告訴狀態(tài)機(jī)進(jìn)入 WaitingForTap 狀態(tài)。

在 didMoveToView(_:)方法中,你還要?jiǎng)h除如下一行:

 
 
 
 
  1. ball.physicsBody!.applyImpulse(CGVector(dx: 2.0, dy: -2.0)) // REMOVE

稍后,在本教程中,你需要把這段代碼移動(dòng)到游戲播放狀態(tài)處。

現(xiàn)在,打開(kāi) WaitingForTap.swift 文件。使用如下代碼替換DidEnterWithPreviousState(_:)方法和 willExitWithNextState(_:)方法︰

 
 
 
 
  1. override func didEnterWithPreviousState(previousState: GKState?) {
  2.   let scale = SKAction.scaleTo(1.0, duration: 0.25)
  3.   scene.childNodeWithName(GameMessageName)!.runAction(scale)
  4. }
  5. override func willExitWithNextState(nextState: GKState) {
  6.   if nextState is Playing {
  7.     let scale = SKAction.scaleTo(0, duration: 0.4)
  8.     scene.childNodeWithName(GameMessageName)!.runAction(scale)
  9.   }
  10. }

當(dāng)游戲進(jìn)入WaitingForTap狀態(tài)時(shí),didEnterWithPreviousState(_:) 方法執(zhí)行。此函數(shù)只是用于放大消息“Tap to Play”相應(yīng)的精靈,提示玩家開(kāi)始游戲。

當(dāng)游戲退出 WaitingForTap狀態(tài)并進(jìn)入Playing狀態(tài)時(shí),會(huì)調(diào)用 willExitWithNextState(_:)方法,同時(shí)消息“Tap to Play”縮小為0。

現(xiàn)在,生成和運(yùn)行工程,然后點(diǎn)擊屏幕來(lái)玩玩吧!

好了,現(xiàn)在當(dāng)你點(diǎn)擊屏幕時(shí)沒(méi)事發(fā)生。接下來(lái)要介紹的游戲狀態(tài)正是用來(lái)解決這個(gè)問(wèn)題!

(四)玩游戲狀態(tài)

Playing狀態(tài)將啟動(dòng)游戲并管理小運(yùn)動(dòng)球速度。

首先,切換回 GameScene.swift 文件并實(shí)現(xiàn)下面的幫助方法︰

 
 
 
 
  1. func randomFloat(from from:CGFloat, to:CGFloat) -> CGFloat {
  2.   let rand:CGFloat = CGFloat(Float(arc4random()) / 0xFFFFFFFF)
  3.   return (rand) * (to - from) + from
  4. }

這個(gè)工具函數(shù)會(huì)返回位于兩個(gè)傳入?yún)?shù)指定的數(shù)字之間的隨機(jī)數(shù)。你將使用它在小球運(yùn)動(dòng)的初始方向方面加入一些可變性。

現(xiàn)在,打開(kāi) Playing.swift 文件。首先,添加如下的幫助方法:

 
 
 
 
  1. func randomDirection() -> CGFloat {
  2.   let speedFactor: CGFloat = 3.0
  3.   if scene.randomFloat(from: 0.0, to: 100.0) >= 50 {
  4.     return -speedFactor
  5.   } else {
  6.     return speedFactor
  7.   }
  8. }

這段代碼只是實(shí)現(xiàn)返回一個(gè)正數(shù)或者負(fù)數(shù)的功能。這向小球的運(yùn)動(dòng)方向方面添加了一點(diǎn)隨機(jī)性。

接下來(lái),將此代碼添加到 didEnterWithPreviousState(_:):

 
 
 
 
  1. if previousState is WaitingForTap {
  2.   let ball = scene.childNodeWithName(BallCategoryName) as! SKSpriteNode
  3.   ball.physicsBody!.applyImpulse(CGVector(dx: randomDirection(), dy: randomDirection()))
  4. }

當(dāng)游戲進(jìn)入Playing狀態(tài)時(shí),小球精靈被檢索到,并激活其applyImpulse(_:) 方法。

接下來(lái),將此代碼添加到 updateWithDeltaTime(_:) 方法 ︰

 
 
 
 
  1. let ball = scene.childNodeWithName(BallCategoryName) as! SKSpriteNode
  2. let maxSpeed: CGFloat = 400.0
  3. let xSpeed = sqrt(ball.physicsBody!.velocity.dx * ball.physicsBody!.velocity.dx)
  4. let ySpeed = sqrt(ball.physicsBody!.velocity.dy * ball.physicsBody!.velocity.dy)
  5. let speed = sqrt(ball.physicsBody!.velocity.dx * ball.physicsBody!.velocity.dx + ball.physicsBody!.velocity.dy * ball.physicsBody!.velocity.dy)
  6. if xSpeed <= 10.0 {
  7.   ball.physicsBody!.applyImpulse(CGVector(dx: randomDirection(), dy: 0.0))
  8. }
  9. if ySpeed <= 10.0 {
  10.   ball.physicsBody!.applyImpulse(CGVector(dx: 0.0, dy: randomDirection()))
  11. }
  12. if speed > maxSpeed {
  13.   ball.physicsBody!.linearDamping = 0.4
  14. } else {
  15.   ball.physicsBody!.linearDamping = 0.0
  16. }

當(dāng)游戲的每幀中處于Playing狀態(tài)時(shí)將調(diào)用updateWithDeltaTime(_:)方法。代碼中,取得小球數(shù)據(jù)并檢查其速度,本質(zhì)上對(duì)應(yīng)于運(yùn)動(dòng)速度。如果沿 x 或 y方向的 速度低于某一閾值,小球可能被卡住而表現(xiàn)為不停地蹦蹦跳跳,或不停地從一邊運(yùn)動(dòng)到另一邊。如果發(fā)生這種情況,需要應(yīng)用另一種脈沖,從而把它強(qiáng)制性轉(zhuǎn)入角運(yùn)動(dòng)狀態(tài)下。

而且,球的速度隨著蹦跳可能不斷增加。如果太高了,你需要增加線性阻尼,這樣小球最終會(huì)慢下來(lái)。

現(xiàn)在,玩狀態(tài)設(shè)置了,是時(shí)候添加代碼來(lái)啟動(dòng)游戲了!

在文件GameScene.swift中,將 touchesBegan(_:withEvent:)方法 替換成下面的新代碼:

 
 
 
 
  1. override func touchesBegan(touches: Set, withEvent event: UIEvent?) {
  2.   switch gameState.currentState {
  3.   case is WaitingForTap:
  4.     gameState.enterState(Playing)
  5.     isFingerOnPaddle = true
  6.   case is Playing:
  7.     let touch = touches.first
  8.     let touchtouchLocation = touch!.locationInNode(self)
  9.     if let body = physicsWorld.bodyAtPoint(touchLocation) {
  10.       if body.node!.name == PaddleCategoryName {
  11.         isFingerOnPaddle = true
  12.       }
  13.     }
  14.   default:
  15.     break
  16.   }
  17. }

上面代碼可以使游戲檢查游戲的當(dāng)前狀態(tài),并相應(yīng)地更改狀態(tài)。接下來(lái),你需要重寫(xiě) update(_:) 方法并修改成像這樣:

 
 
 
 
  1. override func update(currentTime: NSTimeInterval) {
  2.   gameState.updateWithDeltaTime(currentTime)
  3. }

在渲染每一幀之前都會(huì)調(diào)用 update(_:) 方法。正是在此處,我們調(diào)用玩狀態(tài)對(duì)應(yīng)的updateWithDeltaTime(_:) 方法來(lái)管理小球的運(yùn)動(dòng)速度。

現(xiàn)在,生成并運(yùn)行項(xiàng)目,然后點(diǎn)擊屏幕來(lái)查看狀態(tài)機(jī)在游戲中的作用!

(五)游戲結(jié)束狀態(tài)

當(dāng)所有的竹塊被壓跨或小球跌落到屏幕的底部時(shí)GameOver狀態(tài)發(fā)生。

現(xiàn)在,我們打開(kāi)位于Game States組中的GameOver.swift文件,并將下面這些代碼行添加到方法didEnterWithPreviousState(_:)中:

 
 
 
 
  1. if previousState is Playing {
  2.   let ball = scene.childNodeWithName(BallCategoryName) as! SKSpriteNode
  3.   ball.physicsBody!.linearDamping = 1.0
  4.   scene.physicsWorld.gravity = CGVectorMake(0, -9.8)
  5. }

當(dāng)游戲進(jìn)入GameOver狀態(tài)時(shí),線性阻尼應(yīng)用于小球而且重力得到恢復(fù),從而導(dǎo)致小跌落到地上,速度也慢下來(lái)。

關(guān)于GameOver狀態(tài),我們就討論至此。接下來(lái)要實(shí)現(xiàn)的代碼是確定玩家是贏了還是輸?shù)袅擞螒颍?/p>

(六)游戲結(jié)局

到現(xiàn)在,既然狀態(tài)機(jī)都設(shè)置好了,可以說(shuō)游戲的絕大部分已經(jīng)開(kāi)發(fā)結(jié)束?,F(xiàn)在,我們需要想一種辦法來(lái)確定游戲的輸贏。

打開(kāi)文件GameScene.swift并添加下面的幫助方法:

 
 
 
 
  1. func isGameWon() -> Bool {
  2.   var numberOfBricks = 0
  3.   self.enumerateChildNodesWithName(BlockCategoryName) {
  4.     node, stop in
  5.     numberOfBricksnumberOfBricks = numberOfBricks + 1
  6.   }
  7.   return numberOfBricks == 0
  8. }

此方法通過(guò)遍歷場(chǎng)景中子結(jié)點(diǎn)來(lái)檢查場(chǎng)景中還留下多少竹塊。對(duì)于每一個(gè)子結(jié)點(diǎn),它要檢查子結(jié)點(diǎn)名字是否等于 BlockCategoryName。如果場(chǎng)景中沒(méi)有留下竹塊,那么玩家贏得了當(dāng)前游戲,方法返回 true。

現(xiàn)在,將如下屬性添加到類的頂部,也就是恰好位于屬性gameState的下面:

 
 
 
 
  1. var gameWon : Bool = false {
  2.   didSet {
  3.     let gameOver = childNodeWithName(GameMessageName) as! SKSpriteNode
  4.     let textureName = gameWon ? "YouWon" : "GameOver"
  5.     let texture = SKTexture(imageNamed: textureName)
  6.     let actionSequence = SKAction.sequence([SKAction.setTexture(texture),
  7.       SKAction.scaleTo(1.0, duration: 0.25)])
  8.     gameOver.runAction(actionSequence)
  9.   }
  10. }

在這里,你創(chuàng)建了gameWon變量,并為之附加一個(gè)didSet屬性觀察器。這將允許你觀察屬性值的變化情況并做出相應(yīng)的反應(yīng)。在上面實(shí)現(xiàn)代碼中,改變游戲消息精靈的紋理以反映游戲是贏了還是輸了,然后在屏幕上顯示結(jié)果。

[注意]屬性觀察器(Property Observer)有一個(gè)允許您檢查新值或舊值的參數(shù)。當(dāng)發(fā)生屬性變化時(shí)允許值變化的比較。如果你不提供名稱的話,它們自己都有默認(rèn)名稱;在上述代碼中分別是newValue和oldValue。

接下來(lái),讓我們編輯一下didBeginContact(_:) 方法,如下所示:

首先,把下面代碼添加到didBeginContact(_:)方法的最頂端:

 
 
 
 
  1. if gameState.currentState is Playing {
  2. // Previous code remains here...
  3. } // Don't forget to close the 'if' statement at the end of the method.

這段代碼的功能是:當(dāng)游戲還未處于玩狀態(tài)時(shí),防止任何的接觸發(fā)生。

接下來(lái),使用下面這段代碼:

 
 
 
 
  1. print("Hit bottom. First contact has been made.")

替換掉下面的代碼:

 
 
 
 
  1. gameState.enterState(GameOver)
  2. gameWon = false

現(xiàn)在,當(dāng)小球碰到屏幕的底部時(shí)游戲結(jié)束。

請(qǐng)使用如下代碼替換掉//TODO:部分:

 
 
 
 
  1. if isGameWon() {
  2.   gameState.enterState(GameOver)
  3.   gameWon = true
  4. }
  5. When all the blocks are broken you win!
  6. Finally, add this code to touchesBegan(_:withEvent:) just above default:
  7. case is GameOver:
  8.   let newScene = GameScene(fileNamed:"GameScene")
  9.   newScene!.scaleMode = .AspectFit
  10.   let reveal = SKTransition.flipHorizontalWithDuration(0.5)
  11.   self.view?.presentScene(newScene!, transition: reveal)

至此,你的游戲已經(jīng)完成!你可以構(gòu)建并運(yùn)行它了。

五、  游戲潤(rùn)色

現(xiàn)在,打竹塊游戲主要功能開(kāi)發(fā)完畢。接下來(lái),讓我們?cè)谟螒蛑刑砑有┰S的潤(rùn)色!每當(dāng)小球發(fā)生接觸和當(dāng)竹塊破裂時(shí)加入一些音效。當(dāng)游戲結(jié)束的時(shí)候,也添加一種快速爆炸的音樂(lè)效果。***,您將把一個(gè)粒子發(fā)射器添加到小球,以便當(dāng)小球在屏幕周圍來(lái)回反彈時(shí)留下一道痕跡。

(一)加入聲效

為了節(jié)省時(shí)間,項(xiàng)目中已經(jīng)導(dǎo)入了各種聲音文件。現(xiàn)在,打開(kāi)GameScene.swift文件,然后把下列常量定義添加到類定義的頂部,更確切地說(shuō)是恰好位于gameWon變量的后面:

 
 
 
 
  1. let blipSound = SKAction.playSoundFileNamed("pongblip", waitForCompletion: false)
  2. let blipPaddleSound = SKAction.playSoundFileNamed("paddleBlip", waitForCompletion: false)
  3. let bambooBreakSound = SKAction.playSoundFileNamed("BambooBreak", waitForCompletion: false)
  4. let gameWonSound = SKAction.playSoundFileNamed("game-won", waitForCompletion: false)
  5. let gameOverSound = SKAction.playSoundFileNamed("game-over", waitForCompletion: false)

這段代碼中定義了一系列的SKAction常量,其中每一個(gè)都將加載并播放聲音文件。因?yàn)槟阍谛枰鼈冎岸x了這些操作,所以它們會(huì)被預(yù)先加載到內(nèi)存,這在你***次播放聲音時(shí)防止游戲延遲。

下一步,將在didMoveToView(_:)方法中設(shè)置小球的contactTestBitMask掩碼的那一行更新為以下形式︰

 
 
 
 
  1. ball.physicsBody!.contactTestBitMask = BottomCategory | BlockCategory | BorderCategory | PaddleCategory

并沒(méi)有什么新內(nèi)容,只是在小球的contactTestBitMask掩碼上添加了BorderCategory和PaddleCategory,這樣你就可以檢測(cè)到與屏幕邊界的接觸,以及當(dāng)小球與擋板接觸時(shí)使用。

接下來(lái),讓我們修改一下方法didBeginContact(_:)來(lái)加入聲音效果,方法是把以下幾行添加到設(shè)置firstBody和secondBody的if/else語(yǔ)句后面:

 
 
 
 
  1. // 1
  2. if firstBody.categoryBitMask == BallCategory && secondBody.categoryBitMask == BorderCategory {
  3.   runAction(blipSound)
  4. }
  5. // 2
  6. if firstBody.categoryBitMask == BallCategory && secondBody.categoryBitMask == PaddleCategory {
  7.   runAction(blipPaddleSound)
  8. }

此代碼負(fù)責(zé)檢查兩個(gè)新的碰撞:

(1)在從屏幕邊界反彈時(shí)播放blipSound聲效。

(2)在小球與擋板接觸時(shí)播放blipPaddleSound聲效。

當(dāng)然,你希望在小球打破竹塊時(shí)使用令人滿意的嘎吱聲效。為此,你可以將下面一行添加到方法breakBlock(_:) 的頂部:

 
 
 
 
  1. runAction(bambooBreakSound)

***,在類頂部的針對(duì)變量gameWon創(chuàng)建的didSet屬性觀察器的里面插入下面的行碼行即可:

 
 
 
 
  1. runAction(gameWon ? gameWonSound : gameOverSound)

(二)加入粒子系統(tǒng)

現(xiàn)在,讓我們給小球添加一個(gè)粒子系統(tǒng);這樣一來(lái),當(dāng)它四處反彈時(shí)會(huì)留下一條火苗樣式的軌跡!

為此,可以將下面的代碼添加到方法didMoveToView(_:)中:

 
 
 
 
  1. // 1
  2. let trailNode = SKNode()
  3. trailNode.zPosition = 1
  4. addChild(trailNode)
  5. // 2
  6. let trail = SKEmitterNode(fileNamed: "BallTrail")!
  7. // 3
  8. trail.targetNode = trailNode
  9. // 4
  10. ball.addChild(trail)

讓我們回顧一下上面代碼的功能:

(1)創(chuàng)建一個(gè)SKNode作為粒子系統(tǒng)的targetNode。

(2)從BallTrail.sks文件創(chuàng)建一個(gè)SKEmitterNode。

(3)把targetNode設(shè)置為trailNode。這樣就可以錨定了粒子,從而使其留下一道軌跡;否則,這些粒子總會(huì)跟著小球。

(4)將SKEmitterNode附加到小球身上;這可以通過(guò)將其添加為它的一個(gè)子節(jié)點(diǎn)來(lái)實(shí)現(xiàn)。

好了,所有的工作都已經(jīng)做完!現(xiàn)在,你可以再次生成并運(yùn)行項(xiàng)目來(lái)看看你的游戲在添加了一些小內(nèi)容后是多么精致了。請(qǐng)參考下圖。

六、  小結(jié)

強(qiáng)烈建議您下載本教程的實(shí)例代碼以便進(jìn)行進(jìn)一步的研究(地址是https://cdn4.raywenderlich.com/wp-content/uploads/2016/04/BreakoutFinal_p2.zip)。

當(dāng)然,本文給出的僅是一個(gè)簡(jiǎn)單版本的打竹塊游戲,其實(shí)你還有很多可以要擴(kuò)展的內(nèi)容。例如,你可以添加評(píng)分功能,也可以擴(kuò)展代碼給特定竹塊***時(shí)設(shè)置特定的得分值,建立不同類型的竹塊,并在竹塊被摧毀之前使小球不得不多次擊打某些它們(或全部)。此外,你還可以添加一定特定類型的竹塊使之掉落一定的獎(jiǎng)金或道具,讓擋板對(duì)竹塊發(fā)射激光,等等??傊斡赡阕髦靼?!

基于SpriteKit+Swift開(kāi)發(fā)打竹塊游戲(上篇)


分享題目:基于SpriteKit+Swift開(kāi)發(fā)打竹塊游戲(下篇)
本文URL:http://www.dlmjj.cn/article/cogcehi.html