Фон: Я нашел один из сеансов Apple WWDC под названием «AVAudioEngine in Practice» и пытаюсь сделать что-то похожее на последнюю демонстрацию, показанную в 43:35 (https://youtu.be/FlMaxen2eyw?t=2614). Я использую SpriteKit вместо SceneKit, но принцип тот же: я хочу генерировать сферы, бросать их вокруг и когда они сталкиваются с движком, играет звук, уникальный для каждой сферы.Подробная информация об использовании AVAudioEngine
Проблема:
Я хочу уникальное AudioPlayerNode прикрепленного к каждому SpriteKitNode, так что я могу играть разные звуки для каждой сферы. В настоящее время, если я создаю две сферы и задаю другой шаг для каждого из их AudioPlayerNode, кажется, что воспроизводится только последний созданный AudioPlayerNode, даже когда происходит слияние исходной сферы. Во время демонстрации он упоминает «Я связываю игрока, посвященного игрока каждому шару». Как мне это сделать?
Звуковые клики/артефакты каждый раз, когда происходит новое столкновение. Я предполагаю, что это связано с AVAudioPlayerNodeBufferOptions и/или с тем фактом, что я пытаюсь создавать, планировать и потреблять буферы очень быстро каждый раз, когда происходит контакт, что не самый эффективный метод. Какая была бы хорошая работа для этого?
Код: Как упоминалось в видео, «... за каждый мяч, который родился в этот мир, новый узел игрок также создается». У меня есть отдельный класс для сфер, с помощью метода, который возвращает SpriteKitNode, а также создает AudioPlayerNode каждый раз, когда она называется:
class Sphere {
var sphere: SKSpriteNode = SKSpriteNode(color: UIColor(), size: CGSize())
var sphereScale: CGFloat = CGFloat(0.01)
var spherePlayer = AVAudioPlayerNode()
let audio = Audio()
let sphereCollision: UInt32 = 0x1 << 0
func createSphere(position: CGPoint, pitch: Float) -> SKSpriteNode {
let texture = SKTexture(imageNamed: "Slice")
let collisionTexture = SKTexture(imageNamed: "Collision")
// Define the node
sphere = SKSpriteNode(texture: texture, size: texture.size())
sphere.position = position
sphere.name = "sphere"
sphere.physicsBody = SKPhysicsBody(texture: collisionTexture, size: sphere.size)
sphere.physicsBody?.dynamic = true
sphere.physicsBody?.mass = 0
sphere.physicsBody?.restitution = 0.5
sphere.physicsBody?.usesPreciseCollisionDetection = true
sphere.physicsBody?.categoryBitMask = sphereCollision
sphere.physicsBody?.contactTestBitMask = sphereCollision
sphere.zPosition = 1
// Create AudioPlayerNode
spherePlayer = audio.createPlayer(pitch)
return sphere
}
Вот мой Audio Class, с которой я создаю AudioPCMBuffers и AudioPlayerNodes
class Audio {
let engine: AVAudioEngine = AVAudioEngine()
func createBuffer(name: String, type: String) -> AVAudioPCMBuffer {
let audioFilePath = NSBundle.mainBundle().URLForResource(name as String, withExtension: type as String)!
let audioFile = try! AVAudioFile(forReading: audioFilePath)
let buffer = AVAudioPCMBuffer(PCMFormat: audioFile.processingFormat, frameCapacity: UInt32(audioFile.length))
try! audioFile.readIntoBuffer(buffer)
return buffer
}
func createPlayer(pitch: Float) -> AVAudioPlayerNode {
let player = AVAudioPlayerNode()
let buffer = self.createBuffer("PianoC1", type: "wav")
let pitcher = AVAudioUnitTimePitch()
let delay = AVAudioUnitDelay()
pitcher.pitch = pitch
delay.delayTime = 0.2
delay.feedback = 90
delay.wetDryMix = 0
engine.attachNode(pitcher)
engine.attachNode(player)
engine.attachNode(delay)
engine.connect(player, to: pitcher, format: buffer.format)
engine.connect(pitcher, to: delay, format: buffer.format)
engine.connect(delay, to: engine.mainMixerNode, format: buffer.format)
engine.prepare()
try! engine.start()
return player
}
}
в моем GameScene классе я тогда проверить на столкновение, планировать буфер и играть AudioPlayerNode, если контакт произошел
func didBeginContact(contact: SKPhysicsContact) {
let firstBody: SKPhysicsBody = contact.bodyA
if (firstBody.categoryBitMask & sphere.sphereCollision != 0) {
let buffer1 = audio.createBuffer("PianoC1", type: "wav")
sphere.spherePlayer.scheduleBuffer(buffer1, atTime: nil, options: AVAudioPlayerNodeBufferOptions.Interrupts, completionHandler: nil)
sphere.spherePlayer.play()
}
}
Я новичок в S wift и только имеют базовые знания программирования, поэтому любое предложение/критика приветствуется.
Хотя эта ссылка может ответить на этот вопрос, то лучше включить основные части ответа здесь и предоставить ссылку для справки. Ответные ссылки могут стать недействительными, если связанная страница изменится. - [Из обзора] (/ review/low-quality-posts/11350414) –
@BeauNouvelle Я отредактировал ответ с полным протестированным кодом и дополнительной функцией – triple7