在 SpriteKit 中为弹跳球创建音效

Posted

技术标签:

【中文标题】在 SpriteKit 中为弹跳球创建音效【英文标题】:Creating sound effects for bouncing ball in SpriteKit 【发布时间】:2016-11-13 18:05:00 【问题描述】:

我的 Swift 游戏使用 SpriteKit 和 SKPhysics 为一个小红球制作动画,该小红球在游戏过程中经常与其他物理体发生碰撞。我想在球碰撞时创造一种自然的弹跳音效。我目前有一种相当混乱的方法来执行此操作,并且在使用它时会出现明显的延迟,当我禁用声音时会消失:

var bounceSoundPlayers = [AVAudioPlayer!]()

func buildBounceSound() 
  let path = Bundle.main.path(forResource: "Bounce.mp3", ofType:nil)!
  let url = URL(fileURLWithPath: path)
  for _ in 0...2 
    do 
      let sound = try AVAudioPlayer(contentsOf: url)
      sound.prepareToPlay()
      bounceSoundPlayers.append(sound)
     catch 
      fatalError("couldn't load music file")
    
  

这将创建三个带有声音“Bounce.mp3”的 AVAudioPlayer,并在它们上运行 prepareToPlay() 方法。然后它将它们存储在一个名为bounceSoundPlayers 的数组中,以便我以后可以使用它们。然后我有一个 didBeginContact 方法,每当任何东西与任何东西发生碰撞时都会调用它:

func didBegin(_ contact: SKPhysicsContact) 
  if contact.collisionImpulse > 0.45 && defaults.bool(forKey: "SFX") 
    if ((contact.bodyA.node!.name == "ball" && contact.bodyB.node!.name == "permeable platform") ||
      (contact.bodyB.node!.name == "ball" && contact.bodyA.node!.name == "permeable platform") ||
      (contact.bodyA.node!.name == "ball" && contact.bodyB.node!.name == "ring") ||
      (contact.bodyB.node!.name == "ball" && contact.bodyA.node!.name == "ring"))
      &&
      ball.collidingWithPermeable 
        playBounceSound(contact.collisionImpulse/8<=1 ? contact.collisionImpulse/8 : 1)
    

    if (contact.bodyA.node!.name == "ball" && contact.bodyB.node!.name == "impermeable platform") ||
      (contact.bodyB.node!.name == "ball" && contact.bodyA.node!.name == "impermeable platform") ||
      (contact.bodyA.node!.name == "ball" && contact.bodyB.node!.name == "wall") ||
      (contact.bodyB.node!.name == "ball" && contact.bodyA.node!.name == "wall") 
      playBounceSound(contact.collisionImpulse/5<=1 ? contact.collisionImpulse/5 : 1)
    
  

这个方法的基本作用是检查每次碰撞,如果球与正确的平台或墙壁碰撞,它会调用 playBounceSound(volume: CGFloat) 方法,其音量与碰撞力成正比。因此,如果球与平台轻轻碰撞,体积会比非常强烈的碰撞更安静。这是 playBounceSound 方法:

var bouncePlayerIndex = Int(0)

func playBounceSound(_ volume: CGFloat) 
  let previousIndex = bouncePlayerIndex - 1 >= 0 ? bouncePlayerIndex - 1 : 2
  if bounceSoundPlayer[previousIndex].isPlaying 
    if bounceSoundPlayer[previousIndex].currentTime > 0.1 
      bounceSoundPlayer[bouncePlayerIndex].volume = Float(volume)
      bounceSoundPlayer[bouncePlayerIndex].play()
    
  
  else 
    bounceSoundPlayer[bouncePlayerIndex].volume = Float(volume)
    bounceSoundPlayer[bouncePlayerIndex].play()
  

  bouncePlayerIndex += 1
  if bouncePlayerIndex > 2 bouncePlayerIndex = 0

基本上,这个方法的作用是循环遍历我们之前创建的三个 AVAudioPlayer,它使用一个索引整数。每次调用它时,它都会告诉bouncePlayerIndex 处的bounceSoundPlayer 以给定的音量播放()。然后它增加bouncePlayerIndex,以便下次调用它时,它使用不同的AVAudioPlayer。如果bouncePlayerIndex > 2,它会回到0。使用三个AVAudioPlayer可以让我同时播放多个弹跳——即弹跳声音可以在最后一个结束之前开始,例如当球落在平台上并弹跳高,然后低弹越来越低,越来越频繁,直到它停止弹跳。

我确信有比使用 AVAudioPlayers 数组更好的方法。请帮忙。

【问题讨论】:

你看过这个:largepixels.net/post/1020 吗? 【参考方案1】:

斯威夫特 3

这是我发现播放声音的最佳方式。它们可以重叠,您可以同时播放任意数量的游戏。快速简单。

1.) 确保导入框架

import AVFoundation

2.) 创建函数

// my sound file is named shatter.mp3
func shatterSound() 
    if let soundURL = Bundle.main.url(forResource: "shatter", withExtension: "mp3") 
        var mySound: SystemSoundID = 0
        AudioservicesCreateSystemSoundID(soundURL as CFURL, &mySound)
        AudioServicesPlaySystemSound(mySound);
    

3.) 在需要的地方调用函数

shatterSound()

【讨论】:

来自文档:“无法同时播放:一次只能播放一种声音”。 developer.apple.com/documentation/audiotoolbox/…

以上是关于在 SpriteKit 中为弹跳球创建音效的主要内容,如果未能解决你的问题,请参考以下文章

SpriteKit给游戏弹跳角色添加一个高度标示器

覆盖 SpriteKit 中的碰撞

如何使用 Actionscript 3 为在 z 轴上弹跳的球设置动画?

Clojurescript:制作弹跳球的功能性方法

SpriteKit 目标 c 节点仅在 x 轴上移动

Spritekit 添加音效