用 Vue + Audio API 实现的热门小游戏,八分音符

2017-02-26 21:04:12 +08:00
 diamondfsd

预览地址: https://8.diamondfsd.com/ (谷歌浏览器打开最佳,不支持移动端,不支持 IE )

会有麦克风权限申请,需要允许才可以正常玩耍,如果不小心点了禁止,可以在浏览器地址栏的右边,重新点击允许

Github: https://github.com/k55k32/quaver

游戏截图

由来

最近看这个游戏比较火,个人也是比较闲。
今天花了一下午的时间,来完成这个当前比较火的小游戏,八分音符。
看了这个游戏,原理也很简单,我们只需要获得声音,然后把声音转换为数字,最后控制小人移动就可以了。

声音的输入

我们发现这个游戏的原理很简单,就是通过声音来控制小人移动,声音越大,跳得越高。
所以要做这个小游戏,我们就首先要解决的问题就是,如何从浏览器获得声音。这方面的东西,我以前也接触的不多。所以我只能先面向谷歌编程。
最后我搜索到了这篇文章: WebRTC , WebRTC 主要让浏览器具备三个作用:

获取音频和视频 进行音频和视频通信 进行任意数据的通信

navigator.getUserMedia({
    video: true, 
    audio: true
}, onSuccess, onError);

通过 navigator.getUserMedia 方法,我们可以获得麦克风的音频流,看到这里,我们第一个问题已经解决了,解决了声音的输入。

声音的输出

获得了声音输入后,如何把输入的声音转换为我们编程可以使用的量化数字呢,我们需要更详细的文档 WebAPI 接口 > AudioContext 。通过参考这篇文档,结合一些实例,最终我写了一个 AudioAPI.js 用于将声音数据,量化为我们需要的声音大小数字。

const navigator = window.navigator
navigator.getUserMedia = navigator.getUserMedia ||
                          navigator.webkitGetUserMedia ||
                          navigator.mozGetUserMedia ||
                          navigator.msGetUserMedia
const AudioContext = window.AudioContext ||
                      window.webkitAudioContext

const isSupport = !!(navigator.getUserMedia && AudioContext)
const context = isSupport && new AudioContext()
export default {
  isSupport,
  start () {
    // https://developer.mozilla.org/zh-CN/docs/Web/API/AudioContext  AudioContent API
    return new Promise((resolve, reject) => {
      navigator.getUserMedia({audio: true}, stream => { // 申请浏览器麦克风权限
        const source = context.createMediaStreamSource(stream)
        // 该对象可以获得声音的频率数据 https://developer.mozilla.org/zh-CN/docs/Web/API/AudioContext/createAnalyser 
        const analyser = context.createAnalyser() 
        source.connect(analyser)
        analyser.fftSize = 2048
        resolve(analyser)
      }, () => {
        reject()
      })
    })
  },
  getVoiceSize (analyser) {
    const dataArray = new Uint8Array(analyser.frequencyBinCount)
    // 这里会获得一个数组,数字的下标表示频率,数组的值表示频率波大小
    // 通过对这些值的一个简单累加,就可以得到一个数字,用于游戏中表示声音的大小
    analyser.getByteFrequencyData(dataArray)

    const data = dataArray.slice(100, 1000)  // 只获得 100 - 1000Hz 的声音频率大小
    const sum = data.reduce((a, b) => a + b)  // 将这些值累加
    return sum
  }
}

通过 AudioAPI.start() 开启麦克风,返回一个 Promise,可以获取到 一个 AnalyserNode对象, 通过该对象的 getByteFrequencyData 方法,可以获取到实时的声音频率数据。

小人的 “移动”

因为之前没有写过游戏,不知道正常的写一个类跑酷的游戏需要怎么写。所以我就照着自己的想法来吧。首先,小人是不会动的,动的只是背景。底部的每一个黑块都是一个 DOM 。
具体的代码可以看源码里面的 Game.vue 组件,因为全部代码比较长,这里就简单讲解一下。我们可以通过比较底部黑块和小人的位置 获得以下值: 小人是否紧贴黑块上面?

如果符合该条件,那么他就可以跳,而且不会再下降了。如果不在黑块上面,那么他就会一直下落:

  1. 落到黑快上,就又符合 在黑块上 这个条件了,那么通过声音的收集,如果大于一定的量,小人就又跳起来了。 底下的黑块是一直向左移动的,看上去是小人在走的样子。
  2. 落到空白处,会一直下降,如果碰不到黑块,那么降到最底部的时候,游戏结束

项目源码

这三个问题解决了,这个游戏就完成了,当然,还有很多可以润色的地方。例如加上游戏背景音乐,在跳的时候加上音效,游戏结束的一些效果,声音收集的灵敏度,积分排行等。这些东西就留到下次再写吧,当然大家有兴趣也可以参与进来完成这方面的工作。

如果大家觉得还不错的话,就去 Github 上帮我点个 Star 吧。

Github: https://github.com/k55k32/quaver

预览地址: https://8.diamondfsd.com/ (谷歌浏览器打开最佳,不支持移动端,不支持 IE )

2410 次点击
所在节点    JavaScript
6 条回复
Death
2017-02-27 07:27:56 +08:00
记得原游戏的移动方式和音调也有关,大致看了一下源码,你似乎只是判断了音量?
wjm2038
2017-02-27 07:54:21 +08:00
没有结束么?
diamondfsd
2017-02-27 10:09:52 +08:00
@Death 是将所有频率的音量加起来了。 如果音调高的话,那应该在高频区的数值会很高。

原游戏是有一定算法的,我对音频方面不太了解,所以就简单粗暴的加到一起,合成一个值了
diamondfsd
2017-02-27 10:10:28 +08:00
@wjm2038 有的呀,游戏只随机生成了 50 个黑块,走完就------
必死无疑 哈哈
StargazerWikiv
2017-02-27 15:48:15 +08:00
Vue 萌新路过,已 star !
Mapz
2017-02-27 17:44:44 +08:00
最近在学 vue ,看看

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/343331

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX