用Swift做個(gè)游戲Lecture09 —— 服務(wù)員,說好的菜單呢人芽?

系列:用Swift作個(gè)游戲
作者:pmst(1345614869)
微博:PPPPPPMST

Lecture08課程結(jié)束望几,我們已經(jīng)走過了90%,剩下的10%是對(duì)游戲體驗(yàn)的改進(jìn)罷了萤厅。就比如橄抹,剛啟動(dòng)游戲,“Player”就出現(xiàn)在屏幕中Flap一下翅膀惕味,然后還沒等用戶清楚這個(gè)游戲是什么情況的時(shí)候楼誓,“Player”已經(jīng)墜地陣亡了。這種游戲體驗(yàn)可謂是差到極致名挥,試想一個(gè)用戶下載游戲并啟動(dòng)疟羹,此時(shí)還對(duì)游戲沒有一絲認(rèn)知,渴求先看看幫助說明或者玩法介紹之類吧禀倔!

因?yàn)楸菊n程中榄融,將剔除早前的直接進(jìn)入游戲的弊端,通過添加主菜單供用戶選擇開始一次游戲亦或是查看游戲幫助說明等選項(xiàng)救湖。如下:

前文已經(jīng)給出了游戲狀態(tài)有如下幾種:

enum GameState{
    case MainMenu
    case Tutorial
    case Play
    case Falling
    case ShowingScore
    case GameOver
}

當(dāng)我們開始一個(gè)游戲的時(shí)候剃袍,必須制定當(dāng)前新游戲的狀態(tài),比如是MainMenu顯示主菜單呢還是直接進(jìn)入正題Play開始進(jìn)行游戲捎谨。為此我們自定義一個(gè)構(gòu)造函數(shù)init(size: CGSize, gameState: GameState)傳入gameState設(shè)置新游戲初識(shí)狀態(tài)民效。請(qǐng)?zhí)砑尤缦聝蓚€(gè)方法到GameScene.swift中的GameScene類中憔维。

init(size: CGSize, gameState: GameState) {
    self.gameState = gameState
    super.init(size: size)
}

添加完畢之后,你會(huì)發(fā)現(xiàn)編譯器報(bào)錯(cuò)畏邢,這也是情理之中业扒,畢竟修改了構(gòu)造方法導(dǎo)致早前的初始化方法都不能使用了。不急舒萎,慢慢修改程储。請(qǐng)定位到switchToNewGame()方法,要知道早前我們開始一個(gè)新游戲就是調(diào)用該函數(shù)臂寝,但是未指定新游戲的狀態(tài)章鲤,為此我們要大刀闊斧地小改一番...如下:

func switchToNewGame(gameState: GameState) {    //改動(dòng)1 添加了一個(gè)傳入?yún)?shù)
    
    runAction(popAction)
    
    let newScene = GameScene(size: size,gameState:gameState)//修改傳入?yún)?shù)
    let transition = SKTransition.fadeWithColor(SKColor.blackColor(), duration: 0.5)
    view?.presentScene(newScene, transition: transition)
}

wo ca!!這下早前所有調(diào)用switchToNewGame()方法的地方都報(bào)錯(cuò)了。請(qǐng)不要著急咆贬,凡是循序漸進(jìn)败徊,首先找到touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?)方法,這次真要大改一番了:

override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
    
    //1
   let touch = touches.first
   let touchLocation = touch?.locationInNode(self)
   
   switch gameState {
   case .MainMenu:
        //2
       if touchLocation?.y < size.height * 0.15 {
           //TODO: 之后添加
       } else if touchLocation?.x < size.width * 0.6 {
            //3
           switchToNewGame(.Tutorial)
       }
       break
   case .Tutorial:
       //TODO: 之后添加
       break
   case .Play:
       flapPlayer()
       break
   case .Falling:
       break
   case .ShowingScore:
       break
   case .GameOver:
        //4
       if touchLocation?.x < size.width * 0.6 {
           switchToNewGame(.MainMenu)
       }
       break
   }
}

改動(dòng)還是蠻大的掏缎,起碼現(xiàn)在需要根據(jù)你點(diǎn)擊的位置來執(zhí)行相應(yīng)的點(diǎn)擊事件:

  1. 獲得第一個(gè)點(diǎn)擊皱蹦,然后得到在場(chǎng)景中的位置Position,自然就是點(diǎn)Point:包括x坐標(biāo)值和y坐標(biāo)值了。
  2. 這里我們只是簡(jiǎn)單判斷點(diǎn)擊位置的范圍眷蜈,比如點(diǎn)擊位置下偏下方時(shí)沪哺,就裝作點(diǎn)擊了"Learn to make this game的按鈕"。
  3. 倘若通過位置判斷酌儒,你點(diǎn)擊了Play按鈕辜妓,則新建一個(gè)初始游戲狀態(tài)為.Tutorial的新游戲,此時(shí)并不會(huì)立刻開始游戲忌怎,而是顯示一個(gè)教程畫面嫌拣,只有當(dāng)再次點(diǎn)擊時(shí)才會(huì)開始游戲。
  4. 此時(shí)處于游戲結(jié)束狀態(tài)呆躲,通過點(diǎn)擊OK按鈕開啟一個(gè)新游戲,但是游戲狀態(tài)為.Menu捶索。

