这次介绍相关的其他内容。
消失
在一般的音游里:
- 如果是 单击音,一旦经过判定,就会显示判定结果图像,然后立马消失,以免影响玩家的注意力
- 而如果是 长按音,则会在成功的时候保持成功的图像,不会消失;而失败的时候更改为失败的图像,同时不透明度大幅度降低
要做出这种效果非常简单,只要在控制 音符 退出到 弃置区 的那个 移动路线 开头加上 开启透明状态,或者 不透明度:100 就可以实现了。
跟在 事件 ID(分页式)里 单击音(分页式)第二页 的最后一点所说的一样,因为我们是先打开 独立开关,再 设置移动路线,所以所有 音符 都会先闪一下结算图像,然后再 开启透明状态 或者设置 不透明度:100。
这里一样也只提供 单击音(一页式)的第一页,其他 音符 的道理一样一样。
这时候我们会发现,不管成功与否,音符 都是在原本设定的 miss_previous、prefect、miss_after 的位置消失(而不是提前半格)。
我猜测这是因为 读取指定位置的信息(数据向)是读取事件的中心点所在位置,所以只要 音符 的中心点过了格子的边界,它就算是在另一个格子里了
而无论怎么样,移动路线(移动向)都是整一格整一格地完成的,所以哪怕它换了事件页,由于之走到了格子与格子的中间,哪怕它之前的 移动路线 的失效了,但它还是要把当前这半格走完。
所以这之间的差异会导致结算图像显示的比较久,而没有达到闪一下的目的,不过不那么纠结的话,目前的方案也无伤大雅。
这里如果是 长按音 _after 出问题了应该比较好理解(比如 长按音·伯 后面的 长按音·仲 更换失败图像慢了一拍),因为长按音·伯 到达 miss_after 打开开关 长按失败 的同时,跟它相邻的那个 长按音·仲 也刚好到达了 prefect 换了事件页,而 长按音·仲 的 prefect 事件页并不包括对开关 长按失败 的判断,按道理来说相邻的 长按音·仲 如果此时按紧了 确定键 是不会失败的。可能是因为要 长按音·仲 进入 prefect 的瞬间才按紧 确定键 的操作太过于极限了,所以才可以不考虑这种情况会出现。实在担心这种情况的发生,你可以在 长按音·仲 的 prefect 事件页加入对于开关 长按失败 的判断。
Combo(连击)
因为我测试用的图里音符只有 5 个很少,所以一开始我设定是音游开始就显示 combo,音游结束就关闭 combo 的显示。这时候只需要设定 combo 的出现条件是变量 音游阶段 >=1 就行。
但现在到了码字的时候,我突然意识到,正常 combo 的出现是需要玩家连击到一定程度才会显示的,比如有些游戏需要连击 3 次或者 5 次才会出现。单纯一次音符判定成功并不能称之为 combo,至少也要有两个吧。所以现在 combo 的出现条件改为变量 combo >= 2。
有关于 combo 的变量/开关有以下三个:
- combo 失败(开关):用以告诉游戏连击失败了
- combo(变量):记录当前的连击数
- MAX combo(变量):记录目前为止最大的连击数
前两个需要在各个 音符 里进行额外的设定。
其中,变量 combo 的设定比较简单,因为变量 combo 的增加往往意味着得分,所有 音符 事件里只要出现了 “变量操作:音游得分 +=1” 的部分,后面直接加上 “变量操作:combo+=1” 就行。
开关 combo 失败 恰恰和变量 combo 完全相反。变量 combo 是在所有成功的地方出现;而 combo 失败 却并不需要在所有失败的地方出现,它只要出现在 单击音 以及 长按音·季 就行,因为 长按音序列 前面任意音符失败都会打开开关 长按失败 从而导致后面的音符一起失败,所以 长按音序列 里的开关 combo 失败 只要根据最后的 长按音·季 失败而变化就行。打开开关 combo 失败 请设定在对应的打开独立开关 A(音符失败)前面。
最后一个变量 MAX combo 主要由 最大连击数修改器 操作,我把显示图片 combo 的第一个事件设为 最大连击数修改器。
之后就是本部分最重要的如何显示连击数的具体实现方式。其实最好的实现方式果然还是使用插件,因为变量 combo 是一个实时变化的量,而 RMMV 自带的 显示文字 会阻碍玩家的操作,这让实时显示并改变文字内容的难度大大提升了。但我们这里的目标是尽量不使用插件,所以让我们尝试看看如何仅使用事件的情况下如何实时显示变量 combo。
其实我使用的方法非常笨拙。将官方自带的 img-system-Damage.png 里的数字取出来做成行走图。然后并行处理,穷举所有可能出现的情况,用 分歧条件 判断当前位数的数字,然后用 设置移动路线 来实时更改要显示的数字图像(存放在 img-characters 里)。
正是因为一首正常的音游曲目少说都有几十上百个音符,我们不可能把所有可能出现的数字都一个个画出来,所以我们要把变量 combo 里的各个位数上的数字提取出来,降为只剩 0~9 这十个数字的工作量。提取的方法并不难,只要简单的混用除法和取模这两种运算方法就行。
我们还要意识到一点,虽然测试时用 F9 打开 开关 / 变量查看器,可以实时查看开关 / 变量,里面的变量都是以整数形式显示,但实际上储存的变量都是浮点数。所以这个时候直接用 分歧条件 判断它们是否为 0~9 这十个整数中的任意一个,将不会成功。我们需要将除法/取模后的数字整数化后再进行判断。
根据前面的探讨,我们可以得出各个位数的写法:
- 个位:单纯使用取模就行。$gameVariables.value(x)%10
- 中间位数:混用除法和取模,最后取整。parseInt($gameVariables.value(x)/10^(n-1))%10
- 最大位数:单纯使用除法,最后取整。parseInt($gameVariables.value(x)/10^(n-1))
解释
- "%" 是取模的符号,"/" 是除法的符号
- $gameVariables.value() 是 读取变量 的函数。中间的 "x" 指的是读取第 x 个变量
- parseInt() 是取整变量,它不管小数的情况,通过直接舍弃小数点后面的数字的方式进行取整(感觉跟向下取整好像)
- "n" 指的是当前的位数,比如个位为 "1",十位为 "2",百位为 "3",以此类推
举例
这里我们暂且只设一个三位数字,读取的是第 18 个变量 combo 的值,所以具体写法如下:
- 个位:$gameVariables.value(18)%10
- 十位:parseInt($gameVariables.value(18)/10)%10
- 百位:parseInt($gameVariables.value(18)/100)
这里我们仅用 连击数(十位)作为例子,来看看连击数的显示事件该如何写,其他的写法一模一样。
流程
- 用 分歧条件 判断当前位数是什么数字
- 用 设置移动路线 更改图像
- 设置移动路线 要选择 本事件
- 记得 设置移动路线 要同时勾上 无法移动时跳过指令 和 等待完成。
最后一项如果不勾上的话,连击失败了,图像不会消失;甚至游戏结束了,部分图像也不会消失。这很可能是 RMMV 的 bug,不过也可能是我思维上哪里出了错误。但即使是这么做了,大多数情况还是能正常地消去图片,少数情况图片还是会残留,尤其是长按音 _prefect_interrupt 的情况(全连也有概率会出现 bug)。
后来我突然想到,我其实没必要在显示 combo 事件的判断页预设图像为 “0”,设成无图像会不会比较好一点。实际尝试后,发现并没有什么区别。
为了修正 “音游结束,连击数部分数字没有正常消失” 的 bug,可以将原事件的最后一个空白页(音游结束)后面再加一个空白页,进行多一次图像刷新。这可以极大地避免该 bug 的出现。
至于 “连击中途失败,连击数部分数字没有正常消失” 的 bug,我尝试在显示 combo 的事件里在开头加一个无图像空白页。经测试,这个 bug 出现概率大幅度降低了,但还是偶尔会出现,尤其随着音游重置(后面会讲)次数增多,bug 出现的概率也相应增大。
或许可以学习前面的 “增加空白页,多一次图像刷新” 的方法。第一页的出现条件改为 “音游阶段 >=1”(音游开始),自动执行打开独立开关 A;第二页出现条件 是“独立开关 A = on”,空白页;第三页就是判断页,在原有基础上增加一个关闭独立开关 A。
由于前面显示 combo 事件经过了多次修改,我这里再全部重新展示一次,以免混淆:
经测试,在目前最新方案下,本章节前面提到的两个 bug 都不会再出现了。明明不出 bug 的话,只需要两个事件页,现在为了修复 bug,不得不做成五个事件页。
校准
校准一般在音游里指的是:“声音发声” 与 “音符到达 prefect 位置” 这两个东西,做到画音同步。做这个的目的,一是不同设备可能会有些许画面和音效上的误差;二是不同玩家的反应时间不一样,玩家可以通过校准来获得最适合自己的设定。
而在我们的 RM 里,我们需要再新建一个地图,单独制作校准环节。
我的设计思路是这样的:首先设定一个默认的变量 校准。然后如果玩家对预设的变量 校准 不满意的话,就启动 校准启动器,校准启动器 会打开 音符驱动器 来驱动音符,每一轮(音符从右运动到左)结束后,音符驱动器 会打开 音效播放器 来每一轮播放一次音效。(校准启动器(启动)→ 音符驱动器(驱动)→ 音效播放器(每一轮播放))
音符驱动器
音符驱动器 是里面非常重要的一零部件,我们先看这个:
音符驱动器 事件页里的变量 miss_after 并不是指的是 miss_after 那个位置上的事件 ID,而是指的是音符运动路径的终点。我不想再增加一个变量,所以才借用。“如果:miss_after = 1”,这里的 “1” 就是音符的事件 ID。
我原本还把 “音符经过判定点(prefect)颜色变绿,不在判定点时颜色恢复红色” 的任务一并交给 音符驱动器,但出现太多 bug 了。最后找到了一个简单的方法,根据情况更变事件页,让 音符 自己干这个任务。
校准启动器
接着是 校准启动器。我计划在 校准启动器 里设定变量 校准 的大小,然后在 音效播放器 前面插入等待 “变量 校准 的值” 的帧数,从而达到校准的目的。
按理来说,这种调整是可以向前向后调整的,因为说不定对于一些玩家来说 “声音响了,音符却还没到达判定点”;而另一些玩家可能发现 “音符早就判定玩了,声音还没响”,所以变量 校准 是可以相对默认值上下调的。但是在 RM 里,如果你从未对一个变量进行过赋值,那么它的默认值是 “0”;另外,RM 的 数值输入处理 只支持正整数,所以变量 校准 的默认值一定要大于 “0” 才行。所以我最好是在校准前就先将变量 校准 改为正整数作为默认值(这样就算玩家不去碰 校准启动器,一开始也是制作者设定的默认值),而且就改一次,之后就算重新打开游戏也不再次设定默认值,而是保存玩家的设定。据此,我的 校准启动器 设定如下:
但实际测试的时候,发现虽然一般来说确实目前的状态是满足了我们的设想,但是偶尔还是会出 bug,校准完后反而被改为了默认值。
玩过 RMMV 的朋友应该知道,如果出现条件一样,优先度更高的是靠后的事件页。但是我猜测,它的运行逻辑还是从前到后地读取事件页,只是如果后面的事件页的出现条件达到了的话,就优先运行后面的。所以在我们上面的情况里,我们完成校准后退出了 校准启动器 的第三页。因为第一页是自动执行,所以它直接就把玩家校准完后的变量 校准 再次改为默认值。但问题是,我们已经打开过 校准启动器 的独立开关 A,按理已经直接到第二页,不会再次执行第一面的内容才对。实际上也确实如我们所设想的一样,不应该执行第一个事件页,正常情况下校准完了还是玩家所设定的值,上面的情况出现概率比较小。虽然概率比较小,但终究还是 bug,我们还是应该去修复它,所以简单地把赋予变量 校准 默认值的任务交给另一个事件,然后永远再也不触发这个事件。校准启动器 只负责校准。
所以我的推荐是,设定默认值都独立出来,这样可以减少很多 bug。
在 校准启动器 里,当我结束校准的时候,我重置了 音符 的位置,将它放在路径终点的前一格。
一开始将 音符 设定在路径终点就是为了一开始就能打开开关 校准(一个回合),从而启动 音效播放器。这个设定是没有问题的,开始校准后,音符驱动器 立刻把 音符 移到了路径起点,同时打开开关 校准(一个回合)。但是一旦我们校准完毕,校准启动器 如果将 音符 重置在我们一开始设定的路径终点的位置的话,再次启动 校准启动器 的时候,音符 直接向左驶去,而不再像第一次一样被 音符驱动器 搬到路径起点,开关 校准(一个回合)也没有打开,一起都乱套了,即使设定上和一开始并没什么不同,这应该也是 RM 的 bug。但是我们在校准完毕的时候,如果 校准启动器 将 音符 放在路径终点前一格的话,bug 就被修复了,一切照常进行。
音效播放器
最后是 音效播放器:
为了让音效在每一轮(音符从右运动到左为一轮,变量 校准 不变的情况下)同一个时间发出声音,我特意再设了一个开关 校准(一个回合)。在 音符 到达运动路径终点然后被 音符驱动器 移动到运动路径的起点的同时打开开关 校准(一个回合),这样就能保证音效都是在每一轮的同一个时间点播放。另外,建议制作或者选择这个音效的时候,最好使用那种比较短促但不刺耳的音效,可以让玩家更加精确地把握音效发生的时刻。
在 音效播放器 事件页里你可以看到我预设了 24 帧。这个 24 帧我叫它 “预设等待值”,它加上变量 校准 的默认值(这个例子里是 5 帧),共 29 帧,这是制作者根据自己测试的情况,加在播放音效前的预设等待时长。因为 音符 从 准备区 运动到 判定点 需要时间,而歌曲的播放有可能是立刻播放;或者音频文件自身就有预留前置的没有任何声音的部分;也可能是音乐前面一部分你并不想设置任何音符,所以调整 “开始播放的时间” 和 “等待 音符 运动到 判定点 的时间” 之间的平衡很重要。这里我们就是在将它们开始时间调整为我们想要的样子。
另外还要记得,音游的每一个歌曲前面也要加 “预设等待值”:
这样一来,音游的校准就做好了!
音符重置
当我们玩完一次音游某一个曲目的时候,我们常常还是想再挑战一次的,这个时候就需要将这个曲目所有东西重置一遍,包括游戏的变量(除了变量 校准),开关,音符的位置。音符的位置无需担心,你玩完音游移动到别的地图,然后再回到音游歌曲这个地图,因为是重新加载这个地图,所以所有事件的位置都会重新读取,事件就都回到一开始设定的位置。变量和大部分开关也不用多想,只要都设置为 “0”,或者全部关闭就行。比较难解决的是独立开关,RM 的事件编辑器并没有一个地方可以直接控制所有的独立开关。还好我们有合适的脚本可以解决。
- 全部独立开关关闭:$gameSelfSwitches.clear();
- 全部独立开关打开:$gameSelfSwitches.onChange();
不过比较可惜的是,这个脚本是针对所有的独立开关,意味着如果你执行这个脚本关闭所有独立开关之后,再次进入校准地图,变量 校准 将会被重置为默认值。所以我们最好还是再多加一个开关代替独立开关,专门来控制设定默认值。(做游戏就是一步步让步和调整)
后记
其实经过这次开发尝试,做到最后最直观的感受还是 RMMV ,单纯事件的方式制作的话,并不是一个适合制作音游的引擎。虽然插件还是有不错的音游插件,就是自由度实在太小了。
另外现在使用的这个 MV 版本的 RM,它的帧数虽然说起来是根据秒计算(1/60 秒一帧),但实际上跟刷新频率有关,这既不方便制作者计算帧数;又因为不同机子的刷新频率不同而导致玩家游玩时和制作者制作时的情况大为不同,进而导致玩家游玩的画面和音乐有可能会有非常大的差异,非常影响游戏体验。最近新出的 MZ 版本据说更新了引擎内核的 pixi(pixi 由 V4 升级到 V5。游戏刷新机制由 V4 版本的 DOM API : requestAnimationFrame,改用 PIXI.Application),应该能解决这样的问题。
全文完。
前两篇:
geek