4. 英雄收集
2026/4/14大约 7 分钟
4. 咸鱼之王——英雄收集
4.1 什么是英雄收集?
想象你在集卡片。每包卡片里随机出现一张——可能是普通卡片(很容易抽到),也可能是稀有闪卡(很难抽到)。你会一直买卡片,直到集齐自己喜欢的。
英雄收集就是游戏版的"集卡片"。玩家通过抽卡(花费金币或钻石随机获取英雄)或者碎片合成(收集足够的碎片兑换指定英雄)来扩充英雄阵容。
英雄稀有度
| 稀有度 | 颜色 | 抽中概率 | 属性倍率 | 举例 |
|---|---|---|---|---|
| 普通(Common) | 白色 | 53% | 1.0x | 村民小兵 |
| 稀有(Rare) | 绿色 | 35% | 1.5x | 森林猎人 |
| 史诗(Epic) | 蓝色 | 10% | 2.5x | 冰霜法师 |
| 传说(Legend) | 橙色 | 2% | 4.0x | 龙骑士 |
传说英雄最稀有也最强——就像集卡游戏里的SSR卡,抽到了就是赚到。
4.2 英雄数据库
C
using Godot;
using System.Collections.Generic;
/// <summary>
/// 英雄数据库——所有可用英雄的定义
/// </summary>
public static class HeroDatabase
{
public static readonly HeroData[] AllHeroes = new[]
{
// ===== 普通英雄 =====
new HeroData
{
Id = "villager",
Name = "村民",
Rarity = HeroRarity.Common,
Level = 1, Attack = 10, MaxHp = 100,
AttackSpeed = 1.0f,
SkillPower = 5,
SkillName = "挥拳",
SkillDesc = "普通地挥一拳"
},
new HeroData
{
Id = "apprentice",
Name = "学徒",
Rarity = HeroRarity.Common,
Level = 1, Attack = 12, MaxHp = 80,
AttackSpeed = 1.2f,
SkillPower = 8,
SkillName = "火苗",
SkillDesc = "发射一颗小火苗"
},
// ===== 稀有英雄 =====
new HeroData
{
Id = "hunter",
Name = "森林猎人",
Rarity = HeroRarity.Rare,
Level = 1, Attack = 20, MaxHp = 150,
AttackSpeed = 1.3f,
SkillPower = 15,
SkillName = "连射",
SkillDesc = "快速射出三支箭"
},
new HeroData
{
Id = "knight",
Name = "铁甲骑士",
Rarity = HeroRarity.Rare,
Level = 1, Attack = 18, MaxHp = 250,
AttackSpeed = 0.8f,
SkillPower = 12,
SkillName = "盾击",
SkillDesc = "用盾牌猛击敌人"
},
// ===== 史诗英雄 =====
new HeroData
{
Id = "ice_mage",
Name = "冰霜法师",
Rarity = HeroRarity.Epic,
Level = 1, Attack = 35, MaxHp = 120,
AttackSpeed = 0.9f,
SkillPower = 30,
SkillName = "暴风雪",
SkillDesc = "召唤一场暴风雪攻击全体敌人"
},
new HeroData
{
Id = "shadow_assassin",
Name = "暗影刺客",
Rarity = HeroRarity.Epic,
Level = 1, Attack = 45, MaxHp = 90,
AttackSpeed = 1.5f,
SkillPower = 25,
SkillName = "暗杀",
SkillDesc = "瞬移到敌人身后致命一击"
},
// ===== 传说英雄 =====
new HeroData
{
Id = "dragon_rider",
Name = "龙骑士",
Rarity = HeroRarity.Legend,
Level = 1, Attack = 60, MaxHp = 200,
AttackSpeed = 1.1f,
SkillPower = 50,
SkillName = "龙息",
SkillDesc = "召唤巨龙喷射毁灭性火焰"
},
new HeroData
{
Id = "goddess",
Name = "圣光女神",
Rarity = HeroRarity.Legend,
Level = 1, Attack = 25, MaxHp = 180,
AttackSpeed = 1.0f,
SkillPower = 45,
SkillName = "神圣审判",
SkillDesc = "召唤圣光净化一切邪恶"
}
};
/// <summary>
/// 根据ID查找英雄模板
/// </summary>
public static HeroData FindById(string id)
{
foreach (var hero in AllHeroes)
{
if (hero.Id == id) return hero;
}
return AllHeroes[0]; // 找不到返回默认英雄
}
/// <summary>
/// 获取指定稀有度的英雄列表
/// </summary>
public static List<HeroData> GetByRarity(HeroRarity rarity)
{
var result = new List<HeroData>();
foreach (var hero in AllHeroes)
{
if (hero.Rarity == rarity)
result.Add(hero);
}
return result;
}
}GDScript
## 英雄数据库——所有可用英雄的定义
class_name HeroDatabase
const ALL_HEROES: Array[Dictionary] = [
# ===== 普通英雄 =====
{
"id": "villager", "name": "村民",
"rarity": HeroRarity.COMMON,
"level": 1, "attack": 10, "max_hp": 100,
"attack_speed": 1.0, "skill_power": 5,
"skill_name": "挥拳", "skill_desc": "普通地挥一拳"
},
{
"id": "apprentice", "name": "学徒",
"rarity": HeroRarity.COMMON,
"level": 1, "attack": 12, "max_hp": 80,
"attack_speed": 1.2, "skill_power": 8,
"skill_name": "火苗", "skill_desc": "发射一颗小火苗"
},
# ===== 稀有英雄 =====
{
"id": "hunter", "name": "森林猎人",
"rarity": HeroRarity.RARE,
"level": 1, "attack": 20, "max_hp": 150,
"attack_speed": 1.3, "skill_power": 15,
"skill_name": "连射", "skill_desc": "快速射出三支箭"
},
{
"id": "knight", "name": "铁甲骑士",
"rarity": HeroRarity.RARE,
"level": 1, "attack": 18, "max_hp": 250,
"attack_speed": 0.8, "skill_power": 12,
"skill_name": "盾击", "skill_desc": "用盾牌猛击敌人"
},
# ===== 史诗英雄 =====
{
"id": "ice_mage", "name": "冰霜法师",
"rarity": HeroRarity.EPIC,
"level": 1, "attack": 35, "max_hp": 120,
"attack_speed": 0.9, "skill_power": 30,
"skill_name": "暴风雪", "skill_desc": "召唤暴风雪"
},
{
"id": "shadow_assassin", "name": "暗影刺客",
"rarity": HeroRarity.EPIC,
"level": 1, "attack": 45, "max_hp": 90,
"attack_speed": 1.5, "skill_power": 25,
"skill_name": "暗杀", "skill_desc": "致命一击"
},
# ===== 传说英雄 =====
{
"id": "dragon_rider", "name": "龙骑士",
"rarity": HeroRarity.LEGEND,
"level": 1, "attack": 60, "max_hp": 200,
"attack_speed": 1.1, "skill_power": 50,
"skill_name": "龙息", "skill_desc": "毁灭性火焰"
},
{
"id": "goddess", "name": "圣光女神",
"rarity": HeroRarity.LEGEND,
"level": 1, "attack": 25, "max_hp": 180,
"attack_speed": 1.0, "skill_power": 45,
"skill_name": "神圣审判", "skill_desc": "净化一切"
}
]
## 根据ID查找英雄模板
static func find_by_id(hero_id: String) -> Dictionary:
for hero in ALL_HEROES:
if hero.id == hero_id:
return hero
return ALL_HEROES[0]
## 获取指定稀有度的英雄列表
static func get_by_rarity(rarity: int) -> Array:
var result: Array = []
for hero in ALL_HEROES:
if hero.rarity == rarity:
result.append(hero)
return result4.3 抽卡系统
抽卡就是花金币或钻石,随机获得一个英雄。
C
using Godot;
using System.Collections.Generic;
/// <summary>
/// 抽卡管理器——处理英雄抽取
/// </summary>
public partial class GachaManager : Node
{
// 信号
[Signal] public delegate void HeroDrawnEventHandler(string heroId, HeroRarity rarity);
[Signal] public delegate void TenDrawCompletedEventHandler(
List<(string id, HeroRarity rarity)> results);
/// <summary>
/// 单次抽卡
/// </summary>
public bool DrawSingle()
{
if (!GameManager.Instance.SpendGold(IdleConstants.NormalDrawCost))
return false;
var (heroId, rarity) = RandomHero();
GD.Print($"抽到英雄: {heroId} ({rarity})");
EmitSignal(SignalName.HeroDrawn, heroId, (int)rarity);
return true;
}
/// <summary>
/// 十连抽(打九折)
/// </summary>
public bool DrawTen()
{
if (!GameManager.Instance.SpendGold(IdleConstants.TenDrawCost))
return false;
var results = new List<(string, HeroRarity)>();
for (int i = 0; i < 10; i++)
{
var (heroId, rarity) = RandomHero();
results.Add((heroId, rarity));
}
GD.Print("十连抽结果:");
foreach (var (id, rarity) in results)
{
GD.Print($" {id} ({rarity})");
}
EmitSignal(SignalName.TenDrawCompleted, results);
return true;
}
/// <summary>
/// 根据概率随机抽取一个英雄
/// </summary>
private (string heroId, HeroRarity rarity) RandomHero()
{
float roll = GD.Randf();
HeroRarity rarity;
if (roll < IdleConstants.LegendChance)
rarity = HeroRarity.Legend;
else if (roll < IdleConstants.LegendChance + IdleConstants.EpicChance)
rarity = HeroRarity.Epic;
else if (roll < IdleConstants.LegendChance + IdleConstants.EpicChance
+ IdleConstants.RareChance)
rarity = HeroRarity.Rare;
else
rarity = HeroRarity.Common;
// 从对应稀有度中随机选一个英雄
var heroes = HeroDatabase.GetByRarity(rarity);
int index = GD.Randi() % heroes.Count;
return (heroes[index].Id, rarity);
}
/// <summary>
/// 获取抽卡概率表
/// </summary>
public Dictionary<HeroRarity, float> GetDropRates()
{
return new Dictionary<HeroRarity, float>
{
{ HeroRarity.Common, IdleConstants.CommonChance },
{ HeroRarity.Rare, IdleConstants.RareChance },
{ HeroRarity.Epic, IdleConstants.EpicChance },
{ HeroRarity.Legend, IdleConstants.LegendChance }
};
}
}GDScript
extends Node
## 抽卡管理器——处理英雄抽取
# 信号
signal hero_drawn(hero_id: String, rarity: int)
signal ten_draw_completed(results: Array)
## 单次抽卡
func draw_single() -> bool:
if not GameManager.spend_gold(IdleConstants.NORMAL_DRAW_COST):
return false
var result = _random_hero()
print("抽到英雄: ", result[0], " (", result[1], ")")
hero_drawn.emit(result[0], result[1])
return true
## 十连抽
func draw_ten() -> bool:
if not GameManager.spend_gold(IdleConstants.TEN_DRAW_COST):
return false
var results: Array = []
for i in range(10):
results.append(_random_hero())
print("十连抽结果:")
for r in results:
print(" ", r[0], " (", r[1], ")")
ten_draw_completed.emit(results)
return true
## 根据概率随机抽取一个英雄
func _random_hero() -> Array:
var roll: float = randf()
var rarity: int
if roll < IdleConstants.LEGEND_CHANCE:
rarity = HeroRarity.LEGEND
elif roll < IdleConstants.LEGEND_CHANCE + IdleConstants.EPIC_CHANCE:
rarity = HeroRarity.EPIC
elif roll < IdleConstants.LEGEND_CHANCE + IdleConstants.EPIC_CHANCE \
+ IdleConstants.RARE_CHANCE:
rarity = HeroRarity.RARE
else:
rarity = HeroRarity.COMMON
var heroes = HeroDatabase.get_by_rarity(rarity)
var index: int = randi() % heroes.size()
return [heroes[index].id, rarity]4.4 英雄管理器
HeroManager 管理玩家拥有的所有英雄,包括升级、编队、碎片合成等功能。
C
using Godot;
using System.Collections.Generic;
using System.Linq;
/// <summary>
/// 英雄管理器——管理玩家拥有的英雄
/// </summary>
public partial class HeroManager : Node
{
// 玩家拥有的英雄列表(可包含重复的)
private List<HeroData> _ownedHeroes = new();
// 当前编队(最多6个英雄)
private List<HeroData> _party = new();
// 碎片收集 {英雄ID: 碎片数量}
private Dictionary<string, int> _fragments = new();
// 信号
[Signal] public delegate void HeroesChangedEventHandler();
[Signal] public delegate void HeroUpgradedEventHandler(string heroId, int newLevel);
public IReadOnlyList<HeroData> OwnedHeroes => _ownedHeroes.AsReadOnly();
public IReadOnlyList<HeroData> Party => _party.AsReadOnly();
public override void _Ready()
{
// 新游戏给一个初始英雄
if (_ownedHeroes.Count == 0)
{
AddHero("villager");
}
}
/// <summary>
/// 添加英雄到收藏
/// </summary>
public void AddHero(string heroId)
{
if (_ownedHeroes.Count >= 50) return; // 上限50个
var template = HeroDatabase.FindById(heroId);
_ownedHeroes.Add(template);
EmitSignal(SignalName.HeroesChanged);
}
/// <summary>
/// 升级英雄
/// </summary>
public bool UpgradeHero(int heroIndex)
{
if (heroIndex < 0 || heroIndex >= _ownedHeroes.Count)
return false;
var hero = _ownedHeroes[heroIndex];
int cost = hero.GetUpgradeCost();
if (!GameManager.Instance.SpendGold(cost))
return false;
_ownedHeroes[heroIndex] = hero.LevelUp();
EmitSignal(SignalName.HeroesChanged);
EmitSignal(SignalName.HeroUpgraded, hero.Id, hero.Level + 1);
GD.Print($"{hero.Name} 升到 {hero.Level + 1} 级!花费 {cost} 金币");
return true;
}
/// <summary>
/// 设置编队
/// </summary>
public bool SetParty(List<int> heroIndices)
{
if (heroIndices.Count > IdleConstants.MaxHeroes)
return false;
_party.Clear();
foreach (int idx in heroIndices)
{
if (idx >= 0 && idx < _ownedHeroes.Count)
{
_party.Add(_ownedHeroes[idx]);
}
}
return true;
}
/// <summary>
/// 获取所有英雄的总等级(用于计算加成)
/// </summary>
public int GetTotalLevels()
{
return _ownedHeroes.Sum(h => h.Level);
}
/// <summary>
/// 获取编队的总DPS
/// </summary>
public float GetPartyDps()
{
return _party.Sum(h => h.GetDps());
}
}GDScript
extends Node
## 英雄管理器——管理玩家拥有的英雄
var _owned_heroes: Array = [] # 玩家拥有的英雄
var _party: Array = [] # 当前编队
var _fragments: Dictionary = {} # 碎片收集
# 信号
signal heroes_changed
signal hero_upgraded(hero_id: String, new_level: int)
func _ready() -> void:
# 新游戏给一个初始英雄
if _owned_heroes.size() == 0:
add_hero("villager")
## 添加英雄
func add_hero(hero_id: String) -> void:
if _owned_heroes.size() >= 50:
return
var template = HeroDatabase.find_by_id(hero_id)
_owned_heroes.append(template.duplicate(true))
heroes_changed.emit()
## 升级英雄
func upgrade_hero(hero_index: int) -> bool:
if hero_index < 0 or hero_index >= _owned_heroes.size():
return false
var hero = _owned_heroes[hero_index]
var cost: int = hero.get_upgrade_cost()
if not GameManager.spend_gold(cost):
return false
_owned_heroes[hero_index] = hero.level_up()
heroes_changed.emit()
hero_upgraded.emit(hero.id, hero.level + 1)
return true
## 设置编队
func set_party(hero_indices: Array) -> bool:
if hero_indices.size() > IdleConstants.MAX_HEROES:
return false
_party.clear()
for idx in hero_indices:
if idx >= 0 and idx < _owned_heroes.size():
_party.append(_owned_heroes[idx])
return true
## 获取所有英雄的总等级
func get_total_levels() -> int:
var total: int = 0
for hero in _owned_heroes:
total += hero.level
return total
## 获取编队总DPS
func get_party_dps() -> float:
var total: float = 0
for hero in _party:
total += hero.get_dps()
return total4.5 英雄卡片UI
英雄在UI上以"卡片"的形式展示:
┌──────────────────┐
│ ★★★★ 传说 │ ← 稀有度星级
│ ┌────────────┐ │
│ │ │ │
│ │ 英雄头像 │ │ ← 英雄图片
│ │ │ │
│ └────────────┘ │
│ 龙骑士 │ ← 英雄名称
│ LV.15 │ ← 等级
│ ATK: 120 HP: 450│ ← 属性
│ 技能: 龙息 │ ← 技能
│ ┌──────┬──────┐ │
│ │ 升级 │ 装备 │ │ ← 操作按钮
│ └──────┴──────┘ │
└──────────────────┘4.6 本章小结
| 知识点 | 说明 |
|---|---|
| 英雄稀有度 | 普通/稀有/史诗/传说四种,概率递减属性递增 |
| 英雄数据库 | 预定义所有英雄的属性和技能 |
| 抽卡系统 | 单抽和十连抽,根据概率随机获得英雄 |
| 英雄管理器 | 收藏、升级、编队、碎片合成 |
| 英雄卡片UI | 星级、头像、属性、操作按钮 |
下一章我们将实现自动战斗系统——英雄们自动打怪推图的核心机制。
