跳到主要内容

镜头路径运镜

镜头路径用于制作过场动画、剧情演出、副本开场、NPC 对话镜头和教学引导。你可以先在客户端录制一串镜头点位,再把路径保存到服务端,后续让任意玩家播放同一条运镜。

这项功能需要客户端 GermMod 和服务端 GermPlugin 同时支持。客户端负责录制、编辑和播放镜头;服务端负责保存路径配置、通过 misc source 下发路径,并提供插件 API。

开启 Camera2 镜头

镜头路径依赖沉浸式第三人称镜头。播放前先确保玩家客户端开启了这个选项:

updateClient<->engineConfig@enableImmersiveThirdPersonCamera@true

如果需要让角色在镜头中心附近有一段小范围活动区,请在服务端 Config.ymlClientOptions.PlayerPerspective 中配置 immersiveDeadZoneimmersiveDeadZoneXZ

录制路径

录制时,客户端会把当前镜头位置、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.156.0

播放路径

camera<->immersive@path@play@duration=6000@mode=remote@ease=smooth

常用播放参数:

参数示例说明
durationduration=6000播放时长,单位毫秒;不填时按路径距离自动计算
modemode=remoteremote 为分离镜头,默认是第三人称镜头
startstart=current从当前镜头位置接入路径;默认从录制的第一个点开始
collision / collidecollision=false是否保留第三人称镜头碰撞
restorerestore=true分离镜头结束后是否恢复原视角
viewview=first分离镜头播放时是否强制第一人称显示
easeease=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_introimmersive_camera_paths.yml 中的 options。如果希望它按 remotestart=currentduration=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 重载。

如果需要确认当前编辑状态,可以随时查看聊天栏反馈中的 editingpausededitModeeditSpeed

camera<->immersive@path@status

保存到服务端

录制好的路径可以保存到 GermPlugin 的数据目录,便于后续重复使用。

camera<->immersive@path@server@save@spawn_intro

服务端会保存为:

plugins/GermPlugin/misc/immersive_camera_paths.yml

路径会写成 misc source 中的一条 type: immersiveCameraPath 配置。路径名建议只使用英文、数字、下划线和中划线,例如 spawn_introboss_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

savedelete 需要玩家是 OP,避免普通玩家覆盖或删除服务器镜头配置。服务端 API 发起的录制保存会给目标玩家一个短时间保存许可,用于完成“服务端开始录制 -> 玩家客户端上报路径 -> 服务端落盘”的闭环。

server@load 会把服务端路径 source 下发到客户端待用;server@playserver@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_personremote
editing / paused是否处于编辑器、是否暂停在当前点
editMode当前编辑模式,姿态或点位
editSpeed当前编辑点速度
timeCurve播放时间曲线,smoothlinear
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.ymloptionseditOptions 中。

路径 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镜头俯仰角,会限制在 -9090
roll镜头侧倾角
fovFOV 偏移
speed该点的速度权重,越大越快

客户端导入时也支持直接传 points 数组:

[
{"x": 0, "y": 72, "z": 0, "yaw": 0, "pitch": 8},
{"x": 8, "y": 74, "z": -6, "yaw": 45, "pitch": 12}
]

缺省字段会使用默认值:坐标和角度默认为 0speed 默认为 1。实际制作路径时,建议至少写 xyzyawpitch

插件可以直接生成 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