This commit is contained in:
OLDREDSTONE
2025-06-01 11:35:11 +08:00
commit 318bbf3be2
423 changed files with 13900 additions and 0 deletions
+174
View File
@@ -0,0 +1,174 @@
---
title: "附录8 代码编写关卡"
---
点击[此处](../stuff/compiler.exe)下载。项目作者:硫酸铜。项目来源:[PyRD - 为视障谱师写节奏医生谱子的一种全新的尝试](https://github.com/qwedc001/pyrd)。
本附录为了介绍更为简明化,部分计算机术语被替代,可以前往我的github项目查找原文档(*作者注:有人能帮我写一下文档就好了,文档苦手伤不起*)
项目介绍:PyRD,又名Python Rhythm Doctor,旨在使用代码创建Rhythm Doctor的自定义关卡,这个项目发起的本心是为了方便节奏医生的视障玩家去制作优质的谱面,而不是对着一个冗长的JSON文件发愁。
后来经过节奏医生官方开发huantian的建议,将原有的Python写代码转换成了学习成本更低的YAML标记格式,引出github分支yaml,文档上方提供的下载就是用于翻译yaml为rdlevel的解释器(我并没有做检查语法功能,有大佬会写可以来提交pr)
此处文档以介绍分支yaml为主,在此分支下,解释器解释的文件后缀为.sprd(Simple RD)
如果你想直接使用python写rdlevel,你可以直接git clone以后将pyrd.py引入项目,然后根据里面提供的函数进行编写。
先通俗的解释一下.sprd文件的构造,建议配合文档末尾提供的示例对比学习。
.sprd文件主要分为三大块,分别是metadata(关卡信息),角色和小节具体内容。
## Metadata关卡信息的填写
在每一块内,每一句是通过换行来分隔的,且在开头有1个空格,比如:
```yaml
metadata:
艺术家 硫酸铜
歌曲 SimpleRD
难度 简单
癫痫 关
```
以上四句话分占四行,在中间有空格,空格前为参数,空格后为内容
metadata可以填写的参数有:
```yaml
metadata:
艺术家:艺术家名称
歌曲:歌曲名称
作者:作者名称
描述:描述
癫痫:是/否
难度:简单/普通/困难/噩梦
标签:标签
rank所需错误数:[20,15,10,5]
rank描述:["F","D","C","B","A","S"]
```
当然,如果你选择全空着也不是不行,所有metadata此时都会填空。
## Character角色信息的填写
角色是一行一个角色,角色只有参数,中间用英文逗号分割。
角色一共有十个参数,其中有五个参数是必填的,剩下五个是你想要填才填,不想填可以不填的。
如果你想要填一个,空一个,再填一个,那么要空过去的那个参数用英文句号.代替。
角色的五个必填参数按照顺序是:
角色名(不想写可以填无),节拍类型(普通拍/单发拍),角色在第几个房间,角色在第几个轨道,角色节拍音效(还没有写对照表,后期补上)
角色的五个选填参数按照顺序是:
在开始时隐藏轨道,节拍音量,节拍音调高低,节拍声象,节拍偏移,比如:
```yaml
- [武士,普通拍,0,1,Stick]
- [科尔,单发拍,0,2,Kick]
```
## Bar每个小节的填写
针对于节拍部分,从第三块开始,接下来每一个小节都标上对应的数字,在之后的内容前再加上一个空格。比如:
```yaml
1:
- [播放音乐,1,sndOrientalTechno,100,0]
```
这里的语法是:- [内容,参数],内容之间/参数和内容之间用英文逗号分隔。
几个已经支持的语法:(带星号为可选参数,并且最后有一个“条件”参数,这个参数因为所有语法都支持所以不单独列出)
```yaml
- [播放音乐,事件在当前小节第几拍,音乐名,BPM,偏移,*音乐音量,*音乐音高,*音乐音像]
- [普通拍,事件在当前小节第几拍,事件在第几轨道,普通拍长度,摇摆拍设置]
- [单发拍,事件在当前小节第几拍,事件在第几轨道,单发拍长度,*单发拍循环,*是否跳过此拍,*冰冻拍间隔,*单发拍类型,*是否播放方块音]
- [设置静音,事件在当前小节第几拍,事件在第几轨道,静音模式(由6个字符组成,-代表正常,x代表静音),切分音拍,切分音摇摆]
- [长按拍,事件在当前小节第几拍,事件在第几轨道,长按拍长度,长按拍摇摆,长按拍按住长度,长按拍X模式]
- [自由拍开始,事件在当前小节第几拍,事件在第几轨道]
- [自由拍脉冲,事件在当前小节第几拍,事件在第几轨道,脉冲行为,自定义脉冲]
- [设置护士音效,事件在当前小节第几拍,说的内容是什么,*是谁的声音,*要提示的单发拍拍长,*音量]
- [设置BPM,事件在当前小节第几拍,bpm]
- [播放音效,事件在当前小节第几拍,音效文件,*音量,*音高,*音像,*偏移,*是否为自定义音效]
- [设置数拍音效,事件在当前小节第几拍,事件在第几轨道,*数拍音效声音,*是否开启,*音量]
- [朗读轨道,事件在当前小节第几拍,事件在第几轨道,信息种类,轨道自定义X,*是否跳过朗读"紊乱",*只发出声音,*朗读X拍]
- [朗读说明,事件在当前小节第几拍,朗读文本,*说明分类]
- [显示对话,事件在当前小节第几拍,对话文字,对话速度,*立绘位置,*播放音效]
```
详细的参数类型可以在pyrd.py中找到,更详细的docs需要等到有时间再进行维护,或者你们谁维护了给我提交个pull request也行。
编写完成后,请执行python compiler.py 你的sprd文件名
(进阶)VFX语法(由群内0x4D2提供):
```yaml
- [预设特效,事件在当前小节第几拍,事件在第几轨道,特效名称,*是否激活,*属性]
```
只有个别特效具有 属性 参数。
- 对于 落雨/JPEG失真/马赛克/海底波浪/电影噪点/暴风雪/素描/色像差/模糊/径向模糊/色调偏移:强度,缓速时长,缓速
- 对于 自定义屏幕块/自定义滚屏:x/y
- 对于 高光:阈值,强度,颜色,缓速时长,缓速
```yaml
- [设置背景,事件在当前小节第几拍,事件在第几轨道,模式,*颜色,*图片,*fps,*填充模式,*过滤器]
```
* 模式: 颜色/图片
* 对于 平铺 填充模式,有额外的参数:速度x,速度y,时长,缓速
```yaml
- [轨道涂色,事件在当前小节第几拍,事件在第几轨道,*受影响的轨道编号,*边框样式,*边框颜色,*边框透明度,*是否启动电击效果,*透明度,*是否填充,*填充颜色,*填充透明度]
```
* 受影响的轨道编号 如果为-1或"全部",则全部轨道均受影响,
* 边框样式 无边框/轮廓/发光
* 透明度最大为100(不透明)
```yaml
- [闪烁,事件在当前小节第几拍,事件在第几轨道,时长]
```
* 时长 短/中/长
```yaml
- [注释,事件在当前小节第几拍,事件在第几轨道,注释文字,*播放时是否显示注释,*注释颜色]
```
## 示例:Github项目 exampleYAML.sprd
```yaml
metadata:
艺术家: 节奏医生
歌曲: 1-1
作者: 卢毅
难度: 简单
癫痫:
描述: 这是一个关卡。
角色:
- [武士,普通拍,0,1,Stick]
- [科尔,单发拍,0,2,Kick]
小节:
1:
- [PlayMusic,1,sndOrientalTechno,100,0]
- [预设特效,1,0,落雨,开]
- [设置背景,1,1,颜色,626262FF]
- [轨道涂色,1,2,全部,发光]
- [普通拍,1,1,1,0]
2:
- [普通拍,1,1,1,0]
3:
- [普通拍,1,1,1,0]
4:
- [普通拍,1,1,1,0]
- [设置护士音效,5,SayReaDyGetSetGoNew,.,1,100]
5:
- [单发拍,1,2,1]
- [单发拍,3,2,1]
- [单发拍,5,2,1]
- [单发拍,7,2,1]
- [设置护士音效,8,JustSayStop,.,1,100]
- [闪烁,1,0,长]
- [闪烁,5,0,长]
- [注释,1,1,插入两个闪光,动作,开]
```
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 160 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 196 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

+1467
View File
File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 151 KiB

+49
View File
@@ -0,0 +1,49 @@
{
"size": [64,64],
"name":"吾夜犹明",
"rowPreviewFrame": 1,
"rowPreviewOffset": [0, 13],
"clips": [
{
"name": "neutral",
"frames": [0,1,2,3,4,5,6,7],
"loop": "onBeat",
"fps": 8,
"loopStart": 0,
"portraitOffset": [16,24],
"portraitSize": [32,32],
"portraitScale": 2
},
{
"name": "happy",
"frames": [8,9,10,11,12,13,14,15],
"loop": "no",
"fps":12,
"loopStart": 0,
"portraitOffset": [16,24],
"portraitSize": [32,32],
"portraitScale": 2
},
{
"name": "barely",
"frames": [16,17,18,19,20,21,22,23],
"loop": "no",
"fps": 12,
"loopStart": 0,
"portraitOffset": [16,24
],
"portraitSize": [32,32],
"portraitScale": 2
},
{
"name": "missed",
"frames": [24,25,26,27,28,29,30,31],
"loop": "yes",
"fps": 12,
"loopStart": 2,
"portraitOffset": [16,24],
"portraitSize": [32,32],
"portraitScale": 2
},
]
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.
+61
View File
@@ -0,0 +1,61 @@
---
title: "尾声"
description: "我们还有些想说的话"
permalink: /epilogue.html
---
到此为止,编辑器教程的正文部分就完全结束了,一不小心这个网站也经营了一年了,不知道总结出的这个教程质量如何,心中诚惶诚恐。因为我等几人也并非什么神仙大佬,编辑器怎么用,全凭自己费时间摸索。教程里技巧虽多,但也都带点每个人自己的使用习惯,示例关卡更是如此。
虽搁笔至此,但每人心中都还是憋着几句话想要一吐为快。不如就以此作为整个教程的收尾吧。
> 整本编辑器教程写到此处收工,通读下来不知各位看官是否注意到了一点。要做出一个谱子其实非常容易,把编辑器的第一大章看完,再加上自己随便这点点,那戳戳,该有的该会的都能做得像那么回事。但为什么这本教程写了足足九万二千多字,不惜笔墨花了三十多章节来一点点的教学?因为每个功能虽然界面一说就懂,但是背后暗藏的细节太多了。
>
> 整个学习的过程大概也分三个阶段。第一个阶段要慢慢熟悉编辑器,理解官方为什么要把剧情模式的每一关设计成现在玩到的样子。第二个阶段要逐渐把节奏设计和视觉效果的技术力提高,做出一个体验完整的谱面。第三个阶段,当技术力已经提升到优秀的线以上的时候,就要开始琢磨跳脱出节奏医生之外的玩法设计、画面叙事以及情感表达了。
>
> 所以我对于每一位看到这里的读者都有一个期待,除了把功能都用会之外,一定再多花一些时间让关卡变得更好。既然教程都已看过,切莫再抱以“我的做谱水平就到这了,不想再改了”的心态把视频和关卡一发了之。我们毫无保留地把自己的做谱经验分享出来,虽不妄图让各位严格遵照,成为诸如编辑器的教科书云云,**但殷切期待所有学成者都能以此为契机打开思路,能意识到一些之前未曾考虑过的想法,并让下一个谱子变得比之前更好**。
>
> 愿你我共勉。
>
> {:.align-right}
> ——养老院里安享晚年的山不转水到渠成
> 《节奏医生》真的是一款很棒的游戏,而关卡编辑器又给这款游戏的内容赋予了极高的上限,让玩家能够在欣赏完官方剧情后能够发挥创意自行创作并分享给更多玩家。但是这款游戏的热度一直以来都比较低,很少人愿意在体验完官方剧情后尝试创作关卡,而坚持下来的人少之又少,这种情况很大程度上是由编辑器一定的上手门槛导致的。因此我们联合为大家带来了编辑器的教程,希望能够帮助大家理解编辑器的各种功能和学习制作关卡的一些技巧,当然还有更重要的一点:了解制作一个合格关卡的基本要求。
>
> 我们过去看过许多社区的自制关卡,其中虽然有很多的优秀作品,但也有不少不够规范,粗制滥造的劣质关卡(包括本人一开始制作的几个关卡),这些关卡或多或少地影响了路人对这款游戏的第一印象和《节奏医生》玩家对自制关卡的第一印象,并对自制关卡的制作产生了一些误解(最典型的是误把《节奏医生》当成硬核音游,并按照硬核音游的标准来制作关卡),进而产生了更多的劣质关卡,这种恶性循环对游戏社区的构建和人们对这款游戏的认识都有非常不好的影响。
>
> 我们制作教程的初衷是希望大家在学会使用编辑器制作关卡后能够为社区带来更好的作品,减少劣质关卡的产生,既然官方把制作关卡的权力交给了玩家,我们玩家就不应该辜负官方的信任,这个游戏不该在玩家手里变烂(我们所制作的关卡可能会影响人们对这款游戏的认识,进而影响人们对这款游戏的评判)。因此我希望各位能在这个教程的帮助下创作出更多优秀的作品,为《节奏医生》这款游戏带来更加精彩的内容。
>
> 新世界大门的钥匙已经准备好了,祝你们好运!
>
> **(省流大师:编辑器不难,好学又好玩。做烂关卡影响不利,做好关卡皆大欢喜。)**
>
> {:.align-right}
> ——吾夜犹明
> 我曾讨论过一个问题:《节奏医生》是音游还是亚音游。也得到了很多种结果。我最支持的是《节奏医生》是新式音游,主要在于游戏中的普通拍和长按拍都增加对应的提示拍。而且这是一款单键音游,设计时考虑到了盲人玩家也可游玩(就像节奏天国一样)。因此,《节奏医生》的铺面设计和其他音游也存在不同。本作和 [7th Beat Games](https://store.steampowered.com/search/?developer=7th%20Beat%20Games) 的另一部作品《冰与火之舞》一样,提供了关卡编辑器,让玩家在打完官谱后有发挥自己想象力和创造力的空间。《节奏医生》因独特的玩法,使得关卡编辑器的内容更加丰富,做出来的关卡更加深层次,多元化、立体化。
>
> 但同时,也因为独特的读谱机制,使得自制谱的潜规则更加复杂(Adofai里边只要能看清轨道就没什么问题),官方节奏和自创节奏的提示也有严格的要求。因此,节奏医生关卡编辑器的人气不是很高,而且国内优秀的谱师和自制谱也没有很多(说实话我并不觉得我是“优秀的谱师”)。最后,希望通过本部教程,能让更多的人喜爱这款游戏,并且在尝试完主线关卡后有兴趣钻研关卡编辑器的相关内容。**认真遵循官方发布的社区关卡制谱规范,拒绝塞爆**。
>
> 留给大家钻研的彩蛋:
>
> 45 39 氚 1 101 8 6 氚 8 86 5
>
> 102 16 氚 92 9 9 49 g
>
> Менделе́ев-Периодична таблица на еле
>
> {:.align-right}
> ——喜欢精灵宝可梦的黄黄
> 感想什么的,感觉跟学校的语文作业一样,好为难啊……
>
> 关于这次教程,我的参与面是比较少的,但我玩过的谱面还是比较多的,毕竟经常直播打谱了,良谱屑谱奇葩谱都有接触过,自己也写了两份很简单并没有太多特效的谱面了,就从游玩者和编辑器初学者的角度来谈谈我对于自定义关卡跟编辑器的感受和对于谱面的一些想法吧。
>
> 首先是作为一个玩家来说,节奏医生是主打单键节奏的音游,所以节奏感一定是很重要的,视觉效果不讲,如果单纯的拍子都没有跟音乐对应那玩起来肯定很难受。我打了很多谱碰到的节奏都对不好的谱还真的比我想象中的要多很多,如果你是看到这里的跟我一样的萌新宝宝,记得一定要先学会对好节奏,找好节拍哦,这点很重要,就像盖房子的地基,打好了才能稳定。
>
> 其次呢是作为一个编辑器的初学者,编辑器特效那么多,再加上各种自定义代码可以解决的就更多了,肯定有你不懂的地方,这个时候一定要厚着脸皮去多问比自己懂得多的前辈们,问多了自然就记住了。也可以没事就自己开个编辑器玩,多尝试自己没有使用过的效果,自己试多了之后有创作灵感了才能有办法去实施。初学者可能会有很多想法不知道怎么去实现,只要敢想敢问敢尝试,一定能做出自己想要的效果的。
>
> 做到上面这两点并不难,其实作谱也就是这样。编辑器上手门槛也并不算难,我也没有特别多的想跟大家说的,毕竟我也只是个初学者,就感谢一下制作本教程的其他大佬能给我这个B站超级鸽子这个和大家谈话的机会吧,希望大家都能做出能让自己喜欢,被大家认可的谱吧,我们一起进步。
>
> {:.align-right}
> ——一个希望自己能火却经常咕这咕那的鸽子,丘露帆
Binary file not shown.
+125
View File
@@ -0,0 +1,125 @@
---
title: "rdview-example"
use_rdview: true
---
行内 <rd-timeline inline><button is="rd-event" style="--event-x: 1; --x: 1"></button><button is="rd-beat" style="--y: 1"><rd-pulse></rd-pulse><rd-pulse type="hit" style="--x: 1"></rd-pulse></button></rd-timeline> 事件。
<rd-timeline style="border: 2px solid #7a7a7a; margin: 2em 0">
<button is="rd-event" id="play-song-event" popovertarget="play-song-event-tooltip" style="--event-x: 8; --width: 2">
</button>
<rd-tooltip id="play-song-event-tooltip" popover anchor="play-song-event" style='
display: grid;
grid-template:
". a a a a a a a a ." 1fr
". . b b b c c c . ." 1fr / 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr;
align-items: center;
gap: 4px;
'>
<input class="dark align-center" value="sndOrientalTechno" disabled style="grid-area: a">
<span class="rd-text-stroke" style="grid-area: b">BPM:</span>
<input class="align-right" value="100" disabled style="grid-area: c">
</rd-tooltip>
<button is="rd-event" id="set-crotchets-event" popovertarget="set-crotchets-event-tooltip" style="--event-x: 9; --event-y: 1; --y: 1">
</button>
<rd-tooltip id="set-crotchets-event-tooltip" popover anchor="set-crotchets-event" style='
display: grid;
grid-template:
". a a a a a b b b ." 1fr
". c c c c c d d d ." 1fr / 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr;
align-items: center;
gap: 4px;
'>
<span class="rd-text-stroke" style="grid-area: a">四分音符数</span>
<input class="align-center" value="4" disabled style="grid-area: b">
<span class="rd-text-stroke" style="grid-area: c">节拍视效倍率</span>
<input class="align-center" value="1" disabled style="grid-area: d">
</rd-tooltip>
<button is="rd-event" style="--event-x: 8; --event-y: 2; --x: 5">
</button>
<button is="rd-event" style="--event-x: 9; --event-y: 2; --x: 6">
</button>
<button is="rd-event" style="--event-x: 10; --event-y: 2; --x: 7">
</button>
<button is="rd-event" style="--event-x: 11; --event-y: 2; --x: 8">
</button>
<button is="rd-event" style="--event-x: 12; --event-y: 2; --x: 9">
</button>
<button is="rd-beat" style="--x: 8; --y: 1; --width: 6">
<rd-pulse></rd-pulse>
<rd-pulse style="--x: 1"></rd-pulse>
<rd-pulse style="--x: 2"></rd-pulse>
<rd-pulse style="--x: 3"></rd-pulse>
<rd-pulse style="--x: 4"></rd-pulse>
<rd-pulse style="--x: 5"></rd-pulse>
<rd-pulse type="hit" style="--x: 6"></rd-pulse>
</button>
<button is="rd-beat" style="--x: 15.5; --y: 1; --width: 3">
<rd-effect type="hold" style="--x: 3; --width: 0.5"></rd-effect>
<rd-pulse></rd-pulse>
<rd-pulse style="--x: 0.5"></rd-pulse>
<rd-pulse style="--x: 1.0"></rd-pulse>
<rd-pulse style="--x: 1.5"></rd-pulse>
<rd-pulse style="--x: 2.0"></rd-pulse>
<rd-pulse style="--x: 2.5"></rd-pulse>
<rd-pulse type="hit" style="--x: 3"></rd-pulse>
</button>
<button is="rd-beat" style="--x: 9; --y: 2; --width: 3">
<rd-pulse></rd-pulse>
<rd-pulse style="--x: 2"></rd-pulse>
<rd-pulse type="hit" style="--x: 1"></rd-pulse>
<rd-pulse type="hit" style="--x: 3"></rd-pulse>
</button>
<button is="rd-beat" style="--x: 13; --y: 2; --width: 1.5">
<rd-pulse></rd-pulse>
<rd-pulse type="freeze" style="--x: 1"></rd-pulse>
<rd-pulse type="hit" style="--x: 1.5"></rd-pulse>
<rd-pulse type="cue" style="--x: -1"></rd-pulse>
<rd-pulse type="cue" style="--x: -0.5"></rd-pulse>
</button>
<button is="rd-beat" style="--x: 15; --y: 2">
<rd-pulse></rd-pulse>
<rd-pulse type="hit" style="--x: 1"></rd-pulse>
</button>
<button is="rd-beat" style="--x: 17; --y: 2; --width: 0.5">
<rd-pulse></rd-pulse>
<rd-pulse type="burn" style="--x: 0.5"></rd-pulse>
<rd-pulse type="hit" style="--x: 0.5"></rd-pulse>
<rd-pulse type="cue" style="--x: -1"></rd-pulse>
<rd-pulse type="cue" style="--x: -0.5"></rd-pulse>
</button>
<button is="rd-beat" style="--x: 20; --y: 2; --width: 0">
<rd-pulse></rd-pulse>
<rd-pulse type="hit"></rd-pulse>
</button>
<button is="rd-beat" style="--x: 21; --y: 2">
<rd-effect type="subdiv" style="--x: 1; --width: 0.667"></rd-effect>
<rd-effect type="skip" style="--x: 1.667; --width: 1.333"></rd-effect>
<rd-pulse></rd-pulse>
<rd-pulse type="subpulse" style="--x: 0.333"></rd-pulse>
<rd-pulse type="subpulse" style="--x: 0.667"></rd-pulse>
<rd-pulse type="subhit" style="--x: 1.333"></rd-pulse>
<rd-pulse type="subhit" style="--x: 1.667"></rd-pulse>
<rd-pulse type="hit" style="--x: 1"></rd-pulse>
<rd-pulse type="skip" style="--x: 3"></rd-pulse>
</button>
<button is="rd-event" style="--event-x: 17; --x: 40; --y: 1">
<rd-indicator type="conditional-mixed"></rd-indicator>
<rd-indicator type="tagged"></rd-indicator>
</button>
</rd-timeline>
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.