- flags.md 第 14/15 行加粗短语以标点结尾致 flanking 失败,调整结构使加粗内容以汉字结尾 - 全量扫描 docs/intermediate/*.md(排除代码 span/围栏),确认 0 处真实失效 - READER-REVIEW 追加 batch 11 记录
5.6 KiB
Flag 变量
有些状态要跨事件、跨楼层一直保留,还要跟着存档走——比如「Boss 是否已被击败」「这道门开过没有」「某处计数到了几」。这些状态放哪?Flag 系统(state.flags)就是数据端提供的全局可存档变量:任何需要跨事件、跨楼层保留的简单状态,都可以存进 Flag,它会随存档一起保存与恢复。
字段与字段值
Flag 里的每一项都对应一个字段(IFlagCommonField)。要读懂下面的接口清单,先分清两个概念:
- 字段是一个对象,代表「这个变量本身」,提供
get()(取值)、set(value)(设置值)、add(value)(对数字值增减)等方法; - 字段值就是字段里存的那个普通值(数字、字符串、布尔等)。你平时读写的,大多是字段值。
系统接口因此分成两组,看名字就能分辨:
- 返回或操作字段对象的:
setField/getField/getOrInsert/getOrInsertComputed——它们返回字段对象本身; - 直接操作字段值的:
setFieldValue/addFieldValue/getFieldValue/getFieldValueDefaults——只关心值,不暴露字段对象。
怎么选?只读写一次值时用「值」那组更简单,不必多一步 get();要多次操作同一个字段、或要复用字段对象(例如先拿到字段、再反复增减)时,用「字段对象」那组更省事。两者可以互相转换:
// 用「字段值」的写法:一次设置、一次增减
state.flags.setFieldValue('open-count', 0);
state.flags.addFieldValue('open-count', 1);
// 用「字段对象」的写法:拿到字段后反复操作
const field = state.flags.getOrInsert('open-count', 0);
field.add(1);
const value = field.get();
其实「值」那组就是对「字段对象」那组的简写:setFieldValue(name, v) 等价于 getField(name)?.set(v),getFieldValue(name) 等价于 getField(name)?.get(),addFieldValue(name, v) 等价于 getField(name)?.add(v),getFieldValueDefaults(name, d) 等价于 getOrInsert(name, d).get()。
全部接口
IFlagSystem 提供如下接口:
| 接口 | 说明 |
|---|---|
occupied(field) |
判断字段是否被占用 |
setField(field, value) |
以指定值插入字段,返回字段对象 |
getField(field) |
取字段对象,不存在返回 null |
getOrInsert(field, defaultValue) |
取字段,不存在则以默认值创建 |
getOrInsertComputed(field, defaultValue) |
同上,但默认值由函数惰性计算 |
deleteField(field) |
删除字段 |
setFieldValue(field, value) |
设置字段的值 |
addFieldValue(field, value) |
对数字字段增减 |
getFieldValue(field) |
取字段的值,不存在返回 undefined |
getFieldValueDefaults(field, defaultValue) |
取字段的值,不存在则以默认值创建并返回 |
getOrInsertComputed 只在字段确实不存在时才执行默认值函数,适合默认值计算量较大的场景。getFieldValue 没有默认值,需要默认值时用 getFieldValueDefaults。
state.flags.setFieldValue('door-open', true);
const open = state.flags.getFieldValue('door-open');
state.flags.addFieldValue('kill-count', 1);
const count = state.flags.getFieldValueDefaults('kill-count', 0);
使用建议
Flag 会进入存档,因此不建议滥用:不再需要的变量应及时用 deleteField 删除,否则它会一直留在存档里。能用局部状态或对象自身数据表达的,就不必放进 Flag。
if (!state.flags.occupied('temp-flag')) {
state.flags.setFieldValue('temp-flag', 1);
}
// 用完后删除,避免残留进存档
state.flags.deleteField('temp-flag');
Flag 常与游戏关键动作配合使用,例如在钩子中读写,见钩子。
示例:记录开关与计数
目标:记下「Boss 已被击败」这个开关,以及「门被开过几次」这个计数——两者都要跟着存档走。
改哪里:你要记录这些状态的地方——例如某个事件函数或钩子里。
复制什么:
// 记录一个开关
state.flags.setFieldValue('boss-defeated', true);
// 记录一个计数
const times = state.flags.getOrInsert('open-count', 0);
times.add(1);
复制说明:片段已省略
import(这里用到的都是state上的成员);若编辑器提示缺少某个名字,再在顶部补对应的import(详见 代码基础 的「照抄教程里的代码时,怎么处理 import」)。
改什么:把 'boss-defeated'、'open-count' 换成你的字段名,把 true、1 换成你的值。只需一次读写的开关用「值」那组更简单;要反复增减的计数,用 getOrInsert 拿到字段对象后再 add 更省事。
怎么验证:写入后读 state.flags.getFieldValue('boss-defeated') / getFieldValue('open-count'),应返回你写入的值;存档后再读档依然存在。
注意:Flag 会进存档,不再需要的变量要及时 deleteField,避免一直残留在存档里。
想从 state 出发找到 Flag 对象,见数据端总览。