Unity下落式音游实现

您所在的位置:网站首页 ae如何卡音乐节奏 Unity下落式音游实现

Unity下落式音游实现

2024-03-11 20:45| 来源: 网络整理| 查看: 265

Unity下落式音游实现——(5)根据音乐生成滑块 前期准备

终于到了最激动人心的时刻!仔细回忆需求,“需要在对应节奏处生成滑块”,其实就是在固定的时间点生成滑块。可以用一个dictionary存储对应时间点和生成的滑块类型,然后在update中每帧记录运行时间,到点了就生成对应的滑块。easy!right?

但这样似乎不能很好地满足某些需求,比如根据难度不同音乐播放速度会变化、音乐并不是连续播放,音乐与音乐会有停顿,同时得实现回放功能。对上述问题,好像不难想到对应解决办法:在每帧记录运行时间时乘上一个表示难度的系数、根据需求添加dictionary中的时间点。有没有更方便的做法呢?

答案就是这款插件:Koreographer!

插件介绍 Koreograpghy Editor

打开Window->Koreograpghy Editor 请添加图片描述

Koreograpghy包含音乐资源和对应的一系列音乐事件,下文中提到的Koreograpghy

新建一个Ky,将你想要处理的音乐拖进Audio Clip里。此时窗口上会出现音乐的波形图(不知道是不是叫这个)。白线表示一个beat(beat的长度和Tempo有关)

Tempo和音乐的节奏有关,需要提前和音乐方沟通(没记错的话120BPM是四四拍)Tempo越大,白线就会越密集。但注意不要出于降低时间间隔的原因去调大Tempo,可以去修改Snap To Beat1 Divide beat by;左下角Snap To Beat1 Divide beat by可以调整两根白线之间的小白线个数;可以点击波形图上方显示数字的小绿框(或小蓝框)切换时间轴的统计形式(有时间、sample数等)

之后新建一个track,点Track Event ID旁边的New,新建一个音乐事件。Payload可以理解为该事件的返回值,之后双击波形图中的小白线,小白线上就多了条小红杠,表示已经在这个时间点上设置了一个音乐事件。再点一下小红杠,便可以设置具体数值

tips:改变Tempo并不会影响已经设置好的Event,虽然小红杠不在小白线上会显得有点奇怪

等等!我们是不是忘了什么?滑块移动需要时间,那是不是应该要在对应节奏之前提前一点时间设置event呢?那不同难度下的“提前量”也不一样,难道要设置三个Koreograpghy吗?

第一个问题:正确的,对于常规需求(不分段也不回放)而言,只需简单地将event提前就好了(将event提前很简单,在Koreograpghy Editor中也不难实现,按正常节奏设置了event之后,选中全部event,一起往前拉)。需要注意音乐资源的开头需要有一段让滑块移动的空白期

但对于我这个奇怪需求而言,确实不能只是简单地将event提前。原因是会有一些属于下个分段的滑块被提前生成到上一个分段中,在模式切换时这些滑到一半的滑块需要清除,而播放下一段音乐时这部分滑块又需要在轨道的正确位置(不在起点)上被显示。因此需要特殊处理(有兴趣的见实现回放功能)

第二个问题:错误的,只需设置一系列标准速度下的event,之后调整难度时随着整体音乐的播放速度变化,提前量自然会正确变化。

Koreographer组件

在SceneController(或者别的空物体上)添加组件:Koreographer和Simple Music Player(设置好Koreograpghy和Target Koreographer)

根据需求,将Track event的返回值设置成int,分别对应7个鼓;因为音乐中都是两个鼓同时被敲下,于是创建了两个Track event,时间点一样,返回值不一样;另外需求中将音乐分为多个小段,每个小段结束后会停顿一段时间,显示一些信息,再创建了一个Track event(命名为MissionClips)记录了关卡切分时间点

之后就进入代码部分了

应用Event

在使用Event之前,需要在脚本中注册单例,使用方法类似观察者模式;同时需要声明一个string数组,记录触发的eventID

