特效系统
交互特效脚本
特效系统 让控件在移入、移出、移动、长按时出现视觉反馈 交互特效脚本对应 4 个位置:`js_enter`、`js_leave`、`js_move`、`js_long`。它们最适合做移入高亮、悬浮提示、跟手提示、长按反馈这类交互表现。 # 先记住这 4 个入口 脚本 什么时候触发 js_enter 鼠标移入,
特效系统
让控件在移入、移出、移动、长按时出现视觉反馈
交互特效脚本对应 4 个位置:`js_enter`、`js_leave`、`js_move`、`js_long`。它们最适合做移入高亮、悬浮提示、跟手提示、长按反馈这类交互表现。
# 先记住这 4 个入口
| 脚本 | 什么时候触发 |
|---|---|
js_enter |
鼠标移入,或手机手指按下时 |
js_leave |
鼠标移出,或手机手指松开 / 取消时 |
js_move |
鼠标移动,或手指按住移动时 |
js_long |
鼠标主键按住,或手机手指持续按住,达到长按阈值时 |
# 1. 这类脚本最适合做什么
# js_enter
- 鼠标移入高亮
- 显示悬浮提示
- 按钮轻微放大
# js_leave
- 关闭悬浮提示
- 恢复默认样式
- 清理 hover 特效
# js_move
- 跟手提示
- 光标附近文字
- 局部聚光
# js_long
- 长按出现菜单
- 长按预览详情
- 长按触发一段强调特效或提示
# 2. 交互脚本本身更适合只做“特效入口”
交互脚本更常见的用法是:
- 读当前上下文
- 调
tools.runClientEffect(...) - 调
tools.disposeClientEffect(...) - 调
tools.clearClientEffects()
真正的结算和状态变化,通常会放在别的脚本位置:
- 扣金币
- 发奖励
- 写剧情日志
- 创建对象
- 发 AI 请求
# 3. 这里最容易搞混的一点
在手机上,这 4 个入口不是互斥关系:
- 鼠标移入通常会先触发
js_enter - 手机按下也会先触发
js_enter - 按住移动时会触发
js_move - 持续按住达到阈值后再触发
js_long - 最后松开或取消时触发
js_leave
在交互脚本本身里,能直接用的是:
playerobjectstools
而这些变量:
apitargettargetspointer
只在 tools.runClientEffect("...") 里面那段特效脚本里可用。
所以这是错的:
const target = api.getTarget();
可以这样写:
tools.runClientEffect(`
const target = api.getTarget();
if (!target) return;
`);
# 4. 当前脚本附带的信息
交互脚本里,常见会直接用这些值:
tools.kwargs.itemIDtools.kwargs.objecttools.kwargs.objIDtools.kwargs.effectTargetId
例如:
let obj = tools.kwargs.object;
let itemID = tools.kwargs.itemID;
# 5. 常见写法:进入创建,离开销毁
# js_enter
tools.runClientEffect(`
const current = api.getTarget();
if (!current) return;
current.setStyle({
outline: "2px solid rgba(255,255,255,0.65)",
filter: "brightness(1.08)"
});
`, {
label: `hover-outline-${tools.kwargs.itemID}`
});
# js_leave
tools.disposeClientEffect(`hover-outline-${tools.kwargs.itemID}`);
这套写法很常见,因为:
- 进入时只负责开效果
- 离开时只负责收效果
label固定,不容易堆积
# 6. js_move 里要重视 label
因为 js_move 触发频率很高。
如果每次移动都新开一个没有固定 label 的效果,同类特效就会越积越多。
# 跟手提示例子
tools.runClientEffect(`
api.createText(payload.text || "查看详情", {
style: {
padding: "4px 8px",
borderRadius: "999px",
background: "rgba(15,23,42,0.88)",
color: "#fff",
fontSize: "12px"
}
}).place({
x: pointer?.clientX || 0,
y: pointer?.clientY || 0,
offsetX: 14,
offsetY: 14
});
`, {
payload: { text: "查看详情" },
label: `pointer-tip-${tools.kwargs.itemID}`
});
# js_leave
tools.disposeClientEffect(`pointer-tip-${tools.kwargs.itemID}`);
# 7. js_long 更适合做“延迟确认”型反馈
js_long 和 js_enter 的区别是:
js_enter更适合立即亮起js_long更适合“按住一会儿才出现”的反馈
例如长按后出现一个环形描边:
tools.runClientEffect(`
const current = api.getTarget();
if (!current) return;
current.setStyle({
outline: "2px solid rgba(250,204,21,0.95)",
boxShadow: "0 0 0 6px rgba(250,204,21,0.18)"
});
`, {
label: `long-press-highlight-${tools.kwargs.itemID}`
});
结束长按态时,通常还是在 js_leave 里统一收掉:
tools.disposeClientEffect(`long-press-highlight-${tools.kwargs.itemID}`);
# 8. 什么时候不用手动传 target
在交互脚本里,如果你不传 target,运行时通常会自动绑定当前真实触发的那个目标。
所以很多移入高亮、悬浮提示,直接省略 target 就够了。
# 9. 什么时候适合自己传 target
如果你想高亮的不是当前控件,而是别的控件,可以自己传:
tools.runClientEffect(`
const current = api.getTarget();
if (!current) return;
current.setStyle({ filter: "brightness(1.08)" });
`, {
target: "主按钮",
label: "main-btn-highlight"
});
如果要一次命中多个目标,可以用 targets。
# 10. 对象控件里更适合直接用当前对象
如果这个控件本身绑定了对象类,交互脚本里通常会直接用:
let obj = tools.kwargs.object;
if (!obj) return;
tools.runClientEffect(`
const current = api.getTarget();
if (!current) return;
current.setStyle({ filter: "brightness(1.08)" });
`, {
label: `hover-${obj.getID()}`
});
# 使用时要注意的几件事
- 交互脚本本身更像特效入口。
api / target / pointer只在内层特效脚本里可用。- 高频
js_move通常会配一个稳定的label。 js_long更适合放延迟出现的反馈,不要和js_enter做成完全重复的一套效果。js_enter创建,js_leave销毁,是最常见的组合。
# 下一步
如果你还没看过基础特效入口,可以先看 客户端特效系统。