美文网首页牛叉的demo
做一个类似Cut The Rote 的游戏(五)

做一个类似Cut The Rote 的游戏(五)

作者: 34码的小孩子 | 来源:发表于2017-09-18 20:39 被阅读31次

    上一篇文章中,鳄鱼吃掉菠萝、菠萝掉到水里或者飞出屏幕,游戏就结束了。这不是我们想要的。今天要修改一下游戏的逻辑。

    重置游戏

    如果菠萝落在鳄鱼的嘴里,鳄鱼就会快乐地嚼起菠萝。但一旦发生这种情况,游戏就会停止。

    GameScene.swift中,找到switchToNewGameWithTransition()并添加以下代码:

    let delay = SKAction.wait(forDuration: 1)
    let sceneChange = SKAction.run({
      let scene = GameScene(size: self.size)
      self.view?.presentScene(scene, transition: transition)
    })    
    run(SKAction.sequence([delay, sceneChange]))
    

    上述代码,调用SKViewpresentScene(_:transition:)方法来呈现下一场景。

    在这种情况下,下一个场景也是GameScene实例。您可以使用SKTransition来作为参数设定转换的过渡效果。可以根据不同的游戏结果设置不同的transition,展示不一样的转场效果。

    回到didBegin()方法,在if条件里面,在奖品收缩和咀嚼动画之后,添加以下内容:

    //转换到下一场景 
    switchToNewGameWithTransition(SKTransition .doorway(withDuration:1.0))
    

    使用SKTransition.doorway(withDuration:)初始化transition,然后作为switchToNewGameWithTransition()的参数,并调用该方法,创建转换效果。展示开门的效果,并且进入游戏的下一局。很整洁啊!

    开门的效果

    结束比赛

    您可能会觉得,给我们的水背景也添加physics body,这样就可以检测到菠萝是否掉落水中。但是如果菠萝从屏幕的侧面飞出,那么就检测不到了。一个更简单、更好的方法就是:检测菠萝是否已经移出屏幕底边,如果是,则结束游戏。

    SKScene提供了update(),该方法每帧调用一次。找到该方法,并添加以下逻辑:

    if prize.position.y <= 0 {
       switchToNewGameWithTransition(SKTransition.fade(withDuration: 1.0))
    }
    

    if语句检查奖品的y坐标是否小于零(屏幕的底部)。如果是,它会调用switchToNewGameWithTransition()方法,以SKTransition.fade(withDuration:)淡出的方式再次启动游戏。

    编译并运行项目。

    玩家获胜或失败时,您应该看到场景过渡到新场景。

    添加声音和音乐

    我们选择了一首来自incompetech.com的的丛林之歌,以及来自freesound.org的的一些音效。

    SpriteKit会为您处理音效。但是你会用AVAudioPlayer在场景转换之间无缝播放背景音乐。

    GameScene.swift添加另一个属性:

    private  static  var backgroundMusicPlayer:AVAudioPlayer!` 
    

    声明了一个静态属性,所以所有的GameScene实例都可以访问到同一个backgroundMusicPlayer实例。找到该setUpAudio()方法并添加以下代码:

    if GameScene.backgroundMusicPlayer == nil {
      let backgroundMusicURL = Bundle.main.url(forResource: SoundFile.BackgroundMusic, withExtension: nil)
      do {
        let theme = try AVAudioPlayer(contentsOf: backgroundMusicURL!)
        GameScene.backgroundMusicPlayer = theme
      } catch {
        // couldn't load file :[
      }
      GameScene.backgroundMusicPlayer.numberOfLoops = -1
    }
    

    上面的代码检查backgroundMusicPlayer是否已经创建。如果没有,它将使用你之前添加到Constants.swift的常量来初始化AVAudioPlayer(该常量已经转化为 URL),并将其分配给backgroundMusicPlayer。numberOfLoops值设置为-1,表示该歌曲将无限循环播放。

    接下来,将下面的代码添加到setUpAudio()方法的底部:

    if !GameScene.backgroundMusicPlayer.isPlaying {
      GameScene.backgroundMusicPlayer.play()
    }
    

    当场景首次加载时,启动背景音乐播放(无限循环播放,直到应用程序退出或在其他方法调用播放器stop()方法)。你也可以不用检查播放器是否正在播放,而直接调用play()方法,但是这样的话,如果音乐在游戏开始前就已经播放,调用play()方法是不会跳过当前的音乐或重新播放。

    此时,您最好先将要使用的所有音效都设置好。音效不像是音乐需要立即播放的。相反,您更希望创建一些可重用的SKAction,可以用于稍后播放音效。

    返回到GameScene类定义的顶部,并添加以下属性:

    private var sliceSoundAction: SKAction!
    private var splashSoundAction: SKAction!
    private var nomNomSoundAction: SKAction! 
    

    现在回到setUpAudio()并添加以下行到方法的底部:

    sliceSoundAction = SKAction.playSoundFileNamed(SoundFile.Slice, waitForCompletion: false)
    splashSoundAction = SKAction.playSoundFileNamed(SoundFile.Splash, waitForCompletion: false)
    nomNomSoundAction = SKAction.playSoundFileNamed(SoundFile.NomNom, waitForCompletion: false)
    

    此代码使用SKActionplaySoundFileNamed(_:waitForCompletion:)方法初始化播放音效的action。现在是时候播放音效了。

    向上滚动到方法update(),并在if在调用switchToNewGameWithTransition()语句之前添加以下代码行:

    run(splashSoundAction))` 
    

    当菠萝落在水中时,会发出飞溅的声音。接下来,找到didBegin()并在runNomNomAnimationWithDelay(0.15)语句下面添加一行代码:

    run(nomNomSoundAction)
    

    当鳄鱼抓住她的奖品时,会发出大嚼的声音。最后,找到checkIfVineCutWithBody()方法,并在if语句中添加以下代码行:

    run(sliceSoundAction)
    

    当玩家剪断葡萄藤的时候,会发出一个扫动的声音。

    编译并运行项目。

    你发现了一个bug吗?如果鳄鱼没有接到菠萝,会播放多次飞溅的声音。这是由于在游戏过渡到下一个场景之前,重复地触发“游戏结束”的逻辑。要纠正这一点,请在类的顶部添加一个新的state属性:

    private  var levelOver = false`
    

    在方法update()didBegin()的顶部,都添加以下代码:

    if levelOver {
      return
    }
    

    最后,同一方法的另外一个if中,将levelOver状态设置为true

    levelOver = true
    

    现在,一旦游戏检测到levelOver标志已经被设置(菠萝撞到地面,或者鳄鱼吃了菠萝),它将停止检查游戏的胜利/失败,并且不会再持续地播放这些音效。编译并运行。没有尴尬的声效了!

    FeedingTime.png

    添加触觉反馈

    iPhone 7配备了一个新的taptic引擎,为用户提供触摸反馈。它最有名的是模拟点击主页按钮(没有移动部分)。多谢UIFeedbackGenerator类,开发人员也可以通过几行代码就实现触碰按钮。

    您将使用UIImpactFeedbackGenerator的子类为精灵碰撞添加一些小小的改变。这个类带有三个设置:lightmediumheavy。当鳄鱼咀嚼菠萝时,添加heavy影响。当菠萝飞出屏幕之外时,添加light影响。

    首先,实例化反馈生成器。在GameScene.swift中,在方法didMove()之前添加以下属性:

    let chomp = UIImpactFeedbackGenerator(style: .heavy)
    let splash = UIImpactFeedbackGenerator(style: .light)`
    

    接下来,使用impactOccurred()方法触发反馈。

    找到update()方法,在run(splashSoundAction)下方,添加以下内容:

    splash.impactOccurred()
    

    接下来,找到didBegin()并在run(nomNomSoundAction)下面添加以下内容:

    chomp.impactOccurred()
    

    在iPhone 7上编译和运行游戏,感受触觉反馈。

    如果您想了解更多关于触觉反馈的信息,请查看这个简短的视频教程,iOS 10:提供触觉反馈

    增加一些难度

    玩了几轮后,游戏似乎有点轻松。你会很快找到一个合适的位置,切断三根葡萄藤,然后喂养鳄鱼。

    让我们通过使用您之前设置的常量CanCutMultipleVinesAtOnce来让游戏的难度增大。

    GameScene.swift中,在GameScene类定义的顶部添加最后一个属性:

    private  var vineCut = false
    

    找到checkIfVineCutWithBody()方法,并在方法的顶部添加下面的if语句:

    if vineCut && !GameConfiguration.CanCutMultipleVinesAtOnce {
      return
    }
    

    将下面这行代码添加到同一方法的底部:

    vineCut = true
    

    找到touchesMoved()方法,并在该方法上面添加下面的方法:

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
      vineCut = false
    }
    

    这样,当用户触摸屏幕时,您将重置vineCut

    编译构建并运行游戏。你现在应该看到,每次滑动时,只能剪断一根葡萄藤。要剪切另一根,你必须抬起手指,然后再次滑动。

    从哪里来?

    在这里下载完成的示例项目

    但不要停止!尝试添加新关卡、不同的葡萄藤,还可以显示分数和游戏用时。

    如果您想了解更多关于SpriteKit的信息,请务必查看我们的书籍,“ 2D Apple Games”

    如果您有任何问题或意见,请随时加入以下讨论!

    球队

    www.raywenderlich.com 上的每个教程都是由专门的开发人员团队创建的,具有高质量标准。本教程的团队成员有:

    相关文章

      网友评论

        本文标题:做一个类似Cut The Rote 的游戏(五)

        本文链接:https://www.haomeiwen.com/subject/qytisxtx.html