如何实现好感度系统
好感度系统是视觉小说的核心机制之一。本章展示如何用灵泛引擎实现一个完整的好感度系统。
设计思路
角色好感度(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 变量——它就是一个简化版的好感度系统。