Luban是一个很强大的Unity配置工具,支持excel、json、xml、yaml、lua等多种数据源。并且支持继承机制,能够表达行为树、技能、剧情等复杂的数据格式。同时Luban能够导出多种语言,支持c#、java、go、lua等多种代码。同时Luban使用MIT协议开源,
本文仅作为我个人在Unity使用luban中的记录,使用习惯也仅是我个人习惯,仅供参考。 如果需要更详细具体的说明,请参考Luban官方文档。
3、 Luban添加表格
接下来,我们尝试向Luban中添加新的表格,通常情况下,为了方便阅读以及分组,我们会将表格分为好几个模块,比如:角色、技能、物品等等。我们通常使用文件夹进行管理。
在Datas文件夹下创建Character文件夹和Weapon文件夹。创建完毕后如下图所示。
Character.xlsx的创建
我们在Character文件夹中创建Character.xlsx文件并打开。
我们先将第一列的表格定义进行填充,##var
、##type
、##
。(注意,由于我个人使用不涉及服务器配置,所以不配置##group
行,如有需要,请参考Luban官方文档)
其次,分别在第一行添加以下内容,name
、run_speed
、hp
、start_weapon
,第二行分别对应填入数据类型,string、float、int、int。这些数据分别代表名字、跑步速度、初始生命值、起始的武器id。之后填入数据如下图所示。
由于Character通常在游戏中只进行一次配置,也可以写成纵表的形式,方便阅读和编辑。(使用方式是在A1单元格添加##column
)。
切换到纵表如下图所示。
编辑完毕后保存表格。(最终保存纵表)
Weapon.xlsx的创建
切换到Weapon文件夹,创建WeaponBase.xlsx文件并打开。
同样的,我们添加##var
、##type
、##
。
我们为武器添加id,名称,描述,攻击力等字段。具体如下图。
通常情况下,近战武器会有多段不同的攻击,分别具有不同的攻击力和攻击速度。注意damage和attack_speed字段的配表方式。
speed字段的type为string?,这表示为可空类型,导出数据时值为null,如果需要非null类型,则使用""进行填写。
damage字段的type使用了list,float
这表示数据为List<float>
类型,且每个数据占用一个单元格。
attack_speed字段则是使用了(list#sep=|),float
的type,这表示可以使用|作为分隔符,将list数据填写在一个单元格中,最终将得到List<float>
的数据。
tables.xlsx的配置
接下来我们将填写好的表格配置到__tables__.xlsx中去。只有配置在__tables__.xlsx中,Luban才可以正确的读取并且生成相应的数据和内容。
首先删除默认的demo表的配置行(此时可以删除Datas下的demo.item.xlsx文件,Luban已经不会再读取此文件),并且添加如下图的内容。
举一个简单的例子说明全名和记录类名是什么:
public class WeaponBases
{
public List<WeaponBase> Weaponbases;
}
public class WeaponBase
{
public int Id;
Public string Name;
}
在tables配置中,全名是第一个类,也就是WeaponBases
的名字,而记录类名则是第二个类,WeaponBase
的名字。
在Characters中,mode列配置为了one
,这表示Character是一个单例表。使用时不需要Get()
,可以从Characters中直接获取内容。
配置完毕并且保存后,运行gen.bat
进行生成。
特别注意的是,Luban配置时##var
行的内容最好写成形如aa_bb_cc
的形式,Luban会按照生成语言的不同选用不同的代码风格。当然也可以手动选择代码风格,请参考官方文档
阅读部分生成的源码
Luban生成的Table表。表中有Character
属性和WeaponBases
属性。
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
using Luban;
using SimpleJSON;
namespace cfg
{
public partial class Tables
{
public Character Character {get; }
public WeaponBases WeaponBases {get; }
public Tables(System.Func<string, JSONNode> loader)
{
Character = new Character(loader("character"));
WeaponBases = new WeaponBases(loader("weaponbases"));
ResolveRef();
}
private void ResolveRef()
{
Character.ResolveRef(this);
WeaponBases.ResolveRef(this);
}
}
}
Characters
中,可以直接获得配置到的属性,也就是正确配置了单例表。
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
using Luban;
using SimpleJSON;
namespace cfg
{
public partial class Characters
{
private readonly Character _data;
public Character Data => _data;
public Characters(JSONNode _buf)
{
int n = _buf.Count;
if (n != 1) throw new SerializationException("table mode=one, but size != 1");
{ if(!_buf[0].IsObject) { throw new SerializationException(); } _data = Character.DeserializeCharacter(_buf[0]); }
}
/// <summary>
/// 名字
/// </summary>
public string Name => _data.Name;
/// <summary>
/// 跑步速度
/// </summary>
public float RunSpeed => _data.RunSpeed;
/// <summary>
/// 初始生命值
/// </summary>
public int Hp => _data.Hp;
/// <summary>
/// 起始的武器ID
/// </summary>
public int StartWeapon => _data.StartWeapon;
public void ResolveRef(Tables tables)
{
_data.ResolveRef(tables);
}
}
}
WeaponBases
中,可以看到_dataMap
和_dataList
两个字段。通过Get(int key)
方法即可获取内容。由于默认设置,配置的Key为ID字段
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
using Luban;
using SimpleJSON;
namespace cfg
{
public partial class WeaponBases
{
private readonly System.Collections.Generic.Dictionary<int, WeaponBase> _dataMap;
private readonly System.Collections.Generic.List<WeaponBase> _dataList;
public WeaponBases(JSONNode _buf)
{
_dataMap = new System.Collections.Generic.Dictionary<int, WeaponBase>();
_dataList = new System.Collections.Generic.List<WeaponBase>();
foreach(JSONNode _ele in _buf.Children)
{
WeaponBase _v;
{ if(!_ele.IsObject) { throw new SerializationException(); } _v = WeaponBase.DeserializeWeaponBase(_ele); }
_dataList.Add(_v);
_dataMap.Add(_v.Id, _v);
}
}
public System.Collections.Generic.Dictionary<int, WeaponBase> DataMap => _dataMap;
public System.Collections.Generic.List<WeaponBase> DataList => _dataList;
public WeaponBase GetOrDefault(int key) => _dataMap.TryGetValue(key, out var v) ? v : null;
public WeaponBase Get(int key) => _dataMap[key];
public WeaponBase this[int key] => _dataMap[key];
public void ResolveRef(Tables tables)
{
foreach(var _v in _dataList)
{
_v.ResolveRef(tables);
}
}
}
}