资源制作指南
音符皮肤等自定义资源的制作方法:图片皮肤 / 字符皮肤 / 模组图片加载
本页汇总游戏所有可以从外部导入的自定义资源,以及每种资源的制作 / 使用方式。大多数资源不需要编程:把文件放到正确的位置,游戏就会识别。
可导入资源总览
| 资源 | 存放目录 | 制作难度 | 说明 |
|---|---|---|---|
| 音符皮肤 | data/respack/ | 低 | 用图片或字符配置替换音符外观 |
| 谱面 | data/charts/ | 中 | 游戏内编辑器制作,或导入他人谱面 |
| 剧情文件 | data/sp_lang/story/ | 低 | 导入他人写的剧情文本 |
| 收藏品 | data/collect/ | 低 | 解锁图鉴条目 |
| 音效 | data/hitsound/ data/sound_effects/ | 低 | 替换判定 / 界面音效 |
| 音乐 | data/audio/ data/bgm/ | 低 | 谱面音乐与菜单 BGM |
| 界面语言 | data/lang/ | 低 | 文本翻译 |
| 窗口图标 | data/ths.ico | 低 | 替换游戏窗口图标 |
| 模组 | mods/(工作目录根) | 高 | 需要代码 / 脚本,见模组文档 |
所有 JSON 文件均使用 UTF-8 编码,并建议保持多行缩进格式。放入文件前建议先备份原文件。
音符皮肤
游戏启动时会扫描工作目录下的 data/respack/ 文件夹,把其中每个子文件夹识别为一个皮肤。
data/
└── respack/
├── RE-OST1.2/ ← 图片皮肤示例
└── neon/ ← 字符皮肤示例(含完整字段说明的 note.json)游戏内自带 Default(内置默认字符皮肤)始终置顶。手动把新文件夹放进 data/respack/ 后重启游戏(或下次进入皮肤列表时重新扫描)即可看到。
皮肤按内容分为两种类型:
- 图片皮肤(IMAGE):文件夹内包含 4 张指定名称的 PNG 图片。
- 字符皮肤(CHAR):文件夹内包含一份
note.json配置文件。
两种皮肤都支持为自定义音符类型补充专属外观条目(见下文「自定义音符类型的皮肤」)。
文件夹内同时存在 4 张图片与 note.json 时,优先按图片皮肤识别。既无图片也无 note.json 的文件夹会被标记为加载错误,在列表中显示,但不会生效。
图片皮肤
图片皮肤是最直观的自定义方式。用绘图软件画 4 张 PNG 即可。
文件清单
| 文件 | 推荐尺寸 | 作用 |
|---|---|---|
normal.png | 1000 × 100 | 普通音符(Tap) |
hold.png | 1000 × 1100 | 长按音符(Hold),三段式结构见下 |
exploit.png | 1000 × 100 | 双向音符(Exploit) |
payload.png | 1000 × 100 | 特殊音符(Payload) |
4 张图片缺一不可——缺少任意一张,整个文件夹无法按图片皮肤加载。
Hold 图片的三段式结构
长按音符的 hold.png 高度是 1100px,自上而下分为三段:
┌────────────────────────────┐
│ 0 ~ 100px 终点(判定线) │ ← 音符落下的判定线处显示这一段
├────────────────────────────┤
│ 100 ~ 1000px 主体 │ ← 起点到终点之间的柱体,按长度伸缩
├────────────────────────────┤
│ 1000 ~ 1100px 起点(按下点)│ ← 玩家按下音符的位置显示这一段
└────────────────────────────┘注意方向:图片顶部是判定线终点,底部是玩家按下的起点。绘制时游戏按轨道宽度等比缩放整张图。
尺寸不达标会怎样
图片尺寸只要可读取就会被加载;若与推荐尺寸不符,皮肤仍能使用,但会在皮肤列表中标记为「不规范」。宽度影响缩放比例,建议保持 1000px 宽以获得最佳显示效果。
制作建议
- 使用 PNG 格式并保留透明通道(
normal.png的透明区域不会遮挡轨道)。 - 高度方向上,
normal.png/exploit.png/payload.png的图案建议集中在中间区域,避免贴边裁切。 - 可参照
data/respack/下自带示例皮肤的图片进行修改。
字符皮肤
字符皮肤用文本字符拼出音符,占用的资源极小,且能与游戏的「增强音符渲染」发光效果配合。你只需要在文件夹里写一份 note.json。
note.json 结构
{
"name": "MySkin",
"normal": { "prefix": "|", "fill": "-", "core": "+", "suffix": "|", "color": "#00FFFF" },
"hold": { "prefix": "[", "fill": "=", "core": "*", "suffix": "]", "bodyChar": "|",
"endPrefix": "[", "endFill": "=", "endCore": "o", "endSuffix": "]",
"color": "#FF66CC", "enhancedColor": "#FF66CC", "enhancedBodyColor": "#FF66CC80" },
"exploit": { "prefix": "|", "fill": "-", "core": "x", "suffix": "|", "color": "#FFFF66" },
"payload": { "fill": ".", "core": "@", "color": "#66FF66" }
}name:皮肤显示名,在皮肤列表的 NAME 列展示(不填则使用文件夹名)。normal/hold/exploit/payload:四种音符各自的样式对象。缺省的对象回退为内置默认样式。- 完整的字段释义已写入自带示例
data/respack/neon/note.json的_comment_*键中,可直接打开对照。
样式字段表
| 字段 | 适用样式 | 说明 | |
|---|---|---|---|
prefix | 全部 | 音符最左侧的前缀字符(如 `\ | 、[`) |
fill | 全部 | 填充字符,按轨道宽度自适应重复填满中间区域 | |
core | 全部 | 中心核心字符(如 +、*、@),支持多字符 | |
suffix | 全部 | 音符最右侧的后缀字符(如 `\ | 、]`) |
bodyChar | hold | 主体竖线字符,从起点到终点在两侧重复绘制 | |
endPrefix | hold | 终点段的前缀字符(缺省复用 prefix) | |
endFill | hold | 终点段的填充字符(缺省复用 fill) | |
endCore | hold | 终点段的中心字符 | |
endSuffix | hold | 终点段的后缀字符(缺省复用 suffix) | |
color | 全部 | 默认颜色,格式 #RRGGBB 或 #RRGGBBAA(带透明度) | |
enhancedColor | 全部 | 开启「增强音符渲染」时的替代颜色 | |
enhancedBodyColor | hold | 增强渲染时主体竖线的颜色(建议带透明度) |
颜色只支持 #RRGGBB(不透明)与 #RRGGBBAA(前两位为透明度,如 #FF66CC80 即 80% 不透明)两种格式。
默认皮肤字符参考
内置默认皮肤使用的字符样式,可作为设计起点:
| 音符 | 外观 | 默认颜色 | 增强颜色 |
|---|---|---|---|
| Normal | ┼──◆──┼ | 白 | — |
| Hold 起点 | ╠══+══╣ | 白 | 蓝 (80,140,255) |
| Hold 主体 | ║ | 白 | 半透明蓝 |
| Hold 终点 | ╠══#══╣ | 白 | 蓝 |
| Exploit | ┼──▶◀─┼ | 白 | — |
| Payload | ···●··· | 白 | 橙 (255,140,20) |
字符建议使用 ASCII 或常见线框字符(| - + * x @ o [ ] = .)。避免使用 emoji 或生僻符号(如 、、◉)——它们在部分字体下会显示为方框。
自定义音符类型的皮肤
自定义音符类型(由模组注册,例如 laser、slide)默认复用其行为分类对应的外观槽位。想让它们拥有专属外观,只需在皮肤中按「类型 key」补充条目——类型 key 与谱面 JSON 中 note.type 字符串完全一致(区分大小写)。
图片皮肤:在皮肤文件夹内额外放一张 <类型key>.png。例如自定义类型 laser 就放 laser.png,原有的 4 张标准图保持不变:
data/respack/MyImageSkin/
├── normal.png ← 4 张标准图(缺一不可)
├── hold.png
├── exploit.png
├── payload.png
└── laser.png ← 自定义类型 "laser" 的专属图片(任意尺寸,按轨道宽度等比缩放)字符皮肤:在 note.json 中增加 custom 对象,每个 key 对应一个样式对象(字段与 normal / hold 等一致):
{
"name": "MySkin",
"normal": { "prefix": "|", "fill": "-", "core": "+", "suffix": "|", "color": "#00FFFF" },
"hold": { "prefix": "[", "fill": "=", "core": "*", "suffix": "]", "color": "#FF66CC" },
"exploit": { "prefix": "|", "fill": "-", "core": "x", "suffix": "|", "color": "#FFFF66" },
"payload": { "fill": ".", "core": "@", "color": "#66FF66" },
"custom": {
"laser": { "prefix": "<", "fill": "=", "core": "*", "suffix": ">", "color": "#00FF88" },
"slide": { "prefix": "(", "fill": "-", "core": "~", "suffix": ")", "color": "#88CCFF" }
}
}规则:
- 未提供专属外观时,自定义类型自动回退到行为分类对应的槽位:普通行为回退
normal、长按行为回退hold、漏洞利用回退exploit、载荷回退payload。 - 字符皮肤的
custom中也可以写内置类型名(如"normal")来整体覆写对应槽位;图片皮肤的内置 4 张图仍由标准文件名决定,不受影响。 - 长按行为的自定义类型若使用图片,图片仍需遵循
hold.png的三段式结构(顶部 100px 判定线终点 / 中间 900px 主体 / 底部 100px 起点)。
在游戏中应用皮肤
- 把皮肤文件夹放入
data/respack/。 - 启动游戏,进入 主菜单 → MAINTENANCE → visual_res.pkg(VISUAL RESOURCE PACK)。
- 列表中会显示所有皮肤:DEFAULT 置顶,其余按名称排序;每项展示名称、类型(图片/字符)与状态(已应用 / 正常 / 不规范 / 加载错误)。
- 选中皮肤按 ENTER 预览,确认效果后再次按 ENTER 应用。
- 选择会持久化到
userdata/settings.json的skin字段,下次启动保持生效。
皮肤限制
- 障碍音符(Barrier)不参与皮肤:始终以固定色块渲染,不受皮肤影响。
- 自定义音符类型已支持专属皮肤(图片
<类型key>.png/ 字符custom映射);未提供专属外观时回退到行为分类对应槽位。 - 图片皮肤不叠加增强渲染发光;字符皮肤在开启「增强音符渲染」时使用
enhancedColor/enhancedBodyColor发光。 - 没有游戏内导入界面:皮肤必须手动放入
data/respack/文件夹。 - 皮肤只改变音符外观,不影响判定、得分与玩法逻辑。
谱面
谱面是完整的可玩关卡文件,包含音乐引用、节拍与全部音符。一个 JSON 文件对应一首谱面。
制作谱面
游戏内置谱面编辑器:进入 主菜单 → [04] EDITOR,新建谱面并放置音符、设置 BPM 与音乐偏移。编辑器保存的谱面直接输出到 data/charts/ 目录。
导入谱面
别人制作好的谱面是一个 JSON 文件。导入步骤:
- 把
.json谱面文件放入data/charts/目录。 - 把谱面引用的音乐文件放入
data/audio/目录(谱面audio.file字段写文件名)。 - 进入游戏的文件夹谱面选择界面,谱面会按
metadata.folder字段分组显示。
注意
folder_index.json是章节索引文件,不要改名或删除;游戏会把以folder_index开头的文件排除出自由游玩列表。
谱面 JSON 结构
{
"version": 1,
"metadata": {
"title": "太陽風。",
"artist": "Unknown",
"charter": "Editor",
"illustrator": "Unknown",
"difficulty": "Easy",
"level": "1",
"folder": "uncategorized"
},
"audio": {
"file": "太陽風。.mp3",
"offset": 0,
"previewTime": 30000
},
"lanes": 4,
"scrollSpeed": 600.0,
"timingPoints": [ { "time": 0, "bpm": 155.0 } ],
"notes": [],
"markers": [],
"disorderMarkers": [],
"extraContent": null
}| 字段 | 说明 |
|---|---|
version | 谱面格式版本号 |
metadata | 曲名、作者、谱师、难度、等级,以及分组用的 folder |
audio.file | 音乐文件名,相对于 data/audio/ |
audio.offset | 音乐偏移(毫秒) |
audio.previewTime | 选曲试听起点(毫秒) |
lanes | 轨道数 |
scrollSpeed | 下落速度 |
timingPoints | 节拍点(时间 + BPM) |
notes | 音符数组 |
markers / disorderMarkers | 演出标记 / 乱序标记 |
extraContent | 谱面扩展数据(供模组的谱面扩展段消费) |
最简单的导入方式是先用编辑器做一首空谱面,再参照它的 JSON 结构修改。
官方章节谱面
data/charts/offical_charts/ 存放章节模式使用的内置谱面,通过 folder_index.json 建立索引。普通自定义谱面不需要放在这里。
谱面热重载
data/resources.json 中声明了资源目录:charts 与 audio 目录默认开启运行期检测(watch: true),放入新谱面或音乐文件后会触发重新加载;其余资源替换后需重启游戏。
剧情文件
剧情由两部分组成:故事登记(data/story.json,决定故事何时触发、解锁什么)与文本内容(data/sp_lang/story/,决定显示什么文字)。
导入别人做的剧情
若对方提供的是剧情文本文件(.json),把它复制到 data/sp_lang/story/ 目录即可:
data/sp_lang/story/
├── awakening_story_zh.json
├── daily_001_first_step_zh.json
└── ...文件命名规则:<故事ID>_<语言>.json,语言为 zh 或 en。
文本文件格式
剧情文本是一个字符串键值对文件,每个键的格式为 story.<故事ID>.t<序号>:
{
"story.daily_001_first_step.t0": "> 日志缓存 // 第一步",
"story.daily_001_first_step.t2": "Aria走出飞船。靴子踩在碎石和野草上,发出细碎的声响。",
"story.daily_001_first_step.t9": "「这真的是地球吗?」"
}新建一个故事
仅放文本文件不会被触发——故事的触发条件登记在 data/story.json 的 stories 数组中,主要字段:
| 字段 | 说明 |
|---|---|
id | 故事 ID,必须与文本文件名一致 |
type | 类型(如 locked、daily) |
sequence | 排序 |
showAfterUnlock | 章节进度达到多少后出现 |
showAfterStory | 前置故事 ID |
unlockSector / unlockCollect | 通关后解锁的扇区 / 收藏品 |
nextScene | 结束后进入的场景 |
bgText | 标题背景文字 |
界面文本
data/lang/zh.json 与 data/lang/en.json 存放全部界面文字(按钮、菜单、提示),同样为键值对。data/sp_lang/tips/<语言>_menu_tips.json 存放加载界面的提示语。
收藏品
data/collect/ 下每个 JSON 文件对应一个收藏品(图鉴条目):
{
"id": "collect_welcome",
"name": "WELCOME_LOGO",
"source": "System Default",
"brief": "终端启动时显示的标志。",
"unlockedByDefault": true,
"rewardLogs": 0,
"detail": "Theseus TERMINAL .1.0\n\n启动标志。"
}| 字段 | 说明 |
|---|---|
id | 唯一标识(建议以 collect_ 开头) |
name | 显示名称 |
source | 来源说明 |
brief | 列表中的简述 |
unlockedByDefault | 是否默认解锁 |
rewardLogs | 解锁奖励的日志数量 |
detail | 详情长文本(\n 换行) |
音效与音乐
替换已有音频
直接替换同名文件即可,无需改配置:
- 判定音效(打击 / 双向 / 长按等):
data/hitsound/*.wav - 界面音效(菜单移动、打开、提示等):
data/sound_effects/*.wav - 谱面音乐:
data/audio/,谱面audio.file指向的文件 - 菜单 BGM:
data/bgm/*.mp3
支持 wav / ogg / mp3 格式。
新增音频
需要编辑注册配置 data/audio_config.json,在 sounds 或 bgm 数组中追加条目:
{
"id": "my_sound",
"path": "data/sound_effects/my_sound.wav",
"type": "sound",
"usage": "ui_effect",
"format": "wav",
"preload": true,
"volume": 0.7
}| 字段 | 说明 |
|---|---|
id | 音频 ID(模组 / 场景按此引用) |
path | 文件路径 |
type | sound(音效)或 music(音乐) |
usage | 用途(hit_effect 判定音效 / ui_effect 界面音效 / background 背景乐) |
format | 文件格式 |
preload | 是否在加载动画阶段预载 |
volume | 音量 0.0 ~ 1.0 |
谱面音乐的基础路径在 audio_config.json 的 chart_music_base_path(默认 data/audio/)。
曲名显示
data/bgm_metadata.json 为 BGM 提供显示名,格式为 "曲名": "作者说明"。
窗口图标
data/ths.ico 是游戏窗口图标。把同名的 .ico 文件替换掉即可。
模组
mods/(工作目录根,与 data/ 同级)存放可加载的模组(Java jar 或 THS 脚本)。模组还可拥有自己的运行时数据目录 data/mods/<模组ID>/,用 ModContext 读写——两者用途不同:mods/ 存放可执行的模组本体,data/mods/<模组ID>/ 存放该模组的配置与数据。新放入的模组默认禁用,需在模组列表中手动启用。这属于进阶内容,见 快速上手 与 THS 简易语言。
打击特效图片(模组)
判定命中时的视觉反馈(打击特效)图片由模组提供,经 ResourceManager.loadImage 加载,无需配置 JSON:
| 项目 | 规格 |
|---|---|
| 存放位置 | 模组数据目录 data/mods/<模组ID>/ 或 jar 内 resources(随模组分发) |
| 格式 | PNG,保留透明通道 |
| 尺寸 | 无固定分辨率限制;绘制大小 = 图片分辨率 × scale(模组代码指定) |
| 锚点 | 以判定点为中心:水平居中于轨道中心、垂直居中于判定线 |
| 播放 | 非循环播完停最后一帧;循环则重复;整体透明度随判定强度(0~1)淡出 |
| 精灵图 | 一张图按网格切分(每格 cellWidth × cellHeight),从左到右、从上到下拆帧;不满一格的多余像素被忽略 |
制作方法与可复制示例见 API 参考 · HitEffectStyle 与 HitEffectStyles。
通用注意事项
- 所有 JSON 使用 UTF-8 编码,建议多行缩进书写。
- 大部分资源在启动时扫描 / 预加载,替换后需重启游戏生效;只有谱面与音频目录支持运行期热重载。
- 修改前备份原文件;格式错误的文件会被跳过并显示警告,不会导致游戏崩溃。
- 目录结构以当前版本为准,更新版本后建议重新查看本页。