【发布时间】: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 吗?
标签: swift sprite-kit avfoundation collision-detection avaudioplayer