技能树 (Skill Tree) 是一种可视化的角色成长系统,玩家通过消耗资源(技能点/经验/货币)来解锁新能力或强化现有能力。
优秀技能树的三大目标:
线性树(单路径):
等级 1: 攻击力 +10%
↓
等级 2: 攻击力 +15%
↓
等级 3: 攻击力 +20%
优点: 简单明了,新手友好
缺点: 无选择,无 Build 多样性
适用: 移动端休闲游戏
---
分支树(多路径):
起点
/ \
物理系 魔法系
/ \ / \
近战 远程 火 冰
优点: 有选择,Build 分化
缺点: 可能出现"必点路径"
适用: 大多数 RPG
---
网格树(自由连接):
[A]─[B]─[C]
│ ╲ │ ╱ │
[D]─[E]─[F]
│ ╱ │ ╲ │
[G]─[H]─[I]
优点: 极限自由,组合无穷
缺点: 新手困惑,平衡困难
适用: 硬核 ARPG (如 Path of Exile)
Vampirefall 推荐: 分支树(多路径),在自由度和易用性之间平衡。
| 类型 | 玩家体验 | 设计难度 | 推荐比例 |
|---|---|---|---|
| 主动技能 | 爽感强,操作复杂度 ↑ | 高(需动画/特效) | 20-30% |
| 被动加成 | 无感知,但持续有效 | 低(纯数值) | 70-80% |
设计公式:
技能树吸引力 = (主动技能数量 × 炫酷度) + (被动加成总和 × 实用性)
最佳配比:
- 每个分支至少 1 个主动技能(吸引玩家选择)
- 被动技能填充路径(提供成长感)
递进式(纵向成长):
攻击力 +10% → 攻击力 +20% → 攻击力 +30%
特点: 同一能力不断强化
适用: 简单系统
横向式(扩展玩法):
攻击力 +10% → 范围伤害 → 生命偷取
特点: 解锁新机制
适用: 复杂系统(推荐)
可能 Build 数量 = C(总技能数, 可用点数)
示例:
10 个技能,5 个点数: C(10, 5) = 252 种组合
但实际有效 Build 远少于数学组合:
- 某些技能互斥
- 某些路径必点
- 某些组合无意义
实际有效 Build ≈ 20-30% 理论值
Build Entropy = -Σ (P(Build_i) × log P(Build_i))
其中 P(Build_i) = 玩家选择该 Build 的概率
理想值:
- 低熵 (<2.0): Build 单一,平衡问题
- 中熵 (2.0-3.5): 健康多样性
- 高熵 (>3.5): 选择过载,无最优解
目标: 保持中等熵值
必点节点 (Mandatory Node):
90%+ 玩家都会点的技能
识别方法:
if (选择率 > 90% AND 无替代方案):
标记为必点节点
→ 考虑改为基础能力或降低吸引力
示例:
❌ "+50% 伤害" 在路径起点 → 必点
✅ "+10% 伤害" 在路径起点 → 可选
| 模式 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 完全免费 | 鼓励实验,友好 | 失去决策重量感 | 肉鸽类 |
| 货币重置 | 保留选择意义 | 可能导致囤积不敢点 | RPG |
| 首次免费 | 平衡两者 | 实现复杂度中等 | 推荐 |
| 禁止重置 | 选择极重要 | 新手可能废号 | 硬核游戏 |
Vampirefall 推荐:
重置成本 = 基础成本 × (1 + 0.5 × 重置次数)
示例:
第 1 次: 100 金币
第 2 次: 150 金币
第 3 次: 200 金币
...
(避免无限制重置)
或者:
每 24 小时免费重置 1 次(时间冷却)
Vampirefall 的混合品类需要局外成长 + 局内成长双层设计:
┌─────────────────────────────────────┐
│ 局外成长 (Meta Progression) │
│ - 永久天赋树 │
│ - 基地建设 │
│ - 解锁新机制 │
├─────────────────────────────────────┤
│ 局内成长 (In-Run Progression) │
│ - 肉鸽词条选择 │
│ - 临时技能强化 │
│ - Build 即时构建 │
└─────────────────────────────────────┘
区分原则:
【猎人天赋树】
│
┌───────┼───────┐
│ │ │
【战士】 【射手】 【法师】
/ \ / \ / \
近战 防御 精准 移动 元素 召唤
分支特色:
- 近战伤害 +20%
- 塔的攻击速度 +15%
- 解锁:战吼(范围Buff)
- 远程伤害 +25%
- 移动速度 +20%
- 解锁:多重箭(一次射三箭)
- 元素伤害 +30%
- 技能范围 +25%
- 解锁:魔法塔强化(塔获得元素属性)
[CreateAssetMenu(fileName = "SkillTree", menuName = "Systems/Skill Tree")]
public class SkillTreeConfig : ScriptableObject
{
[Header("技能树信息")]
public string treeName = "猎人天赋树";
public SkillTreeType treeType = SkillTreeType.Meta; // Meta or InRun
[Header("技能节点")]
public SkillNode[] nodes;
[Header("重置设置")]
public bool allowReset = true;
public int baseResetCost = 100;
public float resetCostMultiplier = 0.5f;
}
[System.Serializable]
public class SkillNode
{
[Header("基础信息")]
public string nodeID = "SKILL_001";
public string displayName = "剑术精通";
[TextArea(2, 5)]
public string description = "近战伤害 +20%";
[Header("类型")]
public SkillNodeType nodeType = SkillNodeType.Passive;
public SkillCategory category = SkillCategory.Warrior;
[Header("连接")]
public string[] prerequisiteIDs; // 前置技能 ID
public Vector2 position; // UI 位置
[Header("消耗")]
public int pointCost = 1;
public int levelRequirement = 1;
[Header("效果")]
public SkillEffect[] effects;
[Header("视觉")]
public Sprite icon;
public Sprite connectorSprite;
}
public enum SkillNodeType
{
Passive, // 被动加成
ActiveAbility,// 主动技能
Keystone // 核心节点(大幅改变玩法)
}
public enum SkillCategory
{
Warrior,
Archer,
Mage,
Universal // 通用
}
[System.Serializable]
public class SkillEffect
{
public EffectType type;
public float value;
public string targetStat; // 例如: "AttackDamage", "MoveSpeed"
public void Apply(PlayerStats stats)
{
switch (type)
{
case EffectType.AddFlat:
stats.ModifyStat(targetStat, value, ModifyType.Flat);
break;
case EffectType.AddPercentage:
stats.ModifyStat(targetStat, value, ModifyType.Percentage);
break;
case EffectType.UnlockAbility:
AbilitySystem.UnlockAbility(targetStat);
break;
}
}
}
public enum EffectType
{
AddFlat, // 固定加成
AddPercentage, // 百分比加成
UnlockAbility // 解锁技能
}
public class SkillTreeManager : MonoBehaviour
{
public static SkillTreeManager Instance { get; private set; }
[Header("配置")]
public SkillTreeConfig metaTree; // 局外成长树
public SkillTreeConfig inRunTree; // 局内成长树(可选)
private Dictionary<string, SkillNode> allNodes;
private HashSet<string> unlockedNodes;
private int availablePoints = 0;
private int resetCount = 0;
void Awake()
{
if (Instance == null)
{
Instance = this;
DontDestroyOnLoad(gameObject);
InitializeSkillTree();
}
else
{
Destroy(gameObject);
}
}
private void InitializeSkillTree()
{
allNodes = new Dictionary<string, SkillNode>();
foreach (var node in metaTree.nodes)
{
allNodes[node.nodeID] = node;
}
// 加载已解锁节点
unlockedNodes = LoadUnlockedNodesFromSave();
availablePoints = CalculateAvailablePoints();
}
public bool CanUnlockNode(string nodeID)
{
if (!allNodes.ContainsKey(nodeID))
return false;
var node = allNodes[nodeID];
// 1. 检查是否已解锁
if (unlockedNodes.Contains(nodeID))
return false;
// 2. 检查技能点
if (availablePoints < node.pointCost)
return false;
// 3. 检查等级需求
if (PlayerLevel.Current < node.levelRequirement)
return false;
// 4. 检查前置技能
foreach (var prereqID in node.prerequisiteIDs)
{
if (!unlockedNodes.Contains(prereqID))
return false;
}
return true;
}
public void UnlockNode(string nodeID)
{
if (!CanUnlockNode(nodeID))
{
Debug.LogWarning($"[SkillTree] 无法解锁: {nodeID}");
return;
}
var node = allNodes[nodeID];
// 1. 扣除点数
availablePoints -= node.pointCost;
// 2. 标记解锁
unlockedNodes.Add(nodeID);
// 3. 应用效果
ApplyNodeEffects(node);
// 4. 保存
SaveUnlockedNodesToSave();
// 5. 触发事件
OnNodeUnlocked?.Invoke(node);
Debug.Log($"[SkillTree] 解锁: {node.displayName}");
}
private void ApplyNodeEffects(SkillNode node)
{
var playerStats = PlayerStats.Instance;
foreach (var effect in node.effects)
{
effect.Apply(playerStats);
}
// 特殊处理核心节点
if (node.nodeType == SkillNodeType.Keystone)
{
ApplyKeystoneEffect(node);
}
}
public int CalculateResetCost()
{
if (resetCount == 0)
return 0; // 首次免费
return Mathf.RoundToInt(
metaTree.baseResetCost *
(1 + metaTree.resetCostMultiplier * resetCount)
);
}
public void ResetSkillTree()
{
int cost = CalculateResetCost();
// 扣除货币
if (!CurrencySystem.TrySpend(CurrencyType.Gold, cost))
{
Debug.LogWarning("[SkillTree] 金币不足,无法重置");
return;
}
// 移除所有效果
foreach (var nodeID in unlockedNodes)
{
RemoveNodeEffects(allNodes[nodeID]);
}
// 清空解锁记录
int totalPoints = unlockedNodes.Sum(id => allNodes[id].pointCost);
unlockedNodes.Clear();
// 返还点数
availablePoints += totalPoints;
// 增加重置计数
resetCount++;
// 保存
SaveUnlockedNodesToSave();
// 事件
OnSkillTreeReset?.Invoke();
Debug.Log($"[SkillTree] 重置技能树(花费 {cost} 金币)");
}
public Dictionary<SkillCategory, int> GetCategoryDistribution()
{
var distribution = new Dictionary<SkillCategory, int>();
foreach (var nodeID in unlockedNodes)
{
var category = allNodes[nodeID].category;
if (!distribution.ContainsKey(category))
distribution[category] = 0;
distribution[category]++;
}
return distribution;
}
// 事件
public System.Action<SkillNode> OnNodeUnlocked;
public System.Action OnSkillTreeReset;
}
┌─────────────────────────────────────┐
│ 猎人天赋树 [已用: 15/30 点] [重置]│
├─────────────────────────────────────┤
│ │
│ [战士] [射手] [法师] │
│ │ │ │ │
│ ┌──┼──┐ ┌──┼──┐ ┌──┼──┐ │
│ │ │ │ │ │ │ │ │ │ │
│ 🗡️ 🛡️ ⚔️ 🏹 👟 🎯 🔥 ❄️ ⚡ │
│ │
│ 选中: [剑术精通] │
│ 近战伤害 +20% │
│ 消耗: 1 点 | 需求: 等级 1 │
│ 前置: 无 │
│ [解锁] │
└─────────────────────────────────────┘
交互设计:
POE 的天赋树是网格树的极致,拥有 1300+ 个节点。
设计特色:
起始位置:
- 7 个职业,7 个不同起点
- 每个职业倾向不同(但可以走到任何位置)
节点类型:
- 小节点: +10 力量(填充路径)
- 显著节点: +30% 物理伤害(强力加成)
- 核心节点: 改变游戏规则(例如:生命不再恢复,但...)
经典核心节点示例:
"虚空之眼" (Void Gaze):
- 你的法术不再造成伤害
- 你的法术造成的伤害转化为生命值
(完全改变玩法)
"痛苦之影" (Pain Attunement):
- 生命值低于 35% 时,法术伤害 +30%
(风险收益设计)
设计哲学:
“给玩家无限可能,让他们自己创造 Build。”
优点:
缺点:
Vampirefall 借鉴:
Borderlands 的技能树是分支树的典范,简洁但有深度。
结构:
每个职业 3 棵树:
- 树 1: 进攻向(伤害提升)
- 树 2: 防御向(生存能力)
- 树 3: 特殊向(独特机制)
每棵树:
- 6 层节点
- 最底层是"终极技能"(强力主动技能)
职业示例 - 猎人 (Hunter):
树 1: 狙击手
├ 第 1 层: 致命打击 (+5% 暴击率)
├ 第 2 层: 专注 (瞄准时伤害 +10%)
├ 第 3 层: 爆头 (爆头伤害 +40%)
...
└ 终极: 一枪致命(下一枪必定暴击 +100% 伤害)
树 2: 游侠
├ 第 1 层: 快速移动 (+15% 移速)
├ 第 2 层: 生命恢复 (每秒 +2% 生命)
...
树 3: 猛禽
├ 第 1 层: 召唤猎鹰(宠物系统)
...
设计巧思:
解锁第 N 层需要:
- 已点第 N-1 层至少 1 个技能
(强制玩家在同一棵树深入)
结果:
每棵树底部的终极技能都很强
→ 吸引玩家深入投资某条路径
Vampirefall 借鉴:
Hades 的”镜子”是肉鸽类技能树的优秀范例。
设计特色:
双选升级(互斥):
┌──────────────────┐
│ +50 生命 │ ← 选其一
│ 或 │
│ +25% 伤害 │
└──────────────────┘
特点:
- 每个升级项都有 2 个方向
- 玩家可以随时切换(免费)
- 鼓励实验不同 Build
升级项示例:
1. 生命系
- +50 生命 vs +25% 死亡挑战伤害
2. 进攻系
- +10% 攻击 vs +10% 技能伤害
3. 防御系
- 20% 伤害减免 vs 100% 死亡后复活 1 次
4. 特殊系
- +20% 稀有祝福概率 vs +1 额外冲刺次数
设计哲学:
“让玩家轻松尝试,频繁切换,找到最适合自己的玩法。”
优点:
缺点:
Vampirefall 借鉴:
Grim Dawn 除了职业技能树,还有独特的星座系统。
设计特色:
星座图:
- 类似 POE 的网格
- 但用"属性点"解锁而非技能点
解锁流程:
1. 玩家获得"属性点"(力量/智力/灵巧)
2. 用属性点解锁星座节点
3. 激活整个星座获得特殊效果
示例:
【毒蛇座】(需要: 3 灵巧点)
└ 节点 1: +3% 攻速
└ 节点 2: +5 智力
└ 节点 3: +10% 毒伤
└ 完成奖励: 触发"毒蛇之咬"(10% 概率中毒敌人)
设计巧思:
玩家会想"集齐所有星座"
→ 长期目标
职业技能树 × 星座系统 = 海量组合
技能点 → 职业技能
属性点 → 星座
(避免资源竞争)
Vampirefall 借鉴:
Skill Trees and Player Choice
Damion Schubert (BioWare)
GDC 论文
The Math of Skill Trees
Game Balance Concepts
在线课程
Build Diversity in RPGs
Extra Credits
YouTube 视频
[GDC 2013] Path of Exile: Designing the Passive Tree
演讲者: Chris Wilson (Grinding Gear Games)
GDC Vault
[GDC 2020] Hades: Balancing Roguelike Progression
演讲者: Greg Kasavin (Supergiant Games)
YouTube 链接
Skill Tree Design Patterns - Gamasutra
文章链接
Build Entropy Analysis
Reddit 深度讨论
Balancing Skill Trees
Game Developer 文章
《RPG 设计指南》 (Tabletop RPG Design)
作者: Jennifer Scheurle
第 8 章: “角色成长系统”
《游戏平衡艺术》 (Game Balance)
作者: Ian Schreiber, Brenda Romero
第 12 章: “技能树平衡”
最后更新: 2025-12-04
维护者: Vampirefall 设计团队