场景读取与运行相机
SDK 1.3 新增了两项内容。
| 成员 | 作用 |
|---|---|
host.Scene | 读取场景 Actor(相机 · 路径 · 触发区域 · 显示 …)。 |
host.View | 读取运行状态和时钟,并在运行中移动视口相机。 |
借此可以在运行预览中制作相机演出(环绕 · 缩放 · 沿路径移动)。在 plugin.json 中写 "sdk": "^1.3"。需要编辑器 0.9.1 及以上。
场景 Actor:INpScene
Section titled “场景 Actor:INpScene”| 成员 | 类型 | 说明 |
|---|---|---|
Actors | IReadOnlyList<NpSceneActor> | 全部场景 Actor(大纲顺序)。每次调用都是从当前世界重新读取的副本。 |
Find(string id) | NpSceneActor? | 按 id 查找。没有时为 null |
public sealed record NpSceneActor(string Id, string Kind, string Name, NpVec3 Pos, NpVec3 Rot, NpVec3 Size, string PropsJson = "{}");| 字段 | 说明 |
|---|---|
Id | Actor id(世界逻辑使用的名称) |
Kind | 种类(camera · path · trigger · blocker · display · text · spawn · light · sound …) |
Name | 大纲中显示的名称 |
Pos | 位置(世界坐标,一个方块格 = 1) |
Rot | (yaw, pitch, roll) Minecraft 角度 |
Size | 触发区域 · 阻挡框为框的尺寸,其他为缩放倍率 |
PropsJson | 属性对象的 JSON 字符串。没有时为 "{}" |
- 这是编辑时的样子,而不是运行中因动画而移动后的姿态。
- Actor 较多时
Actors开销较大。不要在PlayTicked中每次调用,而应在运行开始时读取一次并保存。 PropsJson用System.Text.Json读取。例:相机的fov、路径的points(世界坐标[[x,y,z],…])。
| 值 | 含义 |
|---|---|
| yaw 0 | 朝向 +Z(南) |
| yaw 90 | 朝向 −X(西) |
| pitch 0 | 水平 |
| pitch 90 | 朝下 |
与 Minecraft F3 画面中的角度规则相同。NpSceneActor.Rot 和 INpView 的角度使用相同规则。
foreach (var a in host.Scene.Actors) if (a.Kind == "camera") host.Log($"{a.Id} {a.Name} {a.Pos} yaw {a.Rot.X} pitch {a.Rot.Y}");
if (host.Scene.Find("route") is { } path){ using var doc = System.Text.Json.JsonDocument.Parse(path.PropsJson); // doc.RootElement.GetProperty("points") …}视口 · 运行:INpView
Section titled “视口 · 运行:INpView”| 成员 | 类型 | 说明 |
|---|---|---|
Playing | bool | 是否正在运行或模拟 |
PlayTime | double | 运行时钟(秒)。开始 = 0,暂停时停止。未运行时为 0 |
CameraPos | NpVec3 | 当前相机位置 |
CameraYaw · CameraPitch | float | 当前相机角度(Minecraft 角度) |
CameraFov | float | 当前视野角(度) |
SetCamera(NpVec3 pos, float yaw, float pitch, float fov = 0) | bool | 将相机移到该位置 · 方向。成功时返回 true |
LookAt(NpVec3 target, float fov = 0) | bool | 从当前位置(此插件最后放置的位置)看向 target |
LookAt(NpVec3 eye, NpVec3 target, float fov = 0) | bool | 从 eye 看向 target |
ReleaseCamera() | void | 解除此插件对相机的控制(恢复原视角) |
PlayChanged | event Action<bool>? | 运行开始(true) · 结束(false) |
PlayTicked | event Action<double>? | 运行时钟每个 tick(0.05 秒)。值 = 经过的秒数 |
相机移动规则
Section titled “相机移动规则”| 规则 | 内容 |
|---|---|
| 何时有效 | 仅在运行 · 模拟期间。否则返回 false,不做任何事。 |
| 移动 | 调用一次就停在该位置。要持续移动,需在 PlayTicked 中每个 tick 调用。 |
| 第一人称身体 | 移动相机期间,运行中的身体停止。 |
fov | 0 及以下 = 保持当前视野角。其他值限制在 30 ~ 110 度。 |
| 错误的值 | 无穷大 · NaN 位置、眼睛与目标相同的 LookAt 返回 false |
| 恢复 | ReleaseCamera() · 停止运行(Esc) · 禁用插件 · 隔离时,恢复原视角(运行 = 身体眼睛位置,模拟 = 自由相机)和视野角。 |
| 多方控制时 | 与内置动作 cinematic 的预览使用同一通道。同一 tick 中有多方移动时,后设置者优先。 |
示例:运行中 6 秒环绕相机
Section titled “示例:运行中 6 秒环绕相机”在控制台输入 myorbit,相机将围绕 (0, 70, 0) 旋转 6 秒。
double t = 0; bool on = false;
host.AddCommand(new NpCommand("myorbit", "myorbit", "플레이 중 6초 궤도 카메라", _ =>{ if (!host.View.Playing) return "먼저 플레이를 시작하세요"; on = true; t = 0; return "시작";}));
host.View.PlayChanged += playing => { if (!playing) on = false; };host.View.PlayTicked += dt =>{ if (!on) return; t += dt; var c = new NpVec3(0, 70, 0); var eye = new NpVec3(c.X + 30 * (float)Math.Cos(t), 85, c.Z + 30 * (float)Math.Sin(t)); host.View.LookAt(eye, c, fov: 60); if (t > 6) { on = false; host.View.ReleaseCamera(); }};示例:用场景相机 Actor 缩放
Section titled “示例:用场景相机 Actor 缩放”host.View.PlayTicked += dt =>{ if (!_running) return; _t += dt; var cam = host.Scene.Find("cam_zoom_1"); if (cam == null) { _running = false; return; } host.View.SetCamera(cam.Pos, cam.Rot.X, cam.Rot.Y, fov: 70 - (float)_t * 5); // 缩小视野角实现放大 if (_t > 6) { _running = false; host.View.ReleaseCamera(); }};提示 / 注意
Section titled “提示 / 注意”PlayTicked每 0.05 秒调用一次,请写得轻量。- 内置动作
cinematic已能实现相机演出(多个相机 · 路径 · 停留 · 移动)。若用AddSceneEvent注册同名 type,会与内置重名,插件将无法启用。若要单独做演出,不要注册 type,只使用Scene·View。 - 相机演出仅用于编辑器预览。游戏服务器中的相机由服务器插件负责。
- 目前还没有创建或移动场景 Actor 的 API,只能读取。