镜头路径运镜
镜头路径用于制作过场动画、剧情演出、副本开场、NPC 对话镜头和教学引导。你可以先在客户端录制一串镜头点位,再把路径保存到服务端,后续让任意玩家播放同一条运镜。
这项功能需要客户端 GermMod 和服务端 GermPlugin 同时支持。客户端负责录制、编辑和播放镜头;服务端负责 保存路径配置、通过 misc source 下发路径,并提供插件 API。
开启 Camera2 镜头
镜头路径依赖沉浸式第三人称镜头。播放前先确保玩家客户端开启了这个选项:
updateClient<->engineConfig@enableImmersiveThirdPersonCamera@true
如果需要让角色在镜头中心附近有一段小范围活动区,请在服务端 Config.yml 的 ClientOptions.PlayerPerspective 中配置 immersiveDeadZone 和 immersiveDeadZoneXZ。
录制路径
录制时,客户端会把当前镜头位置、yaw、pitch、roll、FOV 和点位速度写入路径。路径至少需要 2 个点才能播放。
camera<->immersive@path@record@start
camera<->immersive@path@mark
camera<->immersive@path@mark@speed=1.2
camera<->immersive@path@mark@yaw=90@pitch=10@roll=0@fov=8@speed=1.4
camera<->immersive@path@record@stop
录制开始后,可以直接按 P 标记当前镜头点。这个快捷键等价于执行 camera<->immersive@path@mark,适合一边走位一边快速打点。
如果需要给某个点指定角度、FOV 或速度,仍然使用带参数的 mark 命令:
camera<->immersive@path@mark@yaw=90@pitch=10@roll=0@fov=8@speed=1.4
常用点位参数:
| 参数 | 说明 |
|---|---|
yaw | 覆盖当前点的水平朝向 |
pitch | 覆盖当前点的俯仰角 |
roll | 覆盖当前点的镜头侧倾 |
fov | 覆盖当前点的 FOV 偏移 |
speed | 当前点的速度权重,范围约为 0.15 到 6.0 |
播放 路径
camera<->immersive@path@play@duration=6000@mode=remote@ease=smooth
常用播放参数:
| 参数 | 示例 | 说明 |
|---|---|---|
duration | duration=6000 | 播放时长,单位毫秒;不填时按路径距离自动计算 |
mode | mode=remote | remote 为分离镜头,默认是第三人称镜头 |
start | start=current | 从当前镜头位置接入路径;默认从录制的第一个点开始 |
collision / collide | collision=false | 是否保留第三人称镜头碰撞 |
restore | restore=true | 分离镜头结束后是否恢复原视角 |
view | view=first | 分离镜头播放时是否强制第一人称显示 |
ease | ease=smooth | 使用缓入缓出的时间曲线;不填时为匀速 |
进入编辑模式时,如果没有显式填写 restore,客户端默认会在退出编辑后恢复原视角。
mode=remote 未显式填写 collision 时,默认不使用第三人称碰撞回缩,镜头会严格按路径点飞行。
分离镜头模式
mode=remote 会让相机脱离玩家本体,直接沿路径点移动镜头位置和朝向。它适合不希望镜头受玩家当前位置、碰撞或第三人称跟随影响的场景,例如剧情过场、Boss 登场、地图巡览、出生点介绍和教学引导。
camera<->immersive@path@play@mode=remote@start=current@duration=7000@ease=smooth@restore=true@view=first
常用参数:
| 参数 | 作用 |
|---|---|
mode=remote | 使用分离镜头播放路径 |
start=current | 从玩家当前镜头接入路径,减少突然跳镜头 |
restore=true | 播放结束后恢复玩家原来的视角 |
restore=false | 播放结束后保留分离镜头状态,交给后续 DOS 继续控制 |
view=first | 播放期间强制第一人称显示,避免玩家模型挡住镜头 |
collision=false | 不使用第三人称碰撞回缩,适合完全按路径点飞行 |
collision=true | 保留第三人称碰撞回缩,适合室内展示或不希望镜头穿墙的路径 |
如果要做一段完整过场,通常建议使用 restore=true,让玩家播放结束后回到原视角:
camera<->immersive@path@server@play@spawn_intro
这条命令会使用 spawn_intro 在 immersive_camera_paths.yml 中的 options。如果希望它按 remote、start=current、duration=7000 这类参数播放,请在该路径的 options 里配置。
如果路径在狭窄建筑里移动,希望镜头遇到墙体时仍然回缩,可以显式开启碰撞:
camera<->immersive@path@play@mode=remote@duration=5000@collision=true@restore=true
如果后续还要接 remoteCamera 或其他镜头 DOS,可以使用 restore=false,让镜头不要立刻还原:
camera<->immersive@path@play@mode=remote@duration=5000@restore=false
编辑模式也会使用这些默认值。直接执行 camera<->immersive@path@edit@start 时,客户端默认按分离镜头、第一人称显示、不使用碰撞回缩,并在退出编辑后恢复玩家原视角。需要特殊衔接时再显式传 restore=false。
分离镜头只改变玩家看到的相机,不会移动玩家真实坐标,也不会改变服务端碰撞、攻击、移动或其他判定。
停止当前路径播放:
camera<->immersive@path@stop
清空客户端当前路径:
camera<->immersive@path@clear
编辑路径
编辑模式会显示镜头路径 HUD,适合一边预览一边调整镜头。
camera<->immersive@path@edit@start@mode=remote@start=current@duration=8000@ease=smooth
编辑时可用命令:
camera<->immersive@path@edit@pause
camera<->immersive@path@edit@mode
camera<->immersive@path@edit@stop
快捷键说明:
| 状态 | 操作 |
|---|---|
| 预览飞行 | Space 暂停并编辑当前点,Tab 切换编辑模式 |
| 姿态模式 | W/S 调整俯仰,A/D 调整横滚,Q/E 或左右箭头调整偏航,滚轮调整 FOV |
| 点位模式 | W/S 前后,A/D 左右,Q/E 上下,滚轮调整 FOV |
| 暂停编辑 | +/- 调整当前点速度,Space 保存并继续预览 |
编辑器打开时,客户端会接管这些快捷键和滚轮输入,避免同时触发原版移动、快捷栏滚动、其他按键绑定或缓存重载。退出编辑后,按键会恢复原来的行为。
输入保护会同时处理按下和持续按住的状态。也就是说,连续按住 W/S/A/D/Q/E 微调镜头时,原版移动键不会在后台积压;用滚轮调整 FOV 时不会切换快捷栏;编辑器打开时按 P 不会触发 GermCache 重载。
如果需要确认当前编辑状态,可以随时查看聊天栏反馈中的 editing、paused、editMode 和 editSpeed:
camera<->immersive@path@status
保存到服务端
录制好的路径可以保存到 GermPlugin 的数据目录,便于后续重复使用。
camera<->immersive@path@server@save@spawn_intro
服务端会保存为:
plugins/GermPlugin/misc/immersive_camera_paths.yml
路径会写成 misc source 中的一条 type: immersiveCameraPath 配置。路径名建议只使用英文、数字、下划线和中划线,例如 spawn_intro、boss_start_01。不要在路径名里使用点号,点号在 YAML 路径里容易被当成多级节点。
保存后的配置大致如下:
spawn_intro:
type: immersiveCameraPath
path: '{"version":1,"points":[...]}'
options:
duration: 0
mode: third
start: recorded
collision: true
restore: false
view: false
ease: linear
editOptions:
duration: 0
mode: remote
start: recorded
collision: false
restore: true
view: first
ease: linear
options 控制按名称播放时的默认行为,editOptions 控制按名称进入编辑时的默认行为。想让服务端命令或 API 按固定参数播放同一条路径,应修改这两个 YAML 子项,而不是把大量播放参数塞进服务端命令尾部。
服务端路径命令:
camera<->immersive@path@server@list
camera<->immersive@path@server@load@spawn_intro
camera<->immersive@path@server@play@spawn_intro
camera<->immersive@path@server@edit@spawn_intro
camera<->immersive@path@server@delete@spawn_intro
save 和 delete 需要玩家是 OP,避免普通玩家覆盖或删除服务器镜头配置。服务端 API 发起的录制保存会给目标玩家一个短时间保存许可,用于完成“服务端开始录制 -> 玩家客户端上报路径 -> 服务端落盘”的闭环。
server@load 会把服务端路径 source 下发到客户端待用;server@play 和 server@edit 会先下发 source,再发送对应的客户端播放或编辑 DOS。客户端收到 source 后,会按路径名缓存到本地,后续可以直接执行:
camera<->immersive@path@play@spawn_intro
camera<->immersive@path@edit@start@spawn_intro
状态与反馈
不带具体动作时,camera<->immersive@path 会在客户端聊天栏输出当前路径状态:
camera<->immersive@path
状态里会包含这些信息:
| 字段 | 含义 |
|---|---|
points | 当前客户端路径点数量 |
recording | 是否正在录制 |
playing | 是否正在播放 |
mode | 当前播放模式,third_person 或 remote |
editing / paused | 是否处于编辑器、是否暂停在当前点 |
editMode | 当前编辑模式,姿态或点位 |
editSpeed | 当前编辑点速度 |
timeCurve | 播放时间曲线,smooth 或 linear |
durationMs | 当前播放时长 |
服务端路径命令也会把处理结果返回给客户端。例如:
camera<->immersive@path@server@list
camera<->immersive@path@server@load@spawn_intro
camera<->immersive@path@server@delete@spawn_intro
常见反馈:
| 反馈 | 说明 |
|---|---|
immersive camera path list: empty | 服务端还没有保存任何路径 |
immersive camera path not found: spawn_intro | 指定路径不存在 |
immersive camera path saved: spawn_intro | 路径已经保存到服务端 |
immersive camera path delete denied: operator required | 删除路径需要 OP 权限 |
immersive camera path source loaded: spawn_intro | 服务端路径 source 已下发到客户端待用 |
插件 API
插件开发者可以通过 GermPacketAPI 管理和播放镜头路径:
GermPacketAPI.saveCameraPath("spawn_intro", pathJson);
String json = GermPacketAPI.loadCameraPath("spawn_intro");
GermPacketAPI.sendCameraPath(player, "spawn_intro", json);
GermPacketAPI.playCameraPath(player, "spawn_intro");
GermPacketAPI.editCameraPath(player, "spawn_intro");
可用 API:
| 方法 | 用途 |
|---|---|
saveCameraPath(name, pathJson) | 保存路径 JSON |
loadCameraPath(name) | 读取路径 JSON |
deleteCameraPath(name) | 删除路径配置 |
listCameraPaths() | 列出已保存路径 |
sendCameraPath(player, name, pathJson) | 直接把 JSON 导入客户端当前路径,不注册为命名路径 |
loadCameraPath(player, name) | 从服务端读取并下发 misc source |
playCameraPath(player, name) | 下发 source 后按名称播放 |
editCameraPath(player, name) | 下发 source 后按名称进入编辑 |
涉及文件读取的方法会抛出 IOException,请在调用方处理异常。
如果 插件需要临时 JSON 并用自定义参数播放,可以先用 sendCameraPath 导入到客户端当前路径,再发送本地播放 DOS:
GermPacketAPI.sendCameraPath(player, "boss_intro_temp", pathJson);
GermPacketAPI.sendHudDos(player, "camera<->immersive@path@play@mode=remote@duration=6000@ease=smooth");
如果是服务端路径库中的命名路径,播放参数请写在 plugins/GermPlugin/misc/immersive_camera_paths.yml 的 options 或 editOptions 中。
路径 JSON 格式
客户端录制并保存到服务端的路径,本质上是一段 JSON。标准格式如下:
{
"version": 1,
"points": [
{
"x": 0.0,
"y": 72.0,
"z": 0.0,
"yaw": 0.0,
"pitch": 8.0,
"roll": 0.0,
"fov": 0.0,
"speed": 1.0
},
{
"x": 8.0,
"y": 74.0,
"z": -6.0,
"yaw": 45.0,
"pitch": 12.0,
"roll": 0.0,
"fov": 6.0,
"speed": 1.4
}
]
}
字段说明:
| 字段 | 说明 |
|---|---|
x / y / z | 镜头点的世界坐标 |
yaw | 镜头水平朝向,客户端会自动规整角度 |
pitch | 镜头俯仰角,会限制在 -90 到 90 |
roll | 镜头侧倾角 |
fov | FOV 偏移 |
speed | 该点的速度权重,越大越快 |
客户端导入时也支持直接传 points 数组:
[
{"x": 0, "y": 72, "z": 0, "yaw": 0, "pitch": 8},
{"x": 8, "y": 74, "z": -6, "yaw": 45, "pitch": 12}
]
缺省字段会使用默认值:坐标和角度默认为 0,speed 默认为 1。实际制作路径时,建议至少写 x、y、z、yaw、pitch。
插件可以直接生成 JSON 并下发给玩家:
String pathJson = "{\"version\":1,\"points\":["
+ "{\"x\":0,\"y\":72,\"z\":0,\"yaw\":0,\"pitch\":8,\"roll\":0,\"fov\":0,\"speed\":1},"
+ "{\"x\":8,\"y\":74,\"z\":-6,\"yaw\":45,\"pitch\":12,\"roll\":0,\"fov\":6,\"speed\":1.4}"
+ "]}";
GermPacketAPI.sendCameraPath(player, "boss_intro_temp", pathJson);
GermPacketAPI.sendHudDos(player, "camera<->immersive@path@play@mode=remote@duration=6000@ease=smooth");
也可以先保存到服务端路径库, 再按名称复用:
GermPacketAPI.saveCameraPath("boss_intro", pathJson);
GermPacketAPI.playCameraPath(player, "boss_intro");
路径会保存到服务端 misc source 文件中。建议路径名只使用英文、数字、下划线和中划线,例如 boss_intro_01 会写入:
plugins/GermPlugin/misc/immersive_camera_paths.yml