牛叉的demo

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

2017-09-18  本文已影响31人  34码的小孩子

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

重置游戏

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

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 上的每个教程都是由专门的开发人员团队创建的,具有高质量标准。本教程的团队成员有:

上一篇下一篇

猜你喜欢

热点阅读