Unity Koreographer 之二 音乐制作插件中 Demo 的实现过程说明演示
目录
Unity Koreographer 之二 音乐制作插件中 Demo 的实现过程说明演示
一、Koreographer 简单介绍
二、开发环境
三、注意事项
四、Demo 演示效果预览
五、分步演示说明实现步骤
1、基本场景和数据搭建
2、球根据节拍跳动效果
3、粒子特效根据节拍设置的时间span,来控制粒子发射
4、正方体逐渐变化的效果
5、节拍上的文字获取并展示效果
6、灯光随着节拍一闪一闪的效果
7、随着节拍颜色的动态变化
8、全部场景效果叠加起来,就是Demo的整体效果
一、Koreographer 简单介绍
Koreographer? 官网:Sonic Bloom
??? Koreographer Professional Edition? 简化了在视频游戏中同步游戏玩法和音乐的过程。它简单的编辑界面允许你将音乐的节奏、节拍、音符、音量和其他动态元素映射到游戏中的事件中。
??? Koreographer 可以用来创造节奏游戏,使任何游戏更加电影化,用音乐增强游戏环境,并创造新的控制和音乐驱动的游戏玩法。
??? Koreographer功能:
??????? 1.创建节奏游戏,启用唇形同步或以最小的努力为游戏添加字幕 ??????? 2.准确地将游戏中的事件同步到游戏音乐中的不同点 ??????? 3.快速创建新的音乐游戏和效果 ?
Koreographer Professional Edition 下载建议去 Unity Asset Store 下载,这里下载路径仅供学习使用,商用建议购买正版。
Koreographer Professional Edition 1.6.1 学习下载地址:审核中
本节主要是介绍,Koreographer? 中的 Demo 实现过程,目的是熟悉 Koreographer? 和 相关接口,便于后面 Koreographer? 的深入学习和使用。
有时间你也可以参看官网的学习更多,Koreographer? 官网:Sonic Bloom。
二、开发环境
1、 Koreographer Professional Edition 1.6.1
2、Unity 2019.3.13f1
三、注意事项
1、导入后 Koreographer? 有四个文件夹 Editor Default Resources 、Gizmos、Koreographer、Plugins ,做好不要新建一个文件夹,再把他们统一在该文件下,这样可能会导致一些未知错误,或者没有报错但是一些功能用不了
四、Demo 演示效果预览
五、分步演示说明实现步骤
1、基本场景和数据搭建
1)在场景中,搭建场景如下
2)在工程中新建一个Koreography,用来添加音频和相关数据、节拍事件设置
?
?3)在场景中添加一个 GameObject ,命名为 Music Player,添加组件,Koreographer,AudioSource,Simple Music Player, Simple Music Player 上对应添加之前新建的 Koreography
2、球根据节拍跳动效果
1)在场景中,两个球体,并在球体上添加刚体
?
2)在工程中新建一个 Koreohgraphy Track ,设置 Event ID ,并赋值给?Koreohgraphy
?
3)选中?Koreohgraphy ,点击 Open In Koreography Editor,选择对应 Koreohgraphy Track 的 Event ID,进行节拍设置,这里设置 Payload 为 float ,值可以根据需要设置大小(Demo中没有使用该值,获取可以使用 evt.GetFloatValue() 获取自己对用设置的值)
?
4)这样对应的 Koreohgraphy Track 的 Event List也会被对应设置上
?
5)新建脚本,用来获取对应事件,使得小球跳动,并把脚本添加到,小球上,对应设置 Event ID
//----------------------------------------------
// Koreographer
// Copyright ? 2014-2020 Sonic Bloom, LLC
//----------------------------------------------
using UnityEngine;
namespace SonicBloom.Koreo.Demos
{
[RequireComponent(typeof(Rigidbody))]
[AddComponentMenu("Koreographer/Demos/Musical Impulse")]
public class MusicalImpulse : MonoBehaviour
{
[EventID]
public string eventID;
public float jumpSpeed = 3f;
Rigidbody rigidbodyCom;
void Start()
{
// Register for Koreography Events. This sets up the callback.
Koreographer.Instance.RegisterForEvents(eventID, AddImpulse);
rigidbodyCom = GetComponent<Rigidbody>();
}
void OnDestroy()
{
// Sometimes the Koreographer Instance gets cleaned up before hand.
// No need to worry in that case.
if (Koreographer.Instance != null)
{
Koreographer.Instance.UnregisterForAllEvents(this);
}
}
void AddImpulse(KoreographyEvent evt)
{
// Add impulse by overriding the Vertical component of the Velocity.
Vector3 vel = rigidbodyCom.velocity;
//vel.y = jumpSpeed + evt.GetFloatValue();
vel.y = jumpSpeed ;
rigidbodyCom.velocity = vel;
}
}
}
?
6)运行场景,效果如上
3、粒子特效根据节拍设置的时间span,来控制粒子发射
1)在场景中,添加两个粒子效果
2)同理新建 Koreohgraphy Track,并设置到? Koreohgraphy 上
?
3)编辑 Koreohgraphy 对应 Koreohgraphy Track 的节拍事件,这里根据节拍,设置时间跨度
4)新建脚本,根据时间跨度来设置粒子发射数量,脚本挂在到粒子上,并对应赋值
?
//----------------------------------------------
// Koreographer
// Copyright ? 2014-2020 Sonic Bloom, LLC
//----------------------------------------------
using UnityEngine;
namespace SonicBloom.Koreo.Demos
{
[RequireComponent(typeof(ParticleSystem))]
[AddComponentMenu("Koreographer/Demos/Emit Particles On Span")]
public class EmitParticlesOnSpan : MonoBehaviour
{
[EventID]
public string eventID;
public float particlesPerBeat = 100;
ParticleSystem particleCom;
int lastEmitFrame = -1;
void Start()
{
particleCom = GetComponent<ParticleSystem>();
// Register for Koreography Events. This sets up the callback.
Koreographer.Instance.RegisterForEvents(eventID, OnParticleControlEvent);
}
void OnDestroy()
{
// Sometimes the Koreographer Instance gets cleaned up before hand.
// No need to worry in that case.
if (Koreographer.Instance != null)
{
Koreographer.Instance.UnregisterForAllEvents(this);
}
}
void OnParticleControlEvent(KoreographyEvent evt)
{
// If two Koreography span events overlap, this can be called twice in the same frame.
// This check ensures that we only ask the particle system to emit once for any frame.
if (Time.frameCount != lastEmitFrame)
{
// Spans get called over a specified amount of music time. Use Koreographer's beat delta
// to calculate the number of particles to emit this frame based on the "particlesPerBeat"
// rate configured in the Inspector.
int particleCount = (int)(particlesPerBeat * Koreographer.GetBeatTimeDelta());
Debug.Log(GetType()+ "/OnParticleControlEvent()/ Koreographer.GetBeatTimeDelta:" + Koreographer.GetBeatTimeDelta());
Debug.Log(GetType()+ "/OnParticleControlEvent()/ particleCount:" + particleCount);
// Emit the calculated number of particles!
particleCom.Emit(particleCount);
lastEmitFrame = Time.frameCount;
}
}
}
}
5)运行场景,效果如上
4、正方体逐渐变化的效果
1)在场景中,添加两个靠边 Cube
2)同理新建 Koreohgraphy Track,并设置到? Koreohgraphy 上
?
3)编辑 Koreohgraphy 对应 Koreohgraphy Track 的节拍事件,这里根据节拍,设置时间跨度上的Curve 值
?
4)新建脚本,根据时间跨度上的Curve 的 Value来动态变化 Cube 大小,脚本挂在到Cube上,并对应赋值
//----------------------------------------------
// Koreographer
// Copyright ? 2014-2020 Sonic Bloom, LLC
//----------------------------------------------
using UnityEngine;
namespace SonicBloom.Koreo.Demos
{
[AddComponentMenu("Koreographer/Demos/Cube Scaler")]
public class CubeScaler : MonoBehaviour
{
[EventID]
public string eventID;
public float minScale = 0.5f;
public float maxScale = 1.5f;
void Start()
{
// Register for Koreography Events. This sets up the callback.
Koreographer.Instance.RegisterForEventsWithTime(eventID, AdjustScale);
}
void OnDestroy()
{
// Sometimes the Koreographer Instance gets cleaned up before hand.
// No need to worry in that case.
if (Koreographer.Instance != null)
{
Koreographer.Instance.UnregisterForAllEvents(this);
}
}
void AdjustScale(KoreographyEvent evt, int sampleTime, int sampleDelta, DeltaSlice deltaSlice)
{
if (evt.HasCurvePayload())
{
// Get the value of the curve at the current audio position. This will be a
// value between [0, 1] and will be used, below, to interpolate between
// minScale and maxScale.
float curveValue = evt.GetValueOfCurveAtTime(sampleTime);
transform.localScale = Vector3.one * Mathf.Lerp(minScale, maxScale, curveValue);
Debug.Log(GetType()+ "/AdjustScale()/ curveValue : "+ curveValue);
Debug.Log(GetType()+ "/AdjustScale()/ transform.localScale : " + transform.localScale);
}
}
}
}
?
5)运行场景,效果如上
5、节拍上的文字获取并展示效果
1)场景新建一个GameObject(这里用的 GUI,你也可以使用 UGUI)
?
?2)同理新建 Koreohgraphy Track,并设置到? Koreohgraphy 上
3)编辑 Koreohgraphy 对应 Koreohgraphy Track 的节拍事件,这里根据节拍,设置时间跨度上的Text 值
4)新建脚本,根据时间跨度上的 Text的 Value来动态设置 GUI 文本,脚本挂在到场景中,并对应赋值
//----------------------------------------------
// Koreographer
// Copyright ? 2014-2020 Sonic Bloom, LLC
//----------------------------------------------
using UnityEngine;
namespace SonicBloom.Koreo.Demos
{
[AddComponentMenu("Koreographer/Demos/UI Message Setter")]
public class UIMessageSetter : MonoBehaviour
{
[EventID]
public string eventID;
public GUIStyle style;
KoreographyEvent curTextEvent;
void Start()
{
// Register for Koreography Events. This sets up the callback.
Koreographer.Instance.RegisterForEventsWithTime(eventID, UpdateText);
}
void OnDestroy()
{
// Sometimes the Koreographer Instance gets cleaned up before hand.
// No need to worry in that case.
if (Koreographer.Instance != null)
{
Koreographer.Instance.UnregisterForAllEvents(this);
}
}
void OnGUI()
{
if (curTextEvent != null)
{
// Use the entire screen size as the draw surface. Draw location is determined by
// the GUIStyle.
GUI.Box(new Rect(0,0, Screen.width, Screen.height), curTextEvent.GetTextValue(), style);
}
}
void UpdateText(KoreographyEvent evt, int sampleTime, int sampleDelta, DeltaSlice deltaSlice)
{
// Verify that we have Text in the Payload.
if (evt.HasTextPayload())
{
// Set the text if we have a text event!
// We can get multiple events called at the same time (if they overlap in the track).
// In this case, we prefer the event with the most recent start sample.
if (curTextEvent == null ||
(evt != curTextEvent && evt.StartSample > curTextEvent.StartSample))
{
// Store for later use and comparison.
curTextEvent = evt;
}
// Clear out the text if our event ended this musical frame.
if (curTextEvent.EndSample < sampleTime)
{
// Remove so that the above timing logic works when the audio loops/jumps.
curTextEvent = null;
}
}
}
}
}
5)运行场景,效果如上
6、灯光随着节拍一闪一闪的效果
?
1)在场景中添加 几盏 SpotLight,布局
?
2)新建脚本,根据Koreographer.GetBeatTime() 获取拍子,然后对应开关等即可
//----------------------------------------------
// Koreographer
// Copyright ? 2014-2020 Sonic Bloom, LLC
//----------------------------------------------
using UnityEngine;
namespace SonicBloom.Koreo.Demos
{
[AddComponentMenu("Koreographer/Demos/Tempo Switch")]
public class TempoSwitch : MonoBehaviour
{
// These should be set up in the inspector.
public Behaviour[] quarterNoteGroup;
public Behaviour[] eighthNoteGroup;
int lastQuarterNote = 0;
int lastEighthNote = -1;
void Update()
{
// The Demo song has a quarter note as it's beat value. This will get us the current
// quarter note!
int curQuarterNote = Mathf.FloorToInt(Koreographer.GetBeatTime());
if (curQuarterNote != lastQuarterNote)
{
// Turn the group on when the beat is an even number.
SwitchGroup(quarterNoteGroup, lastQuarterNote % 2 != 0);
lastQuarterNote = curQuarterNote;
}
// The 'null' value asks Koreographer to look at the beat time of what it considers
// the current "Main" song. These demos use a basic player with a single song and
// define that as the Main song. Therefore there is no need to specify it. The
// '2' parameter, tells Koreographer to divide each beat into 2 equal parts. As the
// base beat value is 4, this will result in eighth notes.
int curEighthNote = Mathf.FloorToInt(Koreographer.GetBeatTime(null, 2));
if (curEighthNote != lastEighthNote)
{
SwitchGroup(eighthNoteGroup, lastEighthNote % 2 != 0);
lastEighthNote = curEighthNote;
}
}
void SwitchGroup(Behaviour[] behaviours, bool bGroupOn)
{
for (int i = 0; i < behaviours.Length; ++i)
{
behaviours[i].enabled = bGroupOn;
}
}
}
}
3)运行场景,效果如上
7、随着节拍颜色的动态变化
?
1)场景使用之前球和正方体的结合场景,新建GameObject物体,来监控颜色变化挂载物体
?2)同理新建 两个 Koreohgraphy Track(一个颜色骤变,一个颜色渐变),并设置到? Koreohgraphy 上
?
3)编辑 Koreohgraphy 对应 Koreohgraphy Track 的节拍事件,这里根据节拍,设置 Color 和 Gradient
?
5)新建脚本,根据节拍设置颜色,脚本挂在到场景中,并对应赋值
//----------------------------------------------
// Koreographer
// Copyright ? 2014-2020 Sonic Bloom, LLC
//----------------------------------------------
using UnityEngine;
namespace SonicBloom.Koreo.Demos
{
[AddComponentMenu("Koreographer/Demos/Color Adjuster")]
public class ColorAdjuster : MonoBehaviour
{
[EventID]
public string eventID;
public Renderer[] objectsToColor;
void Start()
{
// Register for Koreography Events. This sets up the callback.
Koreographer.Instance.RegisterForEventsWithTime(eventID, AdjustColor);
}
void OnDestroy()
{
// Sometimes the Koreographer Instance gets cleaned up before hand.
// No need to worry in that case.
if (Koreographer.Instance != null)
{
Koreographer.Instance.UnregisterForAllEvents(this);
}
}
void AdjustColor(KoreographyEvent evt, int sampleTime, int sampleDelta, DeltaSlice deltaSlice)
{
// We have prepared two kinds of events that work with this system:
// 1) OneOffs that store a Color.
// 2) Spans that store a Gradient.
// Ensure that we have the correct types before proceeding!
if (evt.IsOneOff() && evt.HasColorPayload())
{
// This is a simple Color Payload.
Color targetColor = evt.GetColorValue();
ApplyColorToObjects(ref targetColor);
}
else if (!evt.IsOneOff() && evt.HasGradientPayload())
{
// Access the color specified at the current music-time. This is what
// drives musical color animations from gradients!
Color targetColor = evt.GetColorOfGradientAtTime(sampleTime);
ApplyColorToObjects(ref targetColor);
}
}
void ApplyColorToObjects(ref Color color)
{
for (int i = 0; i < objectsToColor.Length; ++i)
{
objectsToColor[i].material.color = color;
}
}
}
}
5)运行场景,效果如上
8、全部场景效果叠加起来,就是Demo的整体效果
|