LPAI AI 游戏编辑器文档

特效系统

客户端特效系统

特效系统 给控件、对象和页面加上临时视觉效果 `客户端特效系统` 只负责画面上的表现,例如飘字、高亮、抖动、悬浮提示、跟手提示。它不负责改属性,也不负责推进剧情。 # 最常见能做什么 飘字 移入高亮 受击抖动 按钮发光 跟手提示 局部遮罩 # 1. 最常用的 3 个方法 方法 用途 tools.runClie

特效系统

给控件、对象和页面加上临时视觉效果

`客户端特效系统` 只负责画面上的表现,例如飘字、高亮、抖动、悬浮提示、跟手提示。它不负责改属性,也不负责推进剧情。

# 最常见能做什么

  • 飘字
  • 移入高亮
  • 受击抖动
  • 按钮发光
  • 跟手提示
  • 局部遮罩

# 1. 最常用的 3 个方法

方法 用途
tools.runClientEffect(script, options?) 启动一个画面特效
tools.disposeClientEffect(label) label 结束一个特效
tools.clearClientEffects() 清空当前页面全部特效

# 2. 最重要的理解:有外层脚本和内层脚本

你平时在编辑器里写的,是外层脚本:

tools.runClientEffect("...");

真正负责演出的,是传进去的那段字符串脚本:

tools.runClientEffect(`
  const current = api.getTarget();
  if (!current) return;
`);

这两层不是一回事。

# 外层脚本里常用什么

  • player
  • objects
  • tools

# 内层特效脚本里常用什么

  • api
  • payload
  • target
  • targets
  • session
  • pointer

# 3. 最简单的启动方式

tools.runClientEffect(`
  const current = api.getTarget();
  if (!current) return;

  current.setStyle({
    outline: "2px solid rgba(255,255,255,0.65)"
  });
`, {
  target: "攻击按钮",
  label: "attack-highlight"
});

# 4. options 里最常用的字段

字段 用途
payload 传数据给特效脚本
target 指定一个目标控件
targets 指定多个目标控件
waitMs 特效结束后额外保留多久
label 给这个特效起一个稳定名字
mode 一次性特效用 replace,保留更新用 update

# 5. target 可以怎么写

# 直接传控件 ID

tools.runClientEffect(script, {
  target: "攻击按钮"
});

# 传对象控件目标

tools.runClientEffect(script, {
  target: { itemId: "装备按钮", objectId: "对象ID" }
});

# 传多个目标

tools.runClientEffect(script, {
  targets: ["主按钮", "副按钮"]
});

# 6. 最常见的几种效果

# 飘字

tools.runClientEffect(`
  api.createText(payload.text || "-10", {
    style: {
      color: "#fff",
      fontSize: "18px",
      textShadow: "0 2px 8px rgba(0,0,0,0.45)"
    }
  }).place({
    target: api.getTarget(),
    offsetY: -20
  });
`, {
  payload: { text: "-10" },
  target: "攻击按钮",
  label: "damage-float"
});

# 高亮

tools.runClientEffect(`
  const current = api.getTarget();
  if (!current) return;

  current.setStyle({
    filter: "brightness(1.15)"
  });
`, {
  target: "主按钮",
  label: "btn-highlight"
});

# 清掉效果

tools.disposeClientEffect("btn-highlight");

# 7. 在 replaceupdate 之间选择

mode 决定同一个 label 的特效如何继续:

模式 行为 适合场景
replace 默认模式。同 label 的新请求会销毁旧会话。 飘字、抖动、闪烁、按顺序播放的动画
update 同 label 的新请求复用原会话和其中的 keyed 节点。 跟手提示、拖拽预览、位置或尺寸连续变化

update 必须提供稳定且非空的 label。它会一直保留到调用 tools.disposeClientEffect(label)tools.clearClientEffects()、页面切换或脚本执行失败。

# 8. 用 upsert 保留同一个 DOM 节点

update 特效内部要用稳定 key 调用:

api.upsertNode(key, options);
api.upsertText(key, text, options);

第一次调用创建节点。之后使用相同特效 label 和节点 key,会 patch 同一个 DOM,而不是删除重建。options 可以更新内容、HTML、类名、属性、样式、父节点、位置和 motion。

api.upsertText("tip", payload.text, {
  placement: {
    x: payload.x,
    y: payload.y,
    offsetX: 12,
    offsetY: -10,
    selfX: 0,
    selfY: 1
  },
  motion: {
    durationMs: 80,
    easing: "linear",
    position: true,
    size: false
  }
});

motion.position 会插值 left/topmotion.size 会插值 width/height。连续提交新目标时,浏览器会把当前 transition 重定向到最新目标,因此补帧不依赖游戏速度。不传 motion 就会立即跳到新值。

# 9. 跟手更新的完整写法

下面的外层脚本可以放在 js_move。每次触发只提交最新的指针位置:

const point = tools.kwargs.pointer;
const label = `pointer-tip-${tools.kwargs.itemID}`;
if (!point) return;

tools.runClientEffect(`
  api.upsertText("tip", payload.text, {
    style: {
      padding: "4px 8px",
      borderRadius: "6px",
      background: "rgba(15,23,42,0.9)",
      color: "#fff",
      pointerEvents: "none"
    },
    placement: {
      x: payload.x,
      y: payload.y,
      offsetX: 12,
      offsetY: -10,
      selfX: 0,
      selfY: 1
    },
    motion: { durationMs: 80, easing: "linear", position: true }
  });
`, {
  mode: "update",
  label,
  payload: { text: "查看详情", x: point.clientX, y: point.clientY }
});

这类 update 脚本不要使用 await api.wait(...)await node.animate(...) 或自己循环补帧。对应的 js_leave 用相同 label 清理。

# 10. 这类内容通常不放在特效系统里

下面这些内容更常写在普通脚本、事件或 AI 联动里:

  • 扣金币
  • 改属性
  • 创建对象
  • 推进主线
  • 决定 AI 能不能输入

一个简单判断方法是:

如果把这段效果删掉,真实状态还是对的,只是看起来没那么明显,那它就很适合放在特效系统里。

# 使用时要注意的几件事

  • runClientEffect 的第一个参数必须是一段字符串脚本。
  • 第二个参数如果传,必须是对象。
  • 内层特效脚本只能使用注入的 apipayloadtargettargetsruntimesessionpointer;运行时会遮蔽 windowdocumentlocalStoragefetchpostMessage 等浏览器能力,但不额外拦截普通 JavaScript 写法。
  • 一次性效果通常使用默认 replace;高频位置或尺寸更新使用 mode: "update"、稳定 label、稳定 upsert key,需要平滑时再配置 motion
  • 特效系统更适合做视觉反馈,核心状态仍然放在属性、事件或别的脚本里。

# 下一步

如果你准备把声音也做成前端脚本,可以继续看 客户端音效系统
如果你准备把特效挂到控件移入、移出、移动上,可以继续看 交互特效脚本