在游戏开发中,你是否也想将音乐旋律变为漂亮的图形显示?就像这样的效果。

或者这样的效果。

还有这样的效果。

但是,我们今天不会讨论怎样实现上面的那些效果(可以用插件实现,哈哈哈…),而是聊一下最朴素的效果实现原理。了解了原理,再复杂的效果也可以实现。最朴素的效果,见下图,哈哈哈哈~

简单来说,我们要实现的东西就是几个条状的UI,跟随音乐的旋律,进行上下缩放。而旋律,其实就是声音中的数据,就是一个int值,只要取到这个数据,就可以将数据通过一些计算,映射为UI的大小。
下面整理一下要做的事情(以下事情都是在Update中做的):
每一帧去取音频数据
查看Unity的 AudioSource API,我们发现有一个 GetOutputData
方法,获取音频输出数据,返回类型是一个 float 数组。
取到音频数据后,将数据进行标准化处理
就是找出音频数据中最大的值,然后用每一个值,除以最大值,就可以将所有音频数据映射为 0 到 1 之间的数值大小,返回新的 float 数组。
有了音频数据大小,我们就可以映射为UI的条形图的大小
假设我们限定条状UI的大小最小为10,最大为200,再配合上面取到的音频数据,就可以设定UI的大小了。假设有10个条,那只需要使 float 数组中前10个数值就行。
其中第二步还可以加入更多计算处理,最后只要映射到0~1之间的数值,就可以用,最终是要表现效果,并不是一定要准确的表示出音频的数据,只要该高的时候高,该低的时候低,那就没问题,至于高到多少,低到多少,都是相对的,并不重要。
下面是示例代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
| using UnityEngine; using System.Collections; using System.Collections.Generic; using UnityEngine.UI;
public class AudioV : MonoBehaviour { public AudioSource audioSource; public float minSize = 10; public float maxSize = 200; public float lerpSpeed = 20.0f; private List<RectTransform> barList = new List<RectTransform>();
private float[] sampleData = new float[64];
private void Start() { RectTransform[] childs = GetComponentsInChildren<RectTransform>(); for (int i = 1; i < childs.Length; ++i) { barList.Add(childs[i]); } }
private float[] NormalizeData(float[] input) { float[] output = new float[input.Length]; float max = 0; float min = 0; for (int i = 0; i < input.Length; i++) { max = Mathf.Max(max, input[i]); min = Mathf.Min(min, input[i]); }
float len = max - min;
for (int i = 0; i < input.Length; i++) { if (len <= 0) { output[i] = 0; } else { output[i] = (input[i] - min) / len; } }
return output; }
void Update() { float[] normalizedData = null;
audioSource.GetOutputData(sampleData, 0);
normalizedData = NormalizeData(sampleData);
for (int i = 0; i < barList.Count; ++i) { float newHeight = minSize + (maxSize - minSize) * normalizedData[i]; float currHeight = Mathf.Lerp(barList[i].sizeDelta.y, newHeight, Time.deltaTime * lerpSpeed);
barList[i].SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, currHeight); } } }
|
在上面的代码中,因为我们是每帧采样,所以UI变化会很剧烈,所以我们这里用了一个Lerp去控制变化速度,但是这样也会带来一个问题就是变化幅度的减小。大家可以自己试一下,自己尝试改进。
如果你用的不是 AudioSource,用了别的音频插件,只要取到音频的采样数据,用法都是一样的。
基本的原理已经介绍完,更复杂的表现形式,也就是改变音频数据的映射形式而已~
如果你有更好的改进方法,欢迎在下面留言~
上文中用到的图片分别来自Unity插件 3D Visualizer Spectrum Vu Meter 和插件 Sound Reactor - Standard