请有人帮忙!
我想让我的SKEmitterNode的规模(意思是大小)随着我使用AVAudioPlayer构建到应用程序中的音乐越来越大。现在,这几乎是我对SKEmitterNode的全部,它看起来很棒:
beatParticle?.position = CGPoint(x: self.size.width * 0.5, y: self.size.height * 0.5)
var beatParticleEffectNode = SKEffectNode()
beatParticleEffectNode.addChild(beatParticle!)
self.addChild(beatParticleEffectNode)
所有的查找都在.sks文件中完成。
这里是我在一个连续循环中调用"updateBeatParticle"函数的地方,这样它就可以放在我的代码中,使粒子的比例(意思是大小)随着音乐而变大或变小。
var dpLink : CADisplayLink?
dpLink = CADisplayLink(target: self, selector: "updateBeatParticle")
dpLink?.addToRunLoop(NSRunLoop.currentRunLoop(), forMode: NSRunLoopCommonModes)
func updateBeatParticle(){
//Put code here
}
知道我该怎么做吗?我看了一些教程,比如:https://www.raywenderlich.com/36475/how-to-make-a-music-visualizer-in-ios
然而,我不能完全理解它,因为他们在Obj-C中使用emitterLayer和它,我也对你们这些优秀的人可能有的任何其他想法感兴趣!
警告:以下代码尚未经过测试。请告诉我它是否有效
首先,它看起来像是在使用SpriteKit,因此您可以将更改发射器比例所需的代码放在SKScene
方法update:
中,该方法会像CADisplayLink
一样频繁地自动调用。
基本上,您所需要做的就是根据AVAudioPlayer
通道的体积更新update:
方法中的发射器比例。请注意,音频播放器可能有多个通道在运行,因此您需要平均每个通道的平均功率。
首先。。。
player.meteringEnabled = true
在初始化音频播放器后设置此选项,以便它可以监控频道的级别。
接下来,在更新方法中添加类似的内容。
override func update(currentTime: CFTimeInterval) {
var scale: CGFloat = 0.5
if audioPlayer.playing { // Only do this if the audio is actually playing
audioPlayer.updateMeters() // Tell the audio player to update and fetch the latest readings
let channels = audioPlayer.numberOfChannels
var power: Float = 0
// Loop over each channel and add its average power
for i in 0..<channels {
power += audioPlayer.averagePowerForChannel(i)
}
power /= Float(channels) // This will give the average power across all the channels in decibels
// Convert power in decibels to a more appropriate percentage representation
scale = CGFloat(getIntensityFromPower(power))
}
// Set the particle scale to match
emitterNode.particleScale = scale
}
方法getIntensityFromPower
用于将以分贝为单位的功率转换为更合适的百分比表示。这个方法可以这样声明…
// Will return a value between 0.0 ... 1.0, based on the decibels
func getIntensityFromPower(decibels: Float) -> Float {
// The minimum possible decibel returned from an AVAudioPlayer channel
let minDecibels: Float = -160
// The maximum possible decibel returned from an AVAudioPlayer channel
let maxDecibels: Float = 0
// Clamp the decibels value
if decibels < minDecibels {
return 0
}
if decibels >= maxDecibels {
return 1
}
// This value can be adjusted to affect the curve of the intensity
let root: Float = 2
let minAmp = powf(10, 0.05 * minDecibels)
let inverseAmpRange: Float = 1.0 / (1.0 - minAmp)
let amp: Float = powf(10, 0.05 * decibels)
let adjAmp = (amp - minAmp) * inverseAmpRange
return powf(adjAmp, 1.0 / root)
}
此转换的算法取自此StackOverflow响应https://stackoverflow.com/a/16192481/3222419.