查看原文
其他

细分赛道博出位?奇葩技巧实现跨平台音乐类游戏!

玻璃小屋 COCOS 2022-06-10

音乐是人类的共同语言,音乐游戏因为游戏模式丰富,规则简单,上手容易,一直广受玩家喜爱,经久不衰。北京猎豹基于 Cocos 引擎研发的《钢琴块2》上线后迅速风靡全球,荣登100多个国家\地区下载榜冠军宝座,后又借助 Cocos 强大的跨平台能力发布了微信小游戏版本,亦是掀起全民热潮。


钢琴块2


除去移植和知名作品,移动端音游往往由中小型团队开发,一部分甚至是音游玩家自行组建的开发团队。近期也有不少采用 Cocos 引擎制作的不俗的音乐游戏作品诞生,比如微信创意小游戏《缪斯计划》、《音游诗人》等等。


缪斯计划


音游诗人


重度游戏需要强大的研发实力,而休闲游戏盈利空间小,音乐游戏是介于两者之间的细分品类,成为不少中小团队的选择。

受限于曲库版权、商业模式等,
音乐游戏其实是个不易做的品类,然而一旦成型,带来的是黏性极高的用户与广阔的产品空间,国内也不乏聚焦音游市场的尝试者。


这么好的细分领域,也有不少人尝试,为什么成功者寥寥呢?


其中一个重要的原因就是,各个平台上对于音频控制接口的支持情况参差不齐,想要实现一些高级特性也往往需要很深入的技术积累。当然在原生平台我们可以使用一些成熟的音频库,虽然可能需要付费但总是可以满足绝大部分需求;在 Web 端也可以利用 WebAudio API 来实现很多高级特性。


然而,在微信等小游戏平台上,音频接口的支持往往仅限于播放、暂停、停止等基础接口,封闭的环境也导致几乎无法定制。这令很多希望制作音乐游戏的开发者望而却步。


近日,Cocos 开发者玻璃小屋在中文社区分享了一篇利用 Cocos Creator 3D 制作音乐游戏的教程,很巧妙地利用了离线预计算的方式实现了音频信息的分析和重音打点,并且不依赖运行时特性,无缝支持所有平台,相信可以给开发者们一些启发。


说到预计算的方法来解决问题其实在游戏中并不少见,比如离线烘焙 light map、离线合并模型网格等数据、神经网络训练模型等。但开发者们往往因为思维定势无法跳脱既有框架寻找解决方案,所以受困于各种运行环境的限制束手无策。


希望这篇文章能够让大家在遇到问题时改变思路,从不同的角度看待问题,也许就迎刃而解了。



效果展示



实现过程


1.音乐


在做音乐游戏之前,首先需要确定一点:如何完美地实现音乐与游戏的结合,将音乐的节奏感融入到游戏中,也就是如何将音乐进行处理解析,得到自己想要的数据。


在明确了目标之后,开始查资料。


我在社区看到了 KUOKUO 分享的一篇帖子[来首 Believer放松下],也是一个音乐类的 Demo,效果很震撼,而且是采用 Cocos Creator 3D 制作的。



看了这篇帖子之后,我更有信心了,我想我也一定可以做出来。


我先尝试着按照 KUOKUO [来首 Believer放松下]一文中的方法去写了一下,结果只能支持部分浏览器,在小游戏平台上无法运行。


于是我接着查资料,后续查找资料的过程并不是很顺利,目前这块的资料比较少,我没有找到相关的例子、资料以及 js 相关音效处理库。


所以,我立即排除了在游戏内部处理解析音效的方法,转化思路,调整为在游戏外部处理音乐,得到想要的数据,配置为关卡信息,然后在游戏内部进行读取显示。


Librosa


确定好新思路立马开始着手,因为自己自学了一点 Python 基础,所以第一时间想到了 [librosa] 这个功能强大的语言,很容易就找到了自己想要的东西。


librosa 是一个非常强大的 Python 语音信号处理第三方库,功能强大,具体有多强大大家可以自己上网查一下,在这里我只将基础的或者用到的功能介绍一下。


  • 读取音频


path:音乐文件路径
y, sr = librosa.load(path)
y:音频时间序列
sr:音频的采样率


  • 获取音频的时长


path:音乐文件路径
#获取音乐时间
musicTimer=librosa.get_duration(filename=path)
#将时间转化为帧数
musicFrame=librosa.time_to_frames(musicTimer)

注:时间转化为帧数,得到的帧数不一定是按照每秒60帧计算的。


  • 获取节拍信息


