Skip to content

如何实现好感度系统 ​

好感度系统是视觉小说的核心机制之一。本章展示如何用灵泛引擎实现一个完整的好感度系统。

设计思路 ​

角色好感度(0~100)
    ↑
    │ 礼物 / 对话选择 / 任务
    │
    ↓
分支路由(不同好感度触发不同剧情)

数据结构 ​

用 define 初始化每个角色的好感度:

dsl
define "npc.keeper.trust" 0 once
define "npc.keeper.gifts_received" 0 once
define "npc.keeper.met" false once

点分路径

用 npc.角色名.属性 的命名约定,方便管理多个角色。

好感度增减 ​

对话选择 ​

dsl
label meet_keeper:
  say "守塔人正在擦拭铜灯。" speaker="旁白"
  menu "你要怎么做?"
    "帮他擦灯" -> help_keeper
    "在一旁看着" -> watch_keeper
    "打断他问问题" -> interrupt_keeper

label help_keeper:
  set "npc.keeper.trust" {npc.keeper.trust + 10}
  say "谢谢你,年轻人。" speaker="守塔人"
  navigate "next_scene"

label watch_keeper:
  set "npc.keeper.trust" {npc.keeper.trust + 2}
  say "你就这样看着吗?" speaker="守塔人"
  navigate "next_scene"

label interrupt_keeper:
  set "npc.keeper.trust" {npc.keeper.trust - 5}
  say "(守塔人皱了皱眉)" speaker="旁白"
  say "什么事?" speaker="守塔人"
  navigate "next_scene"

送礼系统 ​

dsl
label give_gift:
  menu "送什么礼物?"
    "铜灯油" -> gift_oil
    "旧书" -> gift_book
    "什么都不送" -> gift_none

label gift_oil:
  if {player.has_oil}
    set "npc.keeper.trust" {npc.keeper.trust + 15}
    set "npc.keeper.gifts_received" {npc.keeper.gifts_received + 1}
    set "player.has_oil" false
    say "这正是我需要的!太感谢了。" speaker="守塔人"
  else
    say "你没有铜灯油。" speaker="系统"
  navigate "next_scene"

label gift_book:
  if {player.has_book}
    if {npc.keeper.trust < 30}
      say "我们不熟,我不能收。" speaker="守塔人"
    else
      set "npc.keeper.trust" {npc.keeper.trust + 10}
      set "npc.keeper.gifts_received" {npc.keeper.gifts_received + 1}
      set "player.has_book" false
      say "这本书看起来很有趣。" speaker="守塔人"
  else
    say "你没有旧书。" speaker="系统"
  navigate "next_scene"

好感度等级 ​

用 if 分支实现等级判断:

dsl
label check_trust:
  if {npc.keeper.trust >= 80}
    say "守塔人把你当作亲人。" speaker="旁白"
    navigate "ending_family"
  else if {npc.keeper.trust >= 50}
    say "守塔人信任你。" speaker="旁白"
    navigate "ending_trust"
  else if {npc.keeper.trust >= 20}
    say "守塔人对你有好感。" speaker="旁白"
    navigate "ending_neutral"
  else
    say "守塔人对你很冷淡。" speaker="旁白"
    navigate "ending_cold"

好感度显示 ​

在 UI 中显示好感度条:

dsl
scene "status_panel" type=ui
  text "守塔人好感度" x=10% y=20% size=20
  text "{npc.keeper.trust} / 100" x=10% y=25% size=16 color="#88CCFF"
  // 可以用多个 image 模拟进度条
  image "Images/bar_bg.png" x=10% y=30% width=300 height=20
  image "Images/bar_fill.png" x=10% y=30% width={npc.keeper.trust * 3} height=20

好感度影响对话 ​

用 character 的动态 name 反映好感度:

dsl
label dynamic_name:
  if {npc.keeper.trust >= 80}
    set "npc.keeper.display_name" "老人(义父)"
  else if {npc.keeper.trust >= 50}
    set "npc.keeper.display_name" "老人(朋友)"
  else
    set "npc.keeper.display_name" "守塔人"

  say "你好。" speaker="{npc.keeper.display_name}"

多角色好感度 ​

管理多个角色的好感度:

dsl
define "npc.keeper.trust" 0 once
define "npc.merchant.trust" 0 once
define "npc.guard.trust" 0 once

label town_square:
  menu "去找谁?"
    "守塔人" -> visit_keeper
    "商人" -> visit_merchant
    "卫兵" -> visit_guard

好感度互斥 ​

某些选择会同时影响多个角色:

dsl
label conflict_choice:
  say "商人和卫兵在争吵。" speaker="旁白"
  menu "你帮谁?"
    "帮商人" -> help_merchant
    "帮卫兵" -> help_guard

label help_merchant:
  set "npc.merchant.trust" {npc.merchant.trust + 10}
  set "npc.guard.trust" {npc.guard.trust - 5}
  navigate "next"

label help_guard:
  set "npc.guard.trust" {npc.guard.trust + 10}
  set "npc.merchant.trust" {npc.merchant.trust - 5}
  navigate "next"

好感度存档 ​

好感度作为全局变量,自动包含在存档中。无需额外处理。

C# 实现复杂逻辑 ​

对于复杂的好感度计算,用 C# 更清晰:

csharp
public class GiftSystem : StoryScript
{
    public override string SceneName => "cs_gift";

    public override async Task RunAsync()
    {
        var giftType = _state.Get<string>("_local_gift");
        var npcKey = _state.Get<string>("_local_npc");
        var currentTrust = _state.Get<int>($"npc.{npcKey}.trust");

        var bonus = giftType switch
        {
            "favorite" => 20,
            "liked" => 10,
            "normal" => 5,
            "disliked" => -5,
            _ => 0
        };

        // 礼物次数衰减
        var giftsReceived = _state.Get<int>($"npc.{npcKey}.gifts_received");
        if (giftsReceived > 3)
            bonus = Math.Max(1, bonus / 2);

        _state.Set($"npc.{npcKey}.trust", Math.Clamp(currentTrust + bonus, 0, 100));
        _state.Set($"npc.{npcKey}.gifts_received", giftsReceived + 1);

        await SayAsync($"好感度变化:{bonus:+0;-0;0}", speaker: "系统");
        await NavigateAsync("town");
    }
}

完整示例 ​

参见 最终作品中的 story.trust 变量——它就是一个简化版的好感度系统。

基于 .NET 10 + Avalonia 12 · Apache-2.0 License