2

我的Swift遊戲使用SpriteKit和SKPhysics來動畫在遊戲過程中經常與其他physicsBodys碰撞的小紅球。每當球發生碰撞時,我都想創建一個自然的彈跳音效。我現在有這樣做的一個比較無序的方法,並有一個顯著的滯後明顯,而使用它,當我禁用聲音會消失:在SpriteKit中創建彈跳球的聲音效果

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") 
    } 
    } 
} 

這將創建三個AVAudioPlayers有聲「Bounce.mp3」並運行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(體積: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} 
} 

基本上,這個方法所做的就是通過我們前面使用索引整數創建的三個AVAudioPlayers週期。每次調用它時,它都會告知bouncePlayerIndex的bounceSoundPlayer在給定音量處播放()。然後它會增加bouncePlayerIndex,以便下次調用它時,它會使用不同的AVAudioPlayer。如果bouncePlayerIndex> 2,它會回到0.使用三個AVAudioPlayers可以同時彈奏多次彈跳 - 也就是說,彈跳音可以在最後一次彈跳結束之前開始,例如當球落在平臺上並彈跳高時,然後降低更低和更頻繁,直到它停止彈跳。

我相信有一個比AVAudioPlayers數組更好的方法。請幫忙。

+0

你見過這個:http://largepixels.net/post/1020? – Confused

回答

0

斯威夫特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()