<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                > 原文:http://www.jianshu.com/p/bcd17547b395 > 作者:[PMST](http://www.jianshu.com/users/596f2ba91ce9/latest_articles) 前文已經為各個精靈新增了*Physics Body*,設置了三個掩碼: * categoryBitMask表明了分屬類別。 * collisionBitMask告知能與哪些物體碰撞。 * contactTestBitMask則告知能與哪些物體接觸。 現在遺留的問題是如何檢測碰撞?難道是在*update()*方法進行檢測:遍歷所有的節點,通過判斷節點的位置是否有交集嗎?天吶!這也太麻煩了。確實,如果通過自己實時檢測實在過于勞累,何不讓*Sprite Kit*來幫你代勞,每當物體之間發生碰撞了,立馬通知你來處理事件。*Bingo!!*?顯然這里要用**協議+代理**了,設置場景為代理,每當*Sprite Kit*檢測到碰撞事件發生,就通知*GameScene*來處理,當前哪里事情都是在協議(*Protocol*)中聲明了。 ## 01.游戲狀態 在正式開始今天的碰撞檢測課程之前,談談如何劃分游戲各時的狀態,僅以*Flappy bird*游戲為例,簡單劃分如下: * *MaiMenu*。開始一次游戲、查看排名以及游戲幫助。 * *Tutorial*。考慮到新手對于新游戲的上手,在選擇進行一次新游戲時,展示玩法教程顯然是一個明確且友好的措施。 * *Play*。正處于游戲的狀態。 * *Falling*。*Player*因為不小心碰到障礙物失敗下落時刻。**注意:接觸障礙物,失敗掉落才算!** * *ShowingScore*。顯示得分。 * *GameeOver*。告知游戲結束。 為此請打開*Lecture05*的完成工程,打開*GameScene.swift*文件,新增游戲狀態的枚舉聲明到`enum Layer{}`下方: ~~~ enum GameState{ case MainMenu case Tutorial case Play case Falling case ShowingScore case GameOver } ~~~ 當然,我們還需要聲明一個變量用于存儲游戲場景的狀態,請找到*GameScene*類中`let sombrero = SKSpriteNode(imageNamed: "Sombrero")`這條代碼,在下方新增三個新變量: ~~~ //1 var hitGround = false //2 var hitObstacle = false //3 var gameState: GameState = .Play ~~~ 1. 標識符,記錄*Player*是否掉落至地面。 2. 標識符,記錄*Player*是否碰撞了仙人掌。 3. 游戲狀態,默認是正在玩。 ## 02.碰撞檢測 正如前面提及的**協議+代理**方式檢測物體之間的碰撞情況。首先請使得類*GameScene*遵循`SKPhysicsContactDelegate`協議: ~~~ class GameScene: SKScene,SKPhysicsContactDelegate{...} ~~~ 接著在*didMoveToView()*方法中設置代理為`self`,找到`physicsWorld.gravity = CGVector(dx: 0, dy: 0)`這行代碼,添加該行代碼`physicsWorld.contactDelegate = self`。 `SKPhysicsContactDelegate`協議中定義了兩個可選方法,分別是: * `optional public func didBeginContact(contact: SKPhysicsContact)` * `optional public func didEndContact(contact: SKPhysicsContact)` 分別用于反饋兩個物體開始接觸、結束接觸兩個時刻。本文采用第一個方法用戶處理物體接觸事件。 ~~~ func didBeginContact(contact: SKPhysicsContact) { let other = contact.bodyA.categoryBitMask == PhysicsCategory.Player ? contact.bodyB : contact.bodyA if other.categoryBitMask == PhysicsCategory.Ground { hitGround = true } if other.categoryBitMask == PhysicsCategory.Obstacle { hitObstacle = true } } ~~~ `contact`包含了接觸的所有信息,其中*bodyA*和*bodyB*代表兩個碰撞的物體,顯然發生碰撞的結果只有兩種可能:1.*Player*和地面;2.*Player*和障礙物。可惜我們無法確實*bodyA*就是*Player*,亦或是*bodyB*就是它。這是有不確定性的,我們需要通過`categoryBitMask`來區分“陣營”。一旦確定哪個是*Player*之后,我們就能取到與之發生接觸的*other*,通過判斷其類別來分別置為標志位。 一旦標志位設置之后,我們需要在*update()*方法中進行處理了! ## 03.根據游戲狀態來處理事件 請定位到`update()`方法,修改其中的內容: ~~~ override func update(currentTime: CFTimeInterval) { if lastUpdateTime > 0 { dt = currentTime - lastUpdateTime } else { dt = 0 } lastUpdateTime = currentTime switch gameState { case .MainMenu: break case .Tutorial: break case .Play: updateForeground() updatePlayer() //1 checkHitObstacle() //Play狀態下檢測是否碰撞了障礙物 //2 checkHitGround() //Play狀態下檢測是否碰撞了地面 break case .Falling: updatePlayer() //3 checkHitGround() //Falling狀態下檢測是否掉落至地面 此時已經失敗了 break case .ShowingScore: break case .GameOver: break } } ~~~ 其中1,2,3中三個方法均是通過狀態標志位來處理碰撞事件,請添加`checkHitObstacle()`以及`checkHitGround()`方法到`updateForeground()`方法下方: ~~~ // 與障礙物發生碰撞 func checkHitObstacle() { if hitObstacle { hitObstacle = false switchToFalling() } } // 掉落至地面 func checkHitGround() { if hitGround { hitGround = false playerVelocity = CGPoint.zero player.zRotation = CGFloat(-90).degreesToRadians() player.position = CGPoint(x: player.position.x, y: playableStart + player.size.width/2) runAction(hitGroundAction) switchToShowScore() } } // MARK: - Game States // 由Play狀態變為Falling狀態 func switchToFalling() { gameState = .Falling runAction(SKAction.sequence([ whackAction, SKAction.waitForDuration(0.1), fallingAction ])) player.removeAllActions() stopSpawning() } // 顯示分數狀態 func switchToShowScore() { gameState = .ShowingScore player.removeAllActions() stopSpawning() } // 重新開始一次游戲 func switchToNewGame() { runAction(popAction) let newScene = GameScene(size: size) let transition = SKTransition.fadeWithColor(SKColor.blackColor(), duration: 0.5) view?.presentScene(newScene, transition: transition) } ~~~ 完成后自然你發現`stopSpawning()`方法并未實現,因為我打算好好講講這個。早前在`didMoveToView()`方法中調用`startSpawning()`源源不斷地產生障礙物,但是一旦游戲結束,我們所要做的事情有兩個:1.停止繼續產生障礙物;2.已經在場景中的障礙物停止移動。那么如何制定某個動作*Action*停止呢?答案是先為這個動作命名(簡單來說設置一個**Key**而已),然后用`removeActionForKey()`來移除。 OK,找到`startSpawning()`方法,將`runAction(overallSequence)`替換成`runAction(overallSequence, withKey: "spawn")`;定位到`spawnObstacle()`方法,分別設置*bottomObstacle*和*topObstacle*精靈的名字,方便之后找到它們并進行操作: ~~~ ... bottomObstacle.name = "BottomObstacle" worldNode.addChild(bottomObstacle) ... topObstacle.name = "TopObstacle" worldNode.addChild(topObstacle) ... ~~~ 現在來實現`stopSpawning()`方法,在`startSpawning()`下方添加就好: ~~~ func stopSpawning() { removeActionForKey("spawn") worldNode.enumerateChildNodesWithName("TopObstacle", usingBlock: { node, stop in node.removeAllActions() }) worldNode.enumerateChildNodesWithName("BottomObstacle", usingBlock: { node, stop in node.removeAllActions() }) } ~~~ 點擊運行,我擦!還沒來得及點就掉地上了......好吧,只能在游戲進入一瞬間先讓*Player*向上蹦跶下。添加`flapPlayer()`到`didMoveToView()`方法的最下方。 點擊運行,Nice!!*Player*順利穿過了障礙,不小心碰到了障礙物,再點擊,等等!怎么還能動...好吧,看來`touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?)`點擊事件中我們并未根據游戲狀態來處理,是時候修改了。 ~~~ override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) { switch gameState { case .MainMenu: break case .Tutorial: break case .Play: flapPlayer() break case .Falling: break case .ShowingScore: switchToNewGame() break case .GameOver: break } } ~~~ 點擊運行,失敗重新開始游戲...等等貌似還有問題,怎么點擊想重新開始游戲會突然掉落到地面上...好吧,請看[lecture02](http://www.jianshu.com/p/82697ebf5cad)中的時間間隔圖,匆忙的你找找原因,試試解決吧。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看