物理模拟具有一项不可思议的功能-可以将其停止,倒带和重播。这是一个非常强大的工具,可用于生成不寻常的世界。在这篇文章中,我将描述如何使用它来同步击中著名音乐的球的声音。请问有兴趣的人切下!
介绍
我喜欢创建各种精美的可视化效果,物理模拟以及所有类似的东西。大约两三年前,当我提出下一个想法时,我有了一个想法,但是如果我们产生物理世界,使其中发生的过程产生旋律,该怎么办?确实,在计算机模拟中,我们总是可以回滚,浏览选项,选择最佳选项,同时我们拥有有关旋律的所有信息:音符,音符的演奏时间。因此,我有了这个想法,直到更美好的时光,直到我有时间写隔离检疫为止,于是这个带有本文的项目就出现了。
模型
首先,我决定选择一个相当简单的模型。在我的模型中,只有两种类型的对象:大理石和平台或木板。平台具有严格固定的坐标,由两个端点设置并且具有恒定的宽度。球在重力的作用下掉落,并可以根据物理定律从平台弹回。此外,我决定仅使用绝对弹性的碰撞,以便系统的能量始终保持不变。但是最重要的是,当球和平台碰撞时,会发出声音,每个平台都有自己的声音,并且可以一次包含多个音符。
因此,我们的世界由许多平台组成,每个平台都有自己的声音。落在这个世界上的球会产生一系列声音,在我们看来,甚至是一种旋律。
算法
我们找到了模型,但是如何生成这样一个世界,使跳动的球的声音排列成一个著名的旋律?
我决定用最笨拙的,不过,这被证明是相当不错的,递归的蛮力,而在普通百姓暴力破解。但是为了使一切正常工作,我不得不使用一些技巧。所有后续步骤都在递归函数中执行:
- 我们模拟世界,直到下一个需要演奏音符的时刻。
- 如果在仿真过程中发生了不必要的碰撞,我们将返回更高的水平。
- , , , . , .
. «» ( , , ).+ 70 ∘ - 4. .
- 5. ,
- 6. , ,
滴答作响,没有发生碰撞,如果发生碰撞,则返回结果世界。米
在图片中,您可以看到此算法一个步骤的可视化:
注意
, , , . , , . , . , .
递归滞留
像任何蛮力算法一样,此方法也存在“递归滞留”形式的缺点,这种情况发生在某些“不良”平台不允许将来生成地图,但同时又允许您生成足够大的一部分(但不是完全)的情况下... 在这种情况下,递归将被阻塞,直到枚举此“不良”平台产生的递归子树中的所有选项为止。当此子树的高度不超过4-8个递归级别时没有问题,但是有时它可以达到20-30个递归级别,这使得根本不可能遍历此子树的所有变体。
因此,在我的实现中,我决定使用启发式方法来克服卡住的问题。想法是在检测到这种情况时使递归的某些部分崩溃。回到我看来,最明显的是
您可以在演示中看到这种启发式方法的结果,此时地图生成进度有时会重置10%。但是,与此同时,它允许您在合理的时间内完成卡的生成。
迭代生成
现在,我们将解决以下问题:开始生成地图后,页面冻结10-30秒,根本无法理解正在发生的事情,一切都已经下降,或者生成地图花费了很长时间。因此,我决定还要编写生成算法的迭代实现,以便您可以一小部分一致地构建地图。
我不必发明新的东西,只需将递归算法重写到显式堆栈上。因此,页面上会出现一个进度条,可以帮助您了解代码没有丢失,只需要很长时间就可以找到适合您的轨道的平台位置。
在某些情况下,生成可能会花费很长时间,为此,我添加了“播放”按钮,该按钮将停止生成并开始模拟世界。
下载铃声
要下载音乐,我使用midi文件,但在此之前我先通过tonejs.github.io/Midi对其进行了运行,以将其转换为浏览器友好的json(但是此演示尚不具备下载文件的功能,只能从现成的列表中进行选择)。
同样重要的是要注意,midi文件中通常会有几个平行的音轨,但是由于到目前为止我的算法仅适用于一个球,因此只有一个音轨会加载最多的音符。
结果
添加一些效果后,我录制了第一个视频:
审查了好后
视频可能显示不同步,我稍后注意到了这一点。如果转到演示页面,则不应有不同步的情况(只有在录制节拍时才播放声音)。
下一步是什么?
我计划增加一次生成多个球的地图的功能。我对如何执行此操作有想法,我测试了几个选项,但到目前为止,它们都非常缓慢地工作以生成完整的曲目。
我的另一个想法是添加新对象:按钮,跳板,加农炮(?),戒指...可以补充清单:)它们可以极大地丰富世界。
代码
您可以在我的存储库中找到所有源代码。
欢迎提出任何建议,拉取请求,测验!