// SceneController.cs public string[] eventID; void Start() { // 注册单例 Koreographer.Instance.RegisterForEvents(eventID[0], genSlider); Koreographer.Instance.RegisterForEvents(eventID[1], genSlider); Koreographer.Instance.RegisterForEvents(eventID[2], controlPlaying); }

修改genSlider参数

void genSlider(KoreographyEvent eventCallback) { // 保持和原来参数一致 int OrbitNum = eventCallback.GetIntValue(); ... } 串联关卡 // SenceController.cs void Start() { // 获取组件并调速用 audio = GetComponent(); audio.pitch = SlideTime.standardTime / movingTime; music.pitch = SlideTime.standardTime / movingTime; ... // 直接播放 audio.play(); }

pitch是AudioSource的速度变量(虽然官方文档中将它描述为音高),默认值是1

目前为止已经实现了音游的基本功能了

实现回放功能

这一部分真的困扰了我很长时间…如果你的需求只是简单的一首歌播完并且只会生成一种类型的滑块(指交互方式),那么你可以(幸运地)跳过这一部分,如果你想了解奇奇怪怪的需求(和奇奇怪怪的实现方法),那请往下看

仔细回忆需求,首先进入演示阶段,该阶段玩家不能操作(滑块可见且自己销毁),演示阶段结束后,进入游戏阶段,此时播放和演示阶段一样的音乐,玩家进行操作(滑块不可见且不能自动销毁)

书接上回,我们不能只是简单地将event提前。那怎么办呢?难道又要直接暴力,在每个分段前加上一小段空白期吗?

我选择用两个AudioSource,一个AudioClip开头加了一小段空白期,另一个AudioClip没有加空白期,静音,挂载了Koreographer(负责控制滑块生成)。两个AudioClip同时开始播放,当没静音的AudioSource播放到对应节奏时,滑块刚好到达鼓盘处,也不会存在提前生成下一小段滑块的问题

在SenceController修改audio部分

void Start() { // 将另一个AudioSource挂在了子物体上 Transform[] t = GetComponentsInChildren(); music = t[1].GetComponent(); ... } // 两个audio同时播放或停止 public void Play() { //StartCoroutine(fixMusicOffset()); audio.Play(); music.Play(); } public void Pause() { audio.Pause(); music.Pause(); }

接下来时实现回放功能,有如下几个方案:

一、暴力。手动将音频按照关卡分成很多小段,然后将每个小段复制一遍,最后将所有小段缝合到一起。否决,程序员的自尊不允许我采取如此低效的方法(事后回想还不如直接暴力省事…)

二、将音乐时间轴往回调。在同一个Koreograpghy进行操作,进入game阶段时将音乐往回调到上一段show开始的地方

听起来很直观,而且AudioSource提供了Time或timeSamples变量,直接修改该变量就能重定位音乐播放位置

三、用两个不同的挂了koregrapher的gameobject分别负责播放show状态和game状态的音乐。一条暂停,另一条播放到另一条暂停的地方

最终选择了第三种方案,因为(当时觉得)直观上比较简单易实现。于是我新创了一对AudioSource(之前提到的实现提前量)

由于为了分段设置了两个几乎一样的的koregrapher,需要区分game状态和status状态(用一个bool值),奇数次收到关卡切换的信息时暂停,偶数次播放;同时利用协程,达到慢开始(让之前的滑块滑完+两段音乐间过渡期)、慢结束(让音乐放完)的效果,在结束时改变游戏状态并广播

新增的那个koregrapher的内容就是SenceController中controlPlaying()的部分,除了ifBegin的初值不同,奇数播偶数停

// SenceController.cs void controlPlaying(KoreographyEvent koreographyEvent) { if(!ifBegin) { audio.Pause(); StartCoroutine(showlyMusicPause()); // 在game到show间过渡时间也不可击鼓 ifBegin = true; } else if(ifBegin) { ifBegin = false; status = MissionStatus.show; StartCoroutine(showlyPauseInput()); StartCoroutine(showlyBegin(koreographyEvent)); } } // 协程函数就不放上来了 Unity下落式音


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3