此時(shí)還有個(gè)報(bào)錯(cuò)來自于"GameViewController.switf文件"插掂,請(qǐng)找到let scene = GameScene(size:CGSizeMake(320, 320 * aspectRatio))這一行,改為我們定義的構(gòu)造方法let scene = GameScene(size:CGSizeMake(320, 320 * aspectRatio),gameState:.MainMenu)即可腥例。

點(diǎn)擊運(yùn)行辅甥,我去!! 咋不靈了.....

貌似didMoveToView()方法中 我們并沒有根據(jù)游戲初始狀態(tài)來初始化游戲場(chǎng)景...請(qǐng)轉(zhuǎn)到GameScene類中,定位到didMoveToView(),將其中內(nèi)容替換成如下內(nèi)容:

override func didMoveToView(view: SKView) {
    physicsWorld.gravity = CGVector(dx: 0, dy: 0)
    physicsWorld.contactDelegate = self
    
    addChild(worldNode)
    
    // 以下為替換內(nèi)容 
    if gameState == .MainMenu {
        switchToMainMenu()
    } else {
        switchToTutorial()
    }
}
//MARK: Game States 
//添加剩余兩個(gè)場(chǎng)景切換方法
func switchToMainMenu() {
   
   gameState = .MainMenu
   setupBackground()
   setupForeground()
   setupPlayer()
   setupSomebrero()
   //TODO: 實(shí)現(xiàn)setupMainMenu()主界面布局 之后把注釋去掉
   
}

func switchToTutorial() {
   gameState = .Tutorial
   setupBackground()
   setupForeground()
   setupPlayer()
   setupSomebrero()
   setupLabel()
   //TODO: 實(shí)現(xiàn)setupTutorial()教程界面布局 之后把注釋去掉
}

其中我們還未實(shí)現(xiàn)對(duì)主界面的布局燎竖,以及教程界面的布局璃弄,這也是接下來所要干的事了。

實(shí)現(xiàn)主界面的布局:

代碼貌似很長(zhǎng)构回,但內(nèi)容很熟悉不是嗎夏块,當(dāng)年你在配置ScoreCard界面的時(shí)候不也這么做過疏咐?先布局幾個(gè)button,然后執(zhí)行幾個(gè)動(dòng)畫罷了脐供,請(qǐng)邊碼邊回憶是怎么對(duì)精靈位置放置浑塞,添加動(dòng)作的。

func setupMainMenu() {
     
     let logo = SKSpriteNode(imageNamed: "Logo")
     logo.position = CGPoint(x: size.width/2, y: size.height * 0.8)
     logo.zPosition = Layer.UI.rawValue
     worldNode.addChild(logo)
     
     // Play button
     let playButton = SKSpriteNode(imageNamed: "Button")
     playButton.position = CGPoint(x: size.width * 0.25, y: size.height * 0.25)
     playButton.zPosition = Layer.UI.rawValue
     worldNode.addChild(playButton)
     
     let play = SKSpriteNode(imageNamed: "Play")
     play.position = CGPoint.zero
     playButton.addChild(play)
     
     // Rate button
     let rateButton = SKSpriteNode(imageNamed: "Button")
     rateButton.position = CGPoint(x: size.width * 0.75, y: size.height * 0.25)
     rateButton.zPosition = Layer.UI.rawValue
     worldNode.addChild(rateButton)
     
     let rate = SKSpriteNode(imageNamed: "Rate")
     rate.position = CGPoint.zero
     rateButton.addChild(rate)
     
     // Learn button
     let learn = SKSpriteNode(imageNamed: "button_learn")
     learn.position = CGPoint(x: size.width * 0.5, y: learn.size.height/2 + kMargin)
     learn.zPosition = Layer.UI.rawValue
     worldNode.addChild(learn)
     
     // Bounce button
     let scaleUp = SKAction.scaleTo(1.02, duration: 0.75)
     scaleUp.timingMode = .EaseInEaseOut
     let scaleDown = SKAction.scaleTo(0.98, duration: 0.75)
     scaleDown.timingMode = .EaseInEaseOut
     
     learn.runAction(SKAction.repeatActionForever(SKAction.sequence([
         scaleUp, scaleDown
         ])))
     
 }

實(shí)現(xiàn)教程界面設(shè)置:

反觀這個(gè)教程界面就顯得簡(jiǎn)單多了政己,只需要添加一章玩法幫助的圖就ok了酌壕,如下:

