2. 触发条件设计:布尔条件、阈值条件、时间条件、组合条件(AND/OR/NOT)

触发条件,说白了就是事件轮换的「开关」。你设计得再好的事件链,如果触发条件写死了,玩家体验就会很僵硬。我在项目里见过太多「条件写得太死,玩家死活触发不了」的惨案。

这一章我们就把四种基础条件拆开揉碎,再讲怎么把它们组合起来。嗯,先看一张总览图,心里有个谱。

触发条件类型总览 触发条件 布尔条件 true / false 阈值条件 数值比较 时间条件 延迟 / 间隔 组合条件 AND / OR / NOT 四种条件可以单独使用,也可以嵌套组合。实际项目中 90% 的触发逻辑都是组合条件。

2.1 布尔条件:最简单的开关

布尔条件就是 true 或 false。游戏里最常见的就是「某个标志位是否被设置」。比如玩家是否接取了任务、某个门是否已经打开、Boss 是否已经被击败。

我个人习惯把布尔条件叫做「旗帜检查」。你想想看,一个变量要么是 1,要么是 0,没有中间态。写起来也最简单:

// 伪代码示例:检查任务是否完成
if (quest_completed == true) {
    trigger_event("打开隐藏通道");
}

我在项目中遇到过一个问题:多个系统同时读写同一个布尔变量,导致条件判断出现竞态。后来我强制要求所有布尔条件变量只能由单一系统写入,其他系统只读。这个习惯一直保留到现在。

小技巧:布尔变量命名要带「is_」「has_」「can_」前缀,一眼就能看出是条件判断。比如 is_door_open、has_key_item、can_enter_dungeon。

2.2 阈值条件:数值的比较游戏

阈值条件比布尔条件灵活得多。它不是简单的 true/false,而是比较一个数值是否达到某个界限。比如玩家血量低于 30% 时触发低血量警告,或者金币数量超过 1000 时解锁 VIP 商店。

说白了,阈值条件就是「大于、小于、等于、区间判断」。写代码时要注意边界值处理:

// 伪代码示例:血量阈值触发
if (player.hp <= player.max_hp * 0.3) {
    trigger_event("low_hp_warning");
}

// 金币阈值触发
if (player.gold >= 1000) {
    unlock_feature("vip_shop");
}

我曾经踩过一个坑:阈值条件用了 > 而不是 >=,结果玩家刚好达到 1000 金币时死活触发不了 VIP 商店。测试组报 bug 报了一整天。从那以后我写阈值条件都会在注释里标清楚「含不含边界」。

比较类型 运算符 示例 说明
大于 > score > 100 不包含 100
大于等于 >= score >= 100 包含 100
小于 < hp < 30 不包含 30
小于等于 <= hp <= 30 包含 30
区间 && level >= 5 && level <= 10 5 到 10 级之间

2.3 时间条件:让事件「等一等」

时间条件是最容易被新手忽略的。你想想看,玩家刚进游戏就弹出一个活动公告,是不是很烦?但如果等 3 秒再弹,体验就好很多。这就是时间条件的价值。

时间条件通常分三种:

  • 延迟触发:条件满足后等一段时间再触发事件
  • 间隔触发:每隔一段时间重复触发事件
  • 时间窗口:只在某个时间段内允许触发(比如晚上 8 点到 10 点的限时活动)
// 伪代码示例:延迟触发
if (condition_met == true) {
    start_timer(3.0);  // 等待 3 秒
    // 3 秒后自动触发
    trigger_event("show_announcement");
}

// 间隔触发
start_interval_timer(60.0);  // 每 60 秒触发一次
trigger_event("auto_save");

// 时间窗口判断
if (current_hour >= 20 && current_hour < 22) {
    trigger_event("limited_time_activity");
}
注意:时间条件最容易出 bug 的地方是「计时器重置」。比如玩家在延迟期间退出游戏,再登录时计时器还在不在?我建议所有时间条件都绑定到游戏时间(GameTime)而不是现实时间,否则玩家切后台再回来,逻辑就乱了。

2.4 组合条件:AND / OR / NOT

单个条件太单薄了。实际项目中,一个事件往往需要多个条件同时满足,或者满足其中之一。这时候就需要组合条件。

组合条件就三个逻辑运算符:

  • AND(与):所有条件都为 true 才触发
  • OR(或):任意一个条件为 true 就触发
  • NOT(非):条件为 false 时才触发

我建议你记住一个原则:AND 收紧条件,OR 放宽条件,NOT 反转条件。看个例子:

// AND 组合:玩家等级 >= 10 并且 拥有钥匙
if (player.level >= 10 && player.has_key == true) {
    trigger_event("open_secret_room");
}

// OR 组合:玩家是 VIP 或者 充值超过 100 元
if (player.is_vip == true || player.total_recharge > 100) {
    trigger_event("unlock_premium_shop");
}

// NOT 组合:玩家不在战斗状态
if (!player.in_combat) {
    trigger_event("show_rest_menu");
}

// 更复杂的嵌套组合
if ((player.level >= 5 && player.has_quest == true) || player.is_gm == true) {
    trigger_event("debug_teleport");
}

我曾经在项目里见过一个「万恶的条件表达式」:

if (a || b && c || !d && e) {
    // 这行代码没人能看懂
}

嗯,这种写法我强烈建议你避免。组合条件超过 3 个,一定要加括号明确优先级。或者干脆拆成多个 if 判断,可读性比「一行炫技」重要得多。

我的经验法则:组合条件中,AND 和 OR 不要混用超过 2 层。如果逻辑真的复杂,就拆成函数,用变量名解释每一步判断。代码是写给人看的,不是写给编译器看的。

2.5 实战:设计一个「限时副本」的触发条件

光说不练假把式。我们拿一个真实需求来练手:

需求:设计一个限时副本的触发条件。玩家必须满足以下所有条件才能进入:

  • 等级 ≥ 30 级
  • 拥有「副本钥匙」道具
  • 当前时间在晚上 19:00 ~ 22:00 之间
  • 今天还没有进入过该副本

你看,这就是一个典型的组合条件。我们来写一下:

// 限时副本触发条件
bool can_enter_dungeon() {
    // 条件1:等级阈值
    bool level_ok = (player.level >= 30);
    
    // 条件2:布尔条件 - 拥有钥匙
    bool has_key = player.has_item("dungeon_key");
    
    // 条件3:时间窗口
    bool time_ok = (current_hour >= 19 && current_hour < 22);
    
    // 条件4:布尔条件 - 今日未进入
    bool not_entered_today = (player.daily_dungeon_count == 0);
    
    // 组合:四个条件全部满足
    return level_ok && has_key && time_ok && not_entered_today;
}

// 调用
if (can_enter_dungeon()) {
    trigger_event("enter_limited_dungeon");
} else {
    show_message("条件不满足,无法进入");
}

这个例子把布尔条件、阈值条件、时间条件、组合条件全用上了。你想想看,如果不用组合条件,你得写多少个 if 嵌套?

避坑指南:我曾经把「今日未进入」的条件写成了 player.daily_dungeon_count == 1,结果玩家第一次进入后 count 变成 1,条件反而满足了。嗯,边界值一定要想清楚。