上一篇主要对比了两个框架的整体定位、架构风格和 UI 开发方式。
这一篇继续看更偏工程落地的部分:
资源管理。
热更新。
配置表和协议生成。
网络与服务器协作。
对象池和工程检查。
文档生态与框架宣传方式。
还是先说明一点:这不是一篇"谁更强"的文章。
HTFramework 更像一个模块齐全、文档成熟、上手路径清晰的 Unity 客户端快速开发框架;MyFramework 更像一套从长期商业项目中沉淀出来的工程体系,重点不是模块数量,而是项目流程、工具链、热更分层和客户端服务器协作。HTFramework README 中列出了 UI、Resource、Procedure、Network、ObjectPool、ReferencePool 等大量通用模块;MyFramework README 则强调热更新分层、UI 代码生成、配置表工具链、网络协议代码生成、工程检查、低 GC、强生命周期控制以及客户端与服务器协作。
下面的代码都是简化示意,主要用于表达设计取向,不代表两个框架源码逐字实现。
一、资源管理:一个偏通用加载模式,一个偏项目资源管线治理
资源管理是 Unity 框架里绕不开的模块。
HTFramework 的 Resource 模块定位很清楚:它是资源管理器,主要用于动态加载资源,只支持异步加载,并且支持 Resource、AssetBundle、Addressables 三种加载模式,UI 模块也会自动调用资源管理器加载 UI 实体。
所以 HTFramework 的资源系统更像是一个统一的加载入口。
业务层关心的是:
我要加载什么资源?
资源来自 Resources、AssetBundle 还是 Addressables?
加载完成以后回调给我。
用简化代码表示,大概是这种感觉:
public class LoginProcedure
{
public void Enter()
{
Main.m_Resource.LoadAsset<GameObject>(
"Assets/Game/UI/Login.prefab",
onLoadLoginUI
);
}
private void onLoadLoginUI(GameObject prefab)
{
GameObject ui = Object.Instantiate(prefab);
ui.SetActive(true);
}
}
这种设计的优势是通用。
不同项目可能用 Resources,也可能用 AssetBundle,也可能用 Addressables。
框架提供统一入口,业务层不需要到处写不同加载逻辑。
而 MyFramework 的资源管理更偏"项目资源管线治理"。
MyFramework 当然也需要解决加载问题,但它更关心的是:
资源怎么分包?
AssetBundle 依赖是否合理?
有没有重复打包?
有没有环形依赖?
热更资源和非热更资源有没有互相引用?
图集、材质、Prefab、meta 是否符合项目规范?
资源路径能不能被配置表检查到?
资源问题能不能在编辑器阶段提前发现?
这类问题不只是 LoadAsset 能解决的。
比如一个资源路径写在配置表里,如果路径错了,最好不要等到运行时才报错。
更合理的是在编辑器阶段就检查:
public class EDItem : ExcelData
{
public int mID; // 道具 ID
public string mName; // 道具名
public string mIconPath; // 图标路径
}
protected void checkItemIconPath(EDItem item)
{
if (!mResourceManager.isResourceExist(item.mIconPath))
{
logError("道具图标不存在, id:" + item.mID + ", path:" + item.mIconPath);
}
}
这就是 MyFramework 更偏工程体系的地方。
HTFramework 的 Resource 更强调"统一加载资源"。
MyFramework 的资源体系更强调"资源从配置、引用、打包、检查到运行时加载的完整链路"。
一个是加载模块。
一个是资源生产和使用流程。
二、热更新:一个是框架能力,一个是架构前提
HTFramework 有 Hotfix 模块,也有基于 Deployment + HybridCLR 的资源及代码热更新实战演示。HTFramework 的公开说明里,Hotfix 模块被描述为轻量级热更新框架;它也有单独的 HotfixDemo,用来演示基于 HTFrameworkDeployment 和 HybridCLR 的资源及代码热更新流程。
也就是说,HTFramework 是提供热更新能力的。
但从整体结构看,HTFramework 依然更像是一个模块化客户端框架,热更新是它的能力之一。
而 MyFramework 的热更新更像是整个框架的架构前提。
MyFramework README 里直接把代码按是否可热更进行了明确分层:
Frame_Base -> 不可热更,最基础的框架代码
Frame_Game -> 不可热更,项目非热更代码的框架
Game -> 不可热更,项目应用层启动逻辑
Frame_HotFix -> 可热更,框架层热更代码
HotFix -> 可热更,项目应用层热更代码
它的依赖关系也围绕这个分层展开。
这个区别很关键。
如果热更新只是一个模块,那么项目可以先按普通结构写,后面再接热更。
但如果热更新是架构前提,那么项目一开始就要考虑:
哪些代码不能热更?
哪些代码必须放到热更层?
启动逻辑怎么保持稳定?
热更层怎么访问非热更层?
框架层热更和业务层热更怎么隔离?
生成代码应该输出到哪个程序集?
混淆和热更怎么配合?
用简化代码表示,MyFramework 更像这种分层思路:
// Game 层:不可热更,只负责启动和加载热更入口
public class GameEntry : MonoBehaviour
{
private void Start()
{
initFrame();
loadHotFixAssembly();
startHotFix();
}
}
// HotFix 层:可热更,真正的业务逻辑入口
public class HotFixGameEntry
{
public void start()
{
mSceneManager.enterScene<SceneLogin>();
}
}
这说明 MyFramework 的热更新不是"加一个 Hotfix 模块"这么简单。
它更关心项目长期运行时,哪些东西能改,哪些东西不能改。
HTFramework 的热更新能力更适合通用框架扩展。
MyFramework 的热更新分层更适合从一开始就按热更项目来组织代码。
三、配置表:一个偏 DataSet,一个偏配置生产工具链
配置表是 MyFramework 和 HTFramework 差异非常明显的地方。
HTFramework 有 DataSet 模块。它的说明是:任何需要存储数据的地方都可以定义为自定义数据集,包括预制配置文件、运行时生成的动态数据、从后台拉取的数据等。
这类设计更偏"数据集管理"。
比如可以把一个玩家数据、设置数据、运行时缓存数据定义成 DataSet:
public class PlayerDataSet
{
public int Level;
public int Exp;
public string Name;
}
public class PlayerSystem
{
public void LoadPlayerData()
{
PlayerDataSet data = Main.m_DataSet.GetDataSet<PlayerDataSet>();
int level = data.Level;
string name = data.Name;
}
}
它解决的是运行时数据如何统一组织和访问。
而 MyFramework 的配置表工具链更偏"生产流程"。
MyFramework README 里明确写到,它使用 CSV 作为配置表格式,并配套自研表格编辑器,支持字段类型检查、枚举合法性检查、ID 唯一性检查、表格引用检查、资源路径检查、客户端代码生成、服务器代码生成、运行时代码检查逻辑生成。
这说明 MyFramework 的配置表不是简单读取一个数据文件,而是完整工作流:
CSV 配置表
↓
表格编辑器
↓
字段检查 / 引用检查 / 路径检查
↓
生成客户端表格代码
↓
生成服务器表格代码
比如一张道具表,最终可能生成这样的客户端代码:
public class EDItem : ExcelData
{
public int mID; // 道具 ID
public string mName; // 道具名称
public int mQuality; // 道具品质
public string mIconPath; // 图标路径
}
业务层使用时,不应该到处解析 CSV,而是直接查生成后的强类型数据:
protected void refreshItem(int itemID)
{
EDItem item = mExcelItem.query(itemID);
if (item == null)
{
logError("找不到道具配置, id:" + itemID);
return;
}
mNameText.setText(item.mName);
mIconImage.setSprite(item.mIconPath);
}
这就是两者差异。
HTFramework 的 DataSet 更像通用数据管理模块。
MyFramework 的配置表系统更像项目生产工具链。
尤其是客户端和服务器都要使用同一份配置时,MyFramework 这种配置生成就更有价值。
因为它解决的不只是"客户端如何读表",而是:
配置表能不能提前检查?
客户端和服务器字段是否一致?
ID 是否唯一?
枚举是否合法?
资源路径是否存在?
表之间引用是否正确?
这类问题越到大型项目越重要。
四、协议生成和网络:一个偏客户端通信模块,一个偏客户端服务器协作
HTFramework 有 Network 模块。README 中对 Network 的描述是:网络客户端模块,以单个通信管道为单位,每个管道支持 TCP/UDP 等协议,可以为每个管道定义通信消息格式,能胜任常见通信环境。
这种设计很适合客户端框架。
你需要通信,就创建一个网络管道。
你需要 TCP 或 UDP,就配置对应协议。
你需要定义消息格式,就在管道里处理。
简化示意:
public class LoginSystem
{
public void Login(string account, string password)
{
LoginMessage msg = new LoginMessage();
msg.Account = account;
msg.Password = password;
Main.m_Network.Send("GameServer", msg);
}
}
而 MyFramework 的网络系统更偏客户端服务器配套。
MyFramework README 里写到,它有配套服务器框架 MyServerFramework,客户端与服务器可以共享协议生成、配置表生成等工具链,适合需要长期维护的中大型项目。它还明确列出了网络协议代码生成,支持消息类生成、字段序列化生成、字段反序列化生成、消息注册代码生成、客户端消息代码生成、服务器消息代码生成和手写逻辑代码保留。
这说明 MyFramework 的网络不是单纯客户端发包收包。
它关注的是:
协议怎么定义?
客户端消息代码怎么生成?
服务器消息代码怎么生成?
字段序列化和反序列化能不能自动生成?
消息注册能不能自动生成?
手写处理逻辑能不能保留?
客户端和服务器能不能共用同一套协议配置?
比如协议配置中定义了登录消息:
CSLogin
string account
string password
SCLoginRet
int result
long playerGUID
生成后的客户端可能是:
public class CSLogin : NetPacket
{
public string mAccount;
public string mPassword;
public override void write(PacketWriter writer)
{
writer.writeString(mAccount);
writer.writeString(mPassword);
}
}
服务器也可以生成对应的读取代码:
class CSLogin : public NetPacket
{
public:
std::string mAccount;
std::string mPassword;
void read(PacketReader& reader)
{
reader.readString(mAccount);
reader.readString(mPassword);
}
};
业务层只关心发送消息:
protected void onLoginButtonClick()
{
CSLogin msg = new();
msg.mAccount = mAccountInput.getText();
msg.mPassword = mPasswordInput.getText();
mNetManager.sendMessage(msg);
}
这就是 MyFramework 更偏 MMORPG / 网络游戏工程体系的地方。
HTFramework 的 Network 更像客户端网络通信模块。
MyFramework 的协议生成更像客户端和服务器之间的协作工具链。
对单机游戏、小型联网功能来说,HTFramework 这种 Network 模块已经足够。
对 MMO、长连接、协议数量多、客户端服务器强协作的项目来说,MyFramework 这种双端协议生成更贴近实际需求。
五、对象池和低 GC:一个提供通用池模块,一个强调生命周期和重置
HTFramework 的 ObjectPool 模块专用于 GameObject 类型对象池,用来复用 GameObject,减少频繁创建和删除对象时的开销;ReferencePool 则可用于任意引用类型对象池。
这是一套很标准的池化体系。
简化示意:
public class BulletSystem
{
public void Fire()
{
GameObject bullet = Main.m_ObjectPool.Spawn("Bullet");
bullet.transform.position = getFirePosition();
bullet.SetActive(true);
}
public void Recycle(GameObject bullet)
{
bullet.SetActive(false);
Main.m_ObjectPool.Despawn("Bullet", bullet);
}
}
这类对象池主要解决:
少 Instantiate。
少 Destroy。
减少 GC。
提高频繁对象创建场景的性能。
而 MyFramework 的对象池体系更强调"重置"和"生命周期"。
在 MyFramework 里,池化对象不是简单拿出来再塞回去,而是要考虑:
对象是否已经销毁?
对象是否正在回收?
这一次分配和上一次分配如何区分?
回收以后外部引用是否置空?
临时对象是否忘记归还?
对象字段是否全部重置?
List、Dictionary、Array、byte\[\] 这些容器是否也要池化?
简化示意:
public class DamageNumberData : ClassObject
{
public Vector3 mPosition;
public float mTime;
public List<byte> mNumberList;
public List<Vector2> mKeyFrameList;
public override void resetProperty()
{
base.resetProperty();
mPosition = Vector3.zero;
mTime = 0.0f;
if (mNumberList != null)
{
mNumberList.Clear();
}
if (mKeyFrameList != null)
{
mKeyFrameList.Clear();
}
}
}
申请对象:
CLASS(out DamageNumberData data);
data.mPosition = pos;
data.mNumberList.Add(1);
data.mNumberList.Add(2);
data.mNumberList.Add(3);
回收对象:
UN_CLASS(ref data);
注意这里用的是 ref,目的就是回收以后把外部引用置空,避免旧逻辑继续访问已经回池的对象。
这就是 MyFramework 对象池更强调的点:
对象池真正麻烦的不是复用,而是复用前后的状态干净。
如果一个对象回池时没有清理干净,下次拿出来就可能带着上一次的脏数据。
普通项目里,池化 GameObject 就能解决很多问题。
但在低 GC、热更、网络消息、临时容器、UI 子窗口、伤害数字、配置解析这些场景里,只池化 GameObject 远远不够。
所以 MyFramework 的低 GC 不是单点优化,而是一种整体习惯:
普通类对象池化。
List / Dictionary / Array 池化。
UI 子窗口池化。
特效和 Prefab 池化。
临时对象跨帧未回收时给出检查。
池化对象必须 resetProperty。
这也是 MyFramework 和 HTFramework 在对象池上的设计取向差异。
HTFramework 提供通用池模块。
MyFramework 更强调池化对象的生命周期规则。
六、编辑器工具链:一个偏框架工具箱,一个偏项目质量兜底
HTFramework 的公开文档和模块展示非常成熟,它有编码规范、文档博客、游戏实战教程,以及大量模块说明。README 中能看到超级坦克大战、FTG2D 横版格斗、RPG2D、MMORPG + 中国象棋联网对战等实战教程入口。
这对开源框架来说非常重要。
因为新用户接触一个框架时,最怕的不是功能少,而是不知道怎么开始。
HTFramework 在这方面做得很好:
模块说明清楚。
博客入口明确。
教程案例多。
使用者容易找到学习路径。
MyFramework 目前更偏"项目质量兜底"。
它的工具链不是只为了方便开发,而是为了提前发现项目问题。
比如:
资源路径检查。
配置表字段检查。
协议代码生成。
UI 代码生成。
热更引用检查。
资源引用反查。
AssetBundle 依赖分析。
重复打包检测。
图集检查。
Prefab 规范检查。
代码规范检查。
这类工具的价值,通常只有项目做大以后才会特别明显。
小项目可能觉得麻烦。
大项目会发现这是救命的。
因为大型项目里很多问题不能靠人工检查:
哪个资源被重复打包了?
哪个配置表引用了不存在的资源?
哪个热更资源引用了非热更资源?
哪个 UI 节点改名导致生成代码失效?
哪个协议字段客户端和服务器不一致?
哪个对象池对象没有正确 resetProperty?
这些问题如果都等运行时发现,成本就太高了。
七、总结:HTFramework 更像模块框架,MyFramework 更像工程体系
对比下来,两个框架的差异可以这样概括。
HTFramework 更适合这样描述:
它是一个模块化 Unity 快速开发框架。
它把 UI、Resource、Procedure、FSM、Entity、Network、ObjectPool、ReferencePool 等能力拆成清晰模块。
它的文档、博客和教程更成熟。
它更适合希望快速搭建 Unity 客户端项目的使用者。
MyFramework 更适合这样描述:
它是一套面向长期项目的 Unity 工程化框架。
它不只关心模块有没有,而是更关心整个项目流程是否可控。
它把热更分层、UI 生成、配置表工具链、协议代码生成、资源检查、对象池、低 GC、强生命周期和客户端服务器协作放在一起考虑。
它更适合 RPG、MMO、长线运营项目,或者那些 UI 多、配置多、协议多、资源多、需要热更新和服务端协作的项目。
所以这两个框架不是同一种问题的答案。
HTFramework 解决的是:
Unity 项目常见模块如何快速组织起来。
MyFramework 解决的是:
一个长期商业项目里,容易失控的流程如何被框架和工具链接管。
如果用一句话总结:
HTFramework 更像"模块齐全的 Unity 客户端框架"。
MyFramework 更像"服务长期项目的 Unity 工程化框架"。