tempo, beat_frames = librosa.beat.beat_track(y=y, sr=sr)
tempo 估计的整体速度(以每分钟对应的节拍数)
beat_frames:获取的每个拍子相对应的帧数


  • 获取音乐峰值对应的帧索引




通过上图会发现,每一段都会出现一个相对最高的点,这就是峰值,也是咱们游戏中需要用到的重要数据。


获取音乐峰值对应的帧索引(得到的是一个组帧索引)onset_env = librosa.onset.onset_strength(y=y, sr=sr,hop_length=512,aggregate=np.median)对获取的峰值对用的帧索引数据进行处理选择,等的想要的数据peaks = librosa.util.peak_pick(onset_env, 3, 3,3, 5, 0.5, 12)#将帧索引转化为时间peaks_to_timer= librosa.frames_to_time(peaks, sr=sr)peaks_to_timer为获取的音乐中经过处理删选的一组数据,数据中记录了每个峰值对应的音乐播放时间点(单位秒)


整个 python 脚本代码:

#coding=utf-8import librosaimport osimport jsonimport numpy as np

def save_data(data): f=open("level.json","w") f.write(json.dumps(data)+",") f.close()

def analysis(nameKey,path,configJosn): y, sr = librosa.load(path) tempo, beat_frames = librosa.beat.beat_track(y=y, sr=sr)
#获取音乐时间 musicTimer=librosa.get_duration(filename=path) #将时间转化为帧数 musicFrame=librosa.time_to_frames(musicTimer) #获取每个节拍平均相隔几帧 每首歌的节拍是大概固定的 beatsDis=musicFrame/len(beat_frames)

# 峰值点 帧数 onset_env = librosa.onset.onset_strength(y=y, sr=sr,hop_length=512,aggregate=np.median) peaks = librosa.util.peak_pick(onset_env, 3, 3,3, 5, 0.5, 12) peaks_to_timer= librosa.frames_to_time(peaks, sr=sr)
dataStr="[0," for item in peaks_to_timer: dataStr=dataStr+str(item)+"," dataStr=dataStr[:len(dataStr)-1] dataStr=dataStr+"]"

json={} json["timer"]=musicTimer # json["amp"]=ampStr json["rhythm"]=dataStr configJosn[nameKey]=json


def getFileList(configJosn): audioList = os.listdir('music') for tmp in audioList: audioPath = os.path.join('music', tmp) if audioPath.endswith('.mp3'): name=tmp[:tmp.find('.mp3')] print("print "+audioPath+" audio datas----") analysis(name,audioPath,configJosn)if __name__=="__main__": configJosn={} getFileList(configJosn) save_data(configJosn)


得到的数据结构:

{ "1_0": { "timer": 83.0, "rhythm": "[0,0.2786394557823129,0.5804988662131519,.....]" }, "1_1": { "timer": 89.6, "rhythm": "[0,0.2786394557823129,0.5804988662131519,.....]" },
"1_2": { "timer": 60.9, "rhythm": "[0,0.2786394557823129,0.5804988662131519,.....]"
}}


ok 了,关卡信息完毕,对我来说难点问题已经解决。


相关使用以文档和 API 为主,[librosa API 文档] 大家有啥不懂的可以在文档中查找。


2.游戏功能实现


通过以上功能,我们已经在游戏外部获取到了音乐的相关时间以及峰值信息。


接下来只需在游戏逻辑中根据跳台的尺寸大小、玩家的移动速度以及每个峰值对应的音乐播放时间去设置跳台的位置和调整摄像机等其他属性。


在此附上 [Demo链接]



最后


下面是我个人基于 Cocos Creator 3D 制作的游戏作品《躲一躲 OL》以及基于 Cocos Creator 制作的《切片小达人》、《机智三角》,欢迎大家体验!感谢!




参考链接


[来首 Believer 放松下!]

https://forum.cocos.org/t/believer-cocos3d/87206


[librosa] 

https://librosa.org/doc/latest/index.html


[librosa API 文档]

https://librosa.org/doc/latest/index.html


[Demo 链接]

https://gitee.com/carlosyzy/Creator3D_MusicBall.git






以上是由 Cocos 开发者 玻璃小屋 分享的音乐类游戏实现教程,欢迎各位开发者点击【阅读原文】查看原文,与作者进行交流学习!


如果您在使用 Cocos 引擎的过程中,获得了独到的开发心得、见解或是方法,并且乐于分享出来,帮助更多开发者解决技术问题,加速游戏开发效率,期待您与我们联系!

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存