跳转到内容

场景读取与运行相机

SDK 1.3 新增了两项内容。

成员作用
host.Scene读取场景 Actor(相机 · 路径 · 触发区域 · 显示 …)。
host.View读取运行状态和时钟,并在运行中移动视口相机。

借此可以在运行预览中制作相机演出(环绕 · 缩放 · 沿路径移动)。在 plugin.json 中写 "sdk": "^1.3"。需要编辑器 0.9.1 及以上。

成员类型说明
ActorsIReadOnlyList<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 = "{}");
字段说明
IdActor 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") …
}
成员类型说明
Playingbool是否正在运行或模拟
PlayTimedouble运行时钟(秒)。开始 = 0,暂停时停止。未运行时为 0
CameraPosNpVec3当前相机位置
CameraYaw · CameraPitchfloat当前相机角度(Minecraft 角度)
CameraFovfloat当前视野角(度)
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解除此插件对相机的控制(恢复原视角)
PlayChangedevent Action<bool>?运行开始(true) · 结束(false)
PlayTickedevent Action<double>?运行时钟每个 tick(0.05 秒)。值 = 经过的秒数
规则内容
何时有效仅在运行 · 模拟期间。否则返回 false,不做任何事。
移动调用一次就停在该位置。要持续移动,需在 PlayTicked 中每个 tick 调用。
第一人称身体移动相机期间,运行中的身体停止。
fov0 及以下 = 保持当前视野角。其他值限制在 30 ~ 110 度。
错误的值无穷大 · NaN 位置、眼睛与目标相同的 LookAt 返回 false
恢复ReleaseCamera() · 停止运行(Esc) · 禁用插件 · 隔离时,恢复原视角(运行 = 身体眼睛位置,模拟 = 自由相机)和视野角。
多方控制时与内置动作 cinematic 的预览使用同一通道。同一 tick 中有多方移动时,后设置者优先。

在控制台输入 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(); }
};
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(); }
};
  • PlayTicked 每 0.05 秒调用一次,请写得轻量。
  • 内置动作 cinematic 已能实现相机演出(多个相机 · 路径 · 停留 · 移动)。若用 AddSceneEvent 注册同名 type,会与内置重名,插件将无法启用。若要单独做演出,不要注册 type,只使用 Scene · View。
  • 相机演出仅用于编辑器预览。游戏服务器中的相机由服务器插件负责。
  • 目前还没有创建或移动场景 Actor 的 API,只能读取。