func setupTutorial() {
    
    let tutorial = SKSpriteNode(imageNamed: "Tutorial")
    tutorial.position = CGPoint(x: size.width * 0.5, y: playableHeight * 0.4 + playableStart)
    tutorial.name = "Tutorial"
    tutorial.zPosition = Layer.UI.rawValue
    worldNode.addChild(tutorial)
    
    let ready = SKSpriteNode(imageNamed: "Ready")
    ready.position = CGPoint(x: size.width * 0.5, y: playableHeight * 0.7 + playableStart)
    ready.name = "Tutorial"
    ready.zPosition = Layer.UI.rawValue
    worldNode.addChild(ready)
    
}

好了,定位到switchToMainMenu()switchToTutorial()方法歇由,把TODO字樣的之后方法進(jìn)行調(diào)用卵牍。

點(diǎn)擊運(yùn)行項(xiàng)目,恩...出來了沦泌,而且再次點(diǎn)擊Play會(huì)轉(zhuǎn)到教程界面糊昙。不過再點(diǎn)擊的話,貌似沒反應(yīng)了赦肃,聰明的你肯定會(huì)轉(zhuǎn)到touchesBegan()方法溅蛉,定位到.Tutorial狀態(tài),你會(huì)發(fā)現(xiàn)此時(shí)名下啥都沒有他宛,怎么可能開始愉快的玩耍呢船侧??厅各?

為此在下方添加一個(gè)switchToPlay()方法并在.Tutorial下調(diào)用镜撩。

func switchToPlay() {
    // 從.Tutorial 狀態(tài)轉(zhuǎn)到.Play狀態(tài)
    gameState = .Play
    
    // 移除Tutorial精靈 
    worldNode.enumerateChildNodesWithName("Tutorial", usingBlock: { node, stop in
        node.runAction(SKAction.sequence([
            SKAction.fadeOutWithDuration(0.5),
            SKAction.removeFromParent()
            ]))
    })
    
    // 開始產(chǎn)生障礙物 從右向左移動(dòng)
    startSpawning()
    
    // 讓Player 向上蹦跶一次...
    flapPlayer()
}

點(diǎn)擊運(yùn)行項(xiàng)目,請(qǐng)盡情享受成功的果實(shí)吧队塘!

倘若你對(duì)游戲某一部分不太熟悉袁梗,請(qǐng)到github下載所有課程的代碼和課件。

此教程已接近尾聲憔古,博主忙于工作遮怜,文章更新速度不快,請(qǐng)見諒鸿市! 請(qǐng)期待下文對(duì)游戲的進(jìn)一步優(yōu)化锯梁。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市焰情,隨后出現(xiàn)的幾起案子陌凳,更是在濱河造成了極大的恐慌,老刑警劉巖内舟,帶你破解...
    沈念sama閱讀 211,948評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件合敦,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡验游,警方通過查閱死者的電腦和手機(jī)充岛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,371評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門保檐,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人裸准,你說我怎么就攤上這事展东。” “怎么了炒俱?”我有些...
    開封第一講書人閱讀 157,490評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵盐肃,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我权悟,道長(zhǎng)砸王,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,521評(píng)論 1 284
  • 正文 為了忘掉前任峦阁,我火速辦了婚禮谦铃,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘榔昔。我一直安慰自己驹闰,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,627評(píng)論 6 386
  • 文/花漫 我一把揭開白布撒会。 她就那樣靜靜地躺著嘹朗,像睡著了一般。 火紅的嫁衣襯著肌膚如雪诵肛。 梳的紋絲不亂的頭發(fā)上屹培,一...
    開封第一講書人閱讀 49,842評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音怔檩,去河邊找鬼褪秀。 笑死,一個(gè)胖子當(dāng)著我的面吹牛薛训,可吹牛的內(nèi)容都是我干的媒吗。 我是一名探鬼主播,決...
    沈念sama閱讀 38,997評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼乙埃,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼闸英!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起膊爪,我...
    開封第一講書人閱讀 37,741評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎嚎莉,沒想到半個(gè)月后米酬,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,203評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡趋箩,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,534評(píng)論 2 327
  • 正文 我和宋清朗相戀三年赃额,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了加派。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,673評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡跳芳,死狀恐怖芍锦,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情飞盆,我是刑警寧澤娄琉,帶...
    沈念sama閱讀 34,339評(píng)論 4 330
  • 正文 年R本政府宣布,位于F島的核電站吓歇,受9級(jí)特大地震影響孽水,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜城看,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,955評(píng)論 3 313
  • 文/蒙蒙 一女气、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧测柠,春花似錦炼鞠、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,770評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至软吐,卻和暖如春瘩将,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背凹耙。 一陣腳步聲響...
    開封第一講書人閱讀 32,000評(píng)論 1 266
  • 我被黑心中介騙來泰國(guó)打工姿现, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人肖抱。 一個(gè)月前我還...
    沈念sama閱讀 46,394評(píng)論 2 360
  • 正文 我出身青樓备典,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親意述。 傳聞我的和親對(duì)象是個(gè)殘疾皇子提佣,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,562評(píng)論 2 349

推薦閱讀更多精彩內(nèi)容