Skip to content

Branch

branch 指令可以创建分支流程,根据条件判断跳转到不同的执行路径。

branch({
Condition() {
if (this.atk > 10) return "win";
if (this.hp > 10) return "alive";
return "gameOver";
},
// jump 到 chapter-2 这个 flag
win: "chapter-2",
// 执行这些内容。
alive() {
text`something wrong`;
},
// 使用 `likely` 来标记更可能发生的分支
gameOver(likely) {},
});
  1. 条件判断,返回希望前往的分支。
  2. 分支目标 win
  3. 分支目标 alive
  4. 分支目标 gameOver

首先在 branch 指令中,定义一个名为 Condition 的函数(这个名称不可修改),用于控制分支。

branch({
Condition() {
if (this.inGame.atk > 10) return "win";
if (this.inGame.hp > 10) return "alive";
return "gameOver";
},
});
  • this 指向了游戏内可以访问的变量(见 World 变量)。
  • winalivegameOver 是分支目标的名称,可以任意指定。

这个示例 Condition 的逻辑为:当攻击力大于 10 时跳转到 win 分支,当血量大于 10 时跳转到 alive 分支,否则跳转到 gameOver 分支。

随后在 branch 中,定义每个分支的目标。目标可以是跳转到某个 flag,也可以是播放一段剧本。

branch({
Condition() { /* ... */ }
// 跳转到 chapter-2 这个 flag
win: "chapter-2",
// 执行这些内容
alive() {
text `stay alive!`;
Natsume.enter()
text `something wrong`;
Natsume.leave()
jump("chapter-2")
},
// 使用 `likely` 来标记更可能发生的分支,以便编译器进行优化
gameOver(likely) {},
});

Branch 支持嵌套,例如:

branch({
Condition() { /* ... */ },
alive() {
text `看来我还活着!喝瓶可乐压压惊!`;
branch({}); // 嵌套分支
},
});

复杂的嵌套分支会导致剧本变得难以阅读与维护。

最简单的方法是使用 jump 指令跳转到不同的分支,避免嵌套。

此外,还可以利用 JavaScript 的特性,将分支写在一个函数中,然后在分支目标中使用这个函数。通过这种方法可以大量减少嵌套层数。

branch({
Condition() { /* ... */ },
// 执行 aliveResult 这个函数
alive: aliveResult,
// 或是在半当中调用
gameOver(likely) {
aliveResult();
text `哎哟!力竭倒下!...`;
},
});
function aliveResult() {
text `something wrong`;
SomeBody.enter();
text `something wrong`;
SomeBody.leave();
}

默认情况下,你无法在 Condition 函数中执行具有副作用的操作(特别是赋值操作)。

branch({
Condition() {
if (this.inGame.atk > 10) {
this.inGame.money += 10;
return "win";
}
if (this.inGame.hp > 10) {
this.inGame.hp -= 10;
return "alive";
}
return "gameOver";
},
});

如果你确信需要在 Condition 中执行副作用操作,可以使用 TypeScript 的类型绕过 as any

Condition() {
(this.inGame.love as any) = 10;
}

这将暂时禁用类型检查。

回忆 概览 中强调的,所有的控制流指令,都会强制结束目前的语段。

example.ts
text `语段 1`;
yohane.leave();
branch({
Condition() { /* ... */ },
alive() {
text `语段 2`;
yohane.leave();
text `语段 3`;
yohane.leave();
},
});
text `语段 4`;
yohane.leave();

在一些时候,我们可能希望在进入分支的时候,不强制结束语段,这个时候就轮到 directive.SceneBindNext 指令出场(语段分割逻辑不变,但连续播放)。

example.ts
text `语段 1`;
yohane.leave();
directive.SceneBindNext;
branch({
Condition() { /* ... */ },
alive() {
text `语段 2`;
yohane.leave();
text `语段 3`;
yohane.leave();
},
});
text `语段 4`;
yohane.leave();