|
|
如果你已经有了一份英雄技能配置的 Excel 表,那么我们要做的就是把这份表格数据变成 Unity 项目中可以直接使用的配置信息。最专业且高效的做法是在 Unity 编辑器中,通过脚本将 Excel 数据生成 ScriptableObject 资产。这样你就不用每次在运行时解析 Excel,性能更好,策划修改表格后也只需在 Unity 里点一个按钮“刷新”即可。
🎯 目标
有一份 Excel 表格,包含多个英雄及其技能信息。
在 Unity 中一键生成对应的 ScriptableObject 配置资产。
游戏运行时直接加载这些资产,读取所有英雄和技能数据,用于游戏逻辑。
📁 Excel 表格结构设计
我们假设有两个表(两个 Sheet)或一个表包含所有字段,为了方便管理,推荐使用两个独立的 Excel 文件或同一个文件的多个 Sheet:
1. Hero.xlsx(英雄基础信息)
HeroID HeroName Skill1ID Skill2ID Skill3ID Skill4ID
101 盖伦 1011 1012 1013 1014
102 艾希 1021 1022 1023 1024
2. Skill.xlsx(技能详情)
SkillID SkillName Description Damage Cooldown IconPath
1011 致命打击 下次攻击... 30 8 Icons/Garen_Q
1012 勇气 被动... 0 0 Icons/Garen_W
... ... ... ... ... ...
注意:IconPath 可以是资源路径,如 Sprites/Skills/Q。
🧱 第一步:在 Unity 中定义数据类(ScriptableObject)
创建两个脚本,分别表示英雄和技能的数据结构。
csharp
// SkillData.cs
using UnityEngine;
[CreateAssetMenu(fileName = "SkillData", menuName = "GameConfig/SkillData")]
public class SkillData : ScriptableObject
{
public int skillID;
public string skillName;
public string description;
public int damage;
public float cooldown;
public string iconPath; // 或者用 Sprite 引用,这里用路径便于动态加载
}
csharp
// HeroData.cs
using UnityEngine;
using System.Collections.Generic;
[CreateAssetMenu(fileName = "HeroData", menuName = "GameConfig/HeroData")]
public class HeroData : ScriptableObject
{
public int heroID;
public string heroName;
public List<SkillData> skillList = new List<SkillData>(); // 直接引用技能资产
}
这里使用 List<SkillData> 直接引用,而不是存 ID,这样在 Inspector 中能直接拖拽关联,更方便调试。
🔧 第二步:编写 Excel 导入编辑器脚本
创建一个编辑器脚本(放在 Editor 文件夹下),实现读取 Excel 并生成 ScriptableObject 资产的功能。
csharp
// ExcelToConfigImporter.cs
using OfficeOpenXml; // 需要导入 EPPlus (4.5.3.3 免费版)
using System.IO;
using UnityEngine;
using UnityEditor;
using System.Collections.Generic;
public class ExcelToConfigImporter : EditorWindow
{
[MenuItem("Tools/Import Excel Configs")]
public static void ShowWindow()
{
GetWindow<ExcelToConfigImporter>("导入配置");
}
private void OnGUI()
{
if (GUILayout.Button("从 Excel 生成配置"))
{
ImportFromExcel();
}
}
private void ImportFromExcel()
{
// 假设 Excel 文件放在 Assets/StreamingAssets/Configs/ 下(也可自定义)
string excelFolder = Application.dataPath + "/StreamingAssets/Configs/";
string heroFilePath = excelFolder + "Hero.xlsx";
string skillFilePath = excelFolder + "Skill.xlsx";
// 1. 读取技能表,构建 SkillID -> SkillData 的映射(先创建技能资产)
Dictionary<int, SkillData> skillDict = new Dictionary<int, SkillData>();
using (var package = new ExcelPackage(new FileInfo(skillFilePath)))
{
ExcelWorksheet sheet = package.Workbook.Worksheets[0]; // 第一个 sheet
int rowCount = sheet.Dimension.Rows;
for (int row = 2; row <= rowCount; row++) // 跳过标题行
{
int id = sheet.Cells[row, 1].GetValue<int>();
string name = sheet.Cells[row, 2].GetValue<string>();
string desc = sheet.Cells[row, 3].GetValue<string>();
int damage = sheet.Cells[row, 4].GetValue<int>();
float cd = sheet.Cells[row, 5].GetValue<float>();
string icon = sheet.Cells[row, 6].GetValue<string>();
// 创建 SkillData 资产
SkillData skill = ScriptableObject.CreateInstance<SkillData>();
skill.skillID = id;
skill.skillName = name;
skill.description = desc;
skill.damage = damage;
skill.cooldown = cd;
skill.iconPath = icon;
// 保存为资产文件
string assetPath = $"Assets/Resources/Configs/Skills/Skill_{id}.asset";
AssetDatabase.CreateAsset(skill, assetPath);
AssetDatabase.SaveAssets();
skillDict[id] = skill; // 存入字典供后续英雄引用
}
}
Debug.Log($"技能数据导入完成,共 {skillDict.Count} 个技能");
// 2. 读取英雄表,创建 HeroData 并引用对应的技能资产
using (var package = new ExcelPackage(new FileInfo(heroFilePath)))
{
ExcelWorksheet sheet = package.Workbook.Worksheets[0];
int rowCount = sheet.Dimension.Rows;
for (int row = 2; row <= rowCount; row++)
{
int heroId = sheet.Cells[row, 1].GetValue<int>();
string heroName = sheet.Cells[row, 2].GetValue<string>();
int skill1Id = sheet.Cells[row, 3].GetValue<int>();
int skill2Id = sheet.Cells[row, 4].GetValue<int>();
int skill3Id = sheet.Cells[row, 5].GetValue<int>();
int skill4Id = sheet.Cells[row, 6].GetValue<int>();
HeroData hero = ScriptableObject.CreateInstance<HeroData>();
hero.heroID = heroId;
hero.heroName = heroName;
// 从字典中获取技能资产并添加到列表
hero.skillList.Add(skillDict[skill1Id]);
hero.skillList.Add(skillDict[skill2Id]);
hero.skillList.Add(skillDict[skill3Id]);
hero.skillList.Add(skillDict[skill4Id]);
string assetPath = $"Assets/Resources/Configs/Heroes/Hero_{heroId}.asset";
AssetDatabase.CreateAsset(hero, assetPath);
AssetDatabase.SaveAssets();
}
}
Debug.Log("英雄配置导入完成!");
AssetDatabase.Refresh();
}
}
📂 文件夹结构建议
Assets/StreamingAssets/Configs/ 存放 Excel 文件(方便修改)
Assets/Resources/Configs/Skills/ 存放生成的技能资产
Assets/Resources/Configs/Heroes/ 存放生成的英雄资产
使用 Resources 文件夹是为了方便运行时用 Resources.Load 加载。你也可以改用 Addressables 进行更细粒度的资源管理。
🕹️ 第三步:在游戏运行时加载配置
在游戏中,你可以通过一个管理类来加载所有英雄数据,例如:
csharp
using UnityEngine;
using System.Collections.Generic;
public class ConfigManager : MonoBehaviour
{
public static ConfigManager Instance { get; private set; }
private Dictionary<int, HeroData> heroDict = new Dictionary<int, HeroData>();
void Awake()
{
Instance = this;
LoadAllHeroes();
}
void LoadAllHeroes()
{
// 方式1:直接加载所有英雄资产(如果你知道它们的命名规则)
HeroData[] heroes = Resources.LoadAll<HeroData>("Configs/Heroes");
foreach (var h in heroes)
{
heroDict[h.heroID] = h;
}
Debug.Log($"加载了 {heroDict.Count} 个英雄");
}
public HeroData GetHero(int id)
{
heroDict.TryGetValue(id, out HeroData hero);
return hero;
}
}
在游戏逻辑中,你可以这样使用:
csharp
HeroData garen = ConfigManager.Instance.GetHero(101);
foreach (SkillData skill in garen.skillList)
{
Debug.Log($"{skill.skillName} - 伤害:{skill.damage}");
}
🔁 工作流总结
策划维护 Excel:在 StreamingAssets/Configs/ 中修改英雄和技能表。
开发者一键导入:在 Unity 编辑器菜单中点击 Tools/Import Excel Configs。
编辑器脚本自动生成 ScriptableObject 资产,覆盖旧的资产。
游戏运行时加载这些资产,直接使用强类型数据,无需解析 Excel。
🧠 进阶优化建议
增量导入:可以只更新被修改的资产,而不是全部重建,需要记录每个数据的最后修改时间。
使用 Addressable:将配置资产作为 Addressable 资源,实现热更新。
支持多个 Sheet:如果所有数据在一个 Excel 的不同 Sheet 中,你可以通过 package.Workbook.Worksheets["Hero"] 按名称获取。
错误处理:对 Excel 中的空值、类型不匹配等进行健壮校验,避免导入失败。
⚠️ 注意事项
EPPlus 许可证:EPPlus 5.0+ 商业使用需付费,请使用 4.5.3.3 及以下版本(NuGet 可下载)。
文件路径:Application.dataPath 在编辑器中有效,打包后不要依赖此路径(我们只是在编辑器中使用,所以安全)。
资源刷新:AssetDatabase.Refresh() 会刷新工程,确保新资产显示在 Project 窗口。
🏆 总结
通过将 Excel 配置转化为 ScriptableObject 资产,你的游戏将获得:
编辑器友好:策划能直观地在 Unity 中查看、修改配置(即使不改 Excel)。
运行时高性能:直接读取内存中的对象,无需 I/O 或解析。
工作流清晰:策划改 Excel → 点击导入 → 完成,无需程序员介入。
这就是专业团队处理游戏配置的常用方式。祝你开发顺利!🎮
|
|