NarraLeaf

Persistent\<T extends PersistentContent\>

管理具名存档状态的 `Persistent` 类,涵盖比较、条件判断、动态文本与赋值

过去只能通过脚本修改 Storable 的状态,Persistent 则提供了一组实用方法,让你可以轻松控制流程

Persistent 需要命名空间的名称初始状态同名的 Persistent 共享同一份状态

命名空间不能是现有的内置命名空间(内置命名空间包括:「game」)

type PersisData = {
    flag: boolean;
    coin: number;
    name: string;
    // ...
};
const persis = new Persistent<PersisData>("persis", {
    flag: false,
    coin: 0,
    name: "约翰·史密斯",
    // ...
});

注意: 存储的内容必须是可序列化的,NarraLeaf-React 支持的可序列化值包括:

  • string
  • number
  • boolean
  • object: 键为 string,值为上述可序列化值
  • array: 元素为上述可序列化值
  • undefined
  • null
  • Date: 标准的 JavaScript 日期对象

如果剧本中使用了 Persistent,必须通过 Story 注册:

story.registerPersistent(persis);

从宿主监听这些值

下面这些方法构造的是动作,因此属于场景。故事之外的 React 代码——HUD、成就监听、编辑器面板——通过 Storable 读写同一批值,也可以订阅它们:

game.getLiveGame().getStorable()
    .onChange("persistent:persis", "coin", ({previous, next}) => {...});

注意命名空间的:名为 "persis"Persistent 注册时的键是 "persistent:persis"。请在 Storable 而不是 Namespace 上订阅,并把 onChangeonRestore 搭配使用,以免漏掉读入的存档——参见监听存储值的变化

公共方法

constructor

  • namespace: string - 命名空间的名称
  • defaultContent: T - 初始状态

equals<K extends StringKeyOf<T>>

判断值是否相等,可用于条件分支

  • key: K - 状态的键
  • value: T[K] | Lambda<T[K]> | LambdaHandler<T[K]> - 要比较的值、lambda 函数或 lambda 处理程序
  • 返回:Lambda<boolean>
scene.action([
    Condition
        .If(persis.equals("id", persis.get("player_id")), [
            character1.say("ID 匹配!")
        ])
]);

// 或使用 lambda 处理程序
scene.action([
    Condition
        .If(persis.equals("id", (ctx) => ctx.storable.getNamespace("player").get("player_id")), [
            character1.say("玩家 ID 匹配!")
        ])
]);

notEquals<K extends StringKeyOf<T>>

判断值是否不相等,可用于条件分支

  • key: K - 状态的键
  • value: T[K] | Lambda<T[K]> | LambdaHandler<T[K]> - 要比较的值、lambda 函数或 lambda 处理程序
  • 返回:Lambda<boolean>
scene.action([
    Condition
        .If(persis.notEquals("id", persis.get("player_id")), [
            character1.say("ID 不匹配!")
        ])
]);

// 或使用 lambda 处理程序
scene.action([
    Condition
        .If(persis.notEquals("id", (ctx) => ctx.storable.getNamespace("player").get("player_id")), [
            character1.say("玩家 ID 不匹配!")
        ])
]);

isTrue<K extends Extract<keyof T, BooleanValueKeyOf<T>>>

判断值是否为真,可用于条件分支

  • key: K - 状态的键
  • 返回:Lambda<boolean>
scene.action([
    Condition
        .If(persis.isTrue("flag"), [
            character1.say("标志为真")
        ])
]);

isFalse<K extends Extract<keyof T, BooleanValueKeyOf<T>>>

判断值是否为假,可用于条件分支

  • key: K - 状态的键
  • 返回:Lambda<boolean>

isNotNull<K extends StringKeyOf<T>>

判断值是否不为 nullundefined,可用于条件分支

  • key: K - 状态的键
  • 返回:Lambda<boolean>

toWord<K extends StringKeyOf<T>>

转换为动态词

  • key: K - 状态的键
  • 返回:Word<DynamicWord>
character.say(["你有 ", persis.toWord("gold"), " 个金币"]);

// 或者

character.say`你有 ${persis.toWord("gold")} 个金币`;

get<K extends StringKeyOf<T>>

toWord 的别名

  • key: K - 状态的键
  • 返回:Word<DynamicWord>
character.say`你有 ${persis.get("coin")} 个硬币`;

conditional

创建条件词

  • condition: Lambda<boolean> | LambdaHandler<boolean> - 要检查的条件
  • ifTrue: DynamicWordResult - 条件为真时返回的词
  • ifFalse: DynamicWordResult - 条件为假时返回的词
  • 返回:Word
character.say([
  "你的标志是 ",
  persis.conditional(
    persis.isTrue("flag"),
    "开启",
    "关闭"
  )
]);

evaluate<K extends StringKeyOf<T>>

执行 JavaScript 函数,判断结果是否为真

  • key: K - 状态的键
  • fn: (value: T[K]) => boolean - 用于评估状态的 JavaScript 函数
  • 返回:Lambda<boolean>
scene.action([
    Condition
        .If(persis.evaluate("coin", (coin) => coin < 10), [
            character1.say`你没有足够的硬币!`
        ])
]);

链式方法

set<K extends StringKeyOf<T>>

为指定键创建设置值的动作

重载 1 / 2

  • key: K - 要设置值的键
  • value: T[K] - 要设置的值
  • 返回:Proxied<Persistent<T>, Chained<LogicAction.Actions>>
scene.action([
    persis.set("coin", 10)
]);

重载 2 / 2

  • key: K - 要设置值的键
  • handler: (value: T[K]) => T[K] - 用于修改值的处理程序
  • 返回:Proxied<Persistent<T>, Chained<LogicAction.Actions>>
scene.action([
    persis.set("coin", (coin) => coin + 10) // 硬币将增加 10
]);

assign

创建整体赋值的动作

  • value: Partial<T> | ((value: T) => Partial<T>) - 要分配给状态的值
  • 返回:Proxied<Persistent<T>, Chained<LogicAction.Actions>>
scene.action([
    persis.assign({ coin: 10 })
]);

// 或使用函数
scene.action([
    persis.assign((state) => ({ coin: state.coin + 10 }))
]);

本页目录