文档目标:全方位解析 Hades 如何通过“双层标签”设计与“模块化代码”架构,在有限资源下创造出 225+ 种差异巨大的核心战斗体验(Build)。本文档分为设计篇与程序架构篇。
如果游戏有 10 种武器,每种武器只有 1 种玩法,那只有 10 种体验。
Hades 的核心公式:
Build = 武器形态 (4x6) * 核心祝福 (8) * 辅助祝福 (N) * 锤子变异 (2)
但真正的魔法在于标签系统 (Tag System)。
Supergiant Games 没有为每两个神设计特定的硬代码逻辑,而是使用标签来解耦。
每个神的普通攻击/特殊攻击都会赋予敌人一种状态:
Chain-Lightning (连锁)Knockback (击退)Doom (延迟伤害)Weak (虚弱)Hangover (中毒DOT)有些祝福不是为了造成伤害,而是为了响应标签:
Weak 状态的敌人造成额外伤害”Knockback 时,额外造成一次 Rupture (撕裂) 伤害”设计精髓: 这让 Poseidon 的击退不仅是位移控制,变成了触发 DOT 的开关。
当玩家同时拥有神 A 和 神 B 的特定前置祝福时,会解锁 Duo Boon。这是 Hades 构建深度的巅峰。
Duo Boons 通常遵循以下三种逻辑模板:
Supergiant Games 摒弃了传统的长篇设计文档(GDD),采用了高度迭代的开发模式,其核心在于构建了一个“容器(玩家/武器)”与“内容(恩赐/升级)”完全解耦的系统。
当玩家拾取一个恩赐时,代码层面绝不是简单的 if (hasZeus) { ... }。这是一个装饰器模式与策略模式的优雅结合。
原理:允许在不改变原有对象结构的情况下,动态地给对象增加功能。 在 Hades 中,武器的攻击指令(Command)是被层层包裹的。
SwordAttack (造成 10 物理伤害)。DoomDecorator 包裹了 SwordAttack。在执行完基础攻击后,额外给目标挂载一个延迟伤害触发器。DeflectDecorator 包裹了上述整体。在攻击判定的 Hitbox 上增加了 ReflectProjectiles 标记。伪代码逻辑 (C# 概念模拟):
interface IAttackCommand { void Execute(Target t); }
// 原始攻击
class BaseSwordAttack : IAttackCommand {
public void Execute(Target t) { t.TakeDamage(10); }
}
// 装饰器基类
abstract class BoonDecorator : IAttackCommand {
protected IAttackCommand _wrapped;
public BoonDecorator(IAttackCommand wrapped) { _wrapped = wrapped; }
public virtual void Execute(Target t) { _wrapped.Execute(t); }
}
// 宙斯恩赐:增加连锁闪电
class ZeusLightningDecorator : BoonDecorator {
public override void Execute(Target t) {
base.Execute(t); // 先造成基础剑伤
SpawnChainLightning(t.Position); // 后触发闪电
}
}
// 运行时组装
var attack = new ZeusLightningDecorator(new BaseSwordAttack());
原理:定义一系列算法,使其可以互相替换。 这通常用于 Daedalus Hammer (代达罗斯之锤) 这种改变武器形态的升级。
AttackSlot,持有一个 IAttackStrategy。StandardBowShotStrategy,装载了 SpreadShotStrategy。RPG 数值膨胀不崩坏的关键在于属性系统 (Attribute System)。Hades 采用了类似 Unreal GAS 的属性计算方式。 任何数值(攻击力、暴击率、移动速度)都不是简单的变量,而是一个计算管道。
公式模型: \(FinalValue = (Base + \sum Additive) \times \prod Multipliers\)
Hades 中复杂的连锁反应(如“海神+雷神:击退触发闪电”)依赖于全局事件总线。
OnEnemyHit(target, damageInfo)OnDashStartOnKill(target)OnKnockbackApplied(target)OnKnockbackApplied。function OnKnockbackApplied(target) { SpawnLightning(target) }鉴于 Vampirefall 是 塔防 + Roguelike,我们需要将上述架构应用到防御塔(Tower)与词条(Perk/Artifact)的结合中。
不要直接修改防御塔的 damage 变量。创建一个通用的 Stat 类。
[System.Serializable]
public class Stat {
public float BaseValue;
private List<StatModifier> modifiers = new List<StatModifier>();
// 脏标记优化:只有当修饰器列表变动时才重新计算
private bool _isDirty = true;
private float _cachedValue;
public float Value {
get {
if (_isDirty) Recalculate();
return _cachedValue;
}
}
public void AddModifier(StatModifier mod) {
modifiers.Add(mod);
_isDirty = true;
}
}
public enum ModType { Flat, PercentAdd, PercentMult }
利用 Unity 的 ScriptableObject 作为恩赐的数据载体和逻辑入口。
// 恩赐基类
public abstract class BoonEffect : ScriptableObject {
public string boonId;
public List<string> tags; // Tags: ["Lightning", "Status_Shock"]
// 钩子函数:当塔攻击时触发
public virtual void OnAttack(Tower tower, Enemy target) {}
// 钩子函数:当塔击杀时触发
public virtual void OnKill(Tower tower, Enemy victim) {}
// 钩子函数:装备时修改数值
public virtual void OnEquip(Tower tower) {
tower.Stats.Attack.AddModifier(new StatModifier(0.1f, ModType.PercentAdd));
}
}
// 宙斯类效果实现
[CreateAssetMenu(menuName = "Boons/LightningStrike")]
public class LightningBoon : BoonEffect {
public GameObject lightningPrefab;
public override void OnAttack(Tower tower, Enemy target) {
// 生成闪电链逻辑
Instantiate(lightningPrefab, target.transform.position, Quaternion.identity);
// 广播事件,允许其他恩赐响应 "Lightning"
EventManager.Trigger("OnLightningStrike", target);
}
}
为了实现 Duo Boons(双重恩赐),我们需要检查玩家是否凑齐了特定的标签组合。
Dictionary<string, int> globalTags; // 记录当前拥有多少个 “Zeus”, “Fire”, “Melee” 标签bool CanSpawnSeaStorm() {
return globalTags["Poseidon_Knockback"] > 0 && globalTags["Zeus_Lightning"] > 0;
}
#Fire 标签时,普通的物理箭矢自动替换为燃烧箭矢模型。#Wet 标签的敌人,且本次攻击带有 #Lightning 标签 -> 触发感电伤害。| 架构层级 | 传统做法 (Bad) | Hades/Vampirefall 做法 (Good) |
|---|---|---|
| 数值叠加 | 直接修改 tower.damage += 10 |
使用 Stat.AddModifier() 管道,保留溯源能力 |
| 特殊效果 | 在 Tower 类里写 if (hasZeus) ... |
塔持有 List<BoonEffect>,遍历调用接口 |
| 连锁反应 | 硬编码函数调用 DoKnockbackThenLightning() |
事件驱动 OnKnockback -> 订阅者响应 |
| 配置数据 | 散落在各个 Prefab 上 | 集中在 ScriptableObject 或 Lua/Excel 表中 |
总结:真正的多样性不是来自于元素的数量,而是来自于元素之间连接方式的数量。通过良好的底层架构,让策划人员能够像搭积木一样自由组合玩法,而无需每次都请求程序修改代码。