XHFramework 是一个模块化的 Unity 游戏客户端框架,采用 AOT层(固定核心)+ 热更层(动态业务) 的双层架构设计。框架集成了 HybridCLR(代码热更新)和 YooAsset(资源热更新),实现了不发版本即可更新游戏逻辑和资源的能力。
- Unity — 游戏引擎
- HybridCLR — C# 代码热更新(基于 IL2CPP 的补充元数据方案)
- YooAsset — 资源管理与热更新
- Protobuf (Google.Protobuf) — 网络序列化协议
- Luban — 配置表生成工具
- UniTask — Unity 异步编程框架(替代协程)
- Newtonsoft.Json — JSON 序列化
│ ├── XHFrameworkClient/ # unity客户端目录
│ ├── XHFrameworkOut/ # 输出文件目录(安装包、logs)
│ ├── XHFrameworkServer/ # 资源服务器
│ ├── XHFrameworkTool/ # 工具(Luban、Proto)
Assets/
├── XFramework.Boot/ # 启动模块(AOT层)—— 游戏入口、资源更新、代码热更
├── XFramework.Core/ # 🏗️ 核心框架(AOT层)—— 15个管理器子系统
│ ├── Base/ # 框架入口 FW.cs、管理器基类 ManagerBase.cs
│ ├── Audio/ # 音频管理
│ ├── DataNode/ # 数据节点(树形数据存储)
│ ├── DataTable/ # 数据表管理(Luban配置表)
│ ├── Entity/ # 实体管理(游戏对象生命周期)
│ ├── Event/ # 全局事件系统
│ ├── Fsm/ # 有限状态机
│ ├── Http/ # HTTP短连接
│ ├── Localization/ # 多语言本地化
│ ├── Log/ # 日志系统
│ ├── Map/ # A*寻路系统
│ ├── Network/ # 网络通信(TCP/UDP/WebSocket)
│ ├── ObjectPool/ # 对象池
│ ├── ReferencePool/ # 引用池(轻量级对象复用)
│ ├── Resource/ # 资源管理(YooAsset集成)
│ ├── Scene/ # 场景管理
│ ├── Setting/ # 游戏设置
│ ├── Singleton/ # 单例基类
│ └── UI/ # UI框架(UGUI)
├── XFramework.Game/ # 🎮 游戏业务逻辑(热更层)—— 可热更新的业务代码
│ └── HotUpdateScripts/ # 热更脚本(Game.cs入口、各种Config、场景逻辑等)
├── XFramework.Editor/ # 🔧 编辑器工具
├── XFramework.Third/ # 📦 第三方库封装
└── XFramework.Unity/ # 🎨 Unity原生资源(场景、预制体、配置文件等)
Boot.cs (MonoBehaviour,挂在启动场景的 GameObject 上)
Awake()
│
└── 禁用 Unity 默认日志(Debug.unityLogger.logEnabled = false)
Start() [async]
│
├── ① FW.Init(gameObject) → 初始化框架,注册所有15个AOT层管理器
├── ② new YooAssetService() → 创建资源服务
├── ③ new HybridClrService() → 创建热更服务
├── ④ 实例化 PatchWindow → 显示更新界面(进度条、错误提示)
├── ⑤ yooAssetService.InitializeAndUpdate() → 资源版本检查 + 下载更新资源
├── ⑥ hybridClrService.StartHybridCLRUpdate() → 加载AOT元数据 + 热更DLL
├── ⑦ hybridClrService.EnterMainEntry() → 通过反射调用热更层 Game.Start()
└── ⑧ 销毁 PatchWindow → 更新完成,进入游戏
Update()
│
└── FW.Update(deltaTime, unscaledDeltaTime) → 每帧轮询所有管理器
OnDestroy()
└── FW.Shutdown() → 关闭并清理所有管理器
当 HybridCLR 加载完热更 DLL 后,通过反射调用 XFramework.Game.Game.Start():
Game.Start() [async]
│
├── ① PreloadDataTable() → 加载所有 Luban 配置表(实体表、本地化表、音乐表等)
├── ② InitHotUpdateConfigs() → 初始化热更层配置
│ ├── UIConfig.InitUI() → 注册UI组(Background、Normal、Dialog、Tips等)
│ ├── AudioConfig.InitAudio() → 注册音频组(Music、Sound、UISound)
│ ├── EntityConfig.InitEntity() → 注册实体组
│ ├── NetworkConfig.InitNetwork() → 配置TCP/UDP/WebSocket通道
│ └── HttpConfig.InitHttp() → 配置HTTP基础URL和Token
├── ③ PreloadLoadLocalization() → 初始化多语言系统(设置语言类型、数据获取委托)
├── ④ LoadScene(1) → 切换到游戏主场景
├── ⑤ 加载地图资源 + 寻路数据
└── ⑥ 加载角色资源
public static class BootConfig
{
public static readonly string packageName = "DefaultPackage";
public static readonly string packageUrl = "http://192.168.1.167:8084/XFramework/Res/";
public static readonly string hotUpdateDllName = "XFramework.Game.dll"; // 热更DLL名
public static readonly string hotUpdateEntryScript = "XFramework.Game.Game"; // 热更入口类
public static readonly string hotUpdateEntryMethod = "Start"; // 热更入口方法
}
- 为什么用双层架构? AOT层(XFramework.Core)编译后不可变,保证框架稳定性;热更层(XFramework.Game)通过 HybridCLR 可以随时更新业务逻辑,无需重新发版。
- 反射调用热更入口:HybridCLR 加载 DLL 后,通过 Assembly.GetType().GetMethod().Invoke() 调用 Game.Start(),这是 AOT 层和热更层的桥梁。
- PatchWindow 的事件驱动设计:通过 OnStepChange、OnDownloadProgress、OnError 等事件回调,将更新进度反馈给 UI,实现了更新逻辑和 UI 显示的解耦。
FW 是整个框架的静态门面类(Facade Pattern),维护所有管理器的注册、轮询和销毁。
- LinkedList m_Managers —— 按优先级排序的管理器链表,用于 Update 轮询
- Dictionary<Type, ManagerBase> m_ManagerDict —— 类型到实例的映射,用于快速获取管理器
| 优先级 | 管理器 | 职责 |
|---|---|---|
| 150 | SettingManager | 游戏设置、帧率、游戏速度 |
| 140 | DataNodeManager | 树形数据节点存储 |
| 130 | DataTableManager | Luban 配置表管理 |
| 120 | LocalizationManager | 多语言本地化 |
| 120 | PathFindingManager | A* 寻路 |
| 110 | ResourceManager | 资源加载与管理(YooAsset) |
| 100 | EventManager | 全局事件总线 |
| 90 | ObjectPoolManager | 对象池管理 |
| 85 | HttpManager | HTTP 短连接 |
| 80 | NetworkManager | 网络通信(TCP/UDP/WS) |
| 60 | UIManager | UI 界面管理 |
| 60 | FsmManager | 有限状态机 |
| 50 | AudioManager | 音频管理 |
| 40 | EntityManager | 实体管理 |
| 30 | SceneManager | 场景管理 |
RegisterManager()
├── 检查是否已存在(字典查重)
├── Activator.CreateInstance(typeof(T)) → 反射创建实例
├── 注册到 m_ManagerDict 字典
├── 按 Priority 插入 m_Managers 链表(优先级高的排前面)
└── 调用 manager.Init() 初始化
- Update():按链表顺序(优先级从高到低)轮询所有管理器
- Shutdown():按链表逆序(优先级从低到高)关闭所有管理器,最后清理引用池
public abstract class ManagerBase { public virtual int Priority => 0; // 优先级,越高越先被轮询,越后被关闭 public abstract void Init(); // 初始化 public abstract void Update(float elapseSeconds, float realElapseSeconds); // 每帧轮询 public abstract void Shutdown(); // 关闭清理 }
- 为什么用 LinkedList 而不是 List? 因为管理器注册时需要按优先级插入到正确位置,LinkedList 的插入操作是 O(1),而 List 的中间插入是 O(n)。
- 为什么关闭顺序是逆序? 高优先级的管理器(如 ResourceManager)可能被低优先级的管理器(如 SceneManager)依赖,所以先关闭低优先级的,确保依赖关系不被破坏。
- 热更层动态注册:通过 m_ManagerDict 字典和 GetManager() 方法,热更层可以动态注册和获取自定义管理器,扩展框架能力。
优先级:110 | 集成 YooAsset 资源管理是框架最核心的模块之一,负责所有资源的加载、缓存和释放。
| 资源组 | 说明 | 释放策略 |
|---|---|---|
| NormalResourceGroup | 普通资源 | 延迟释放,超时后自动回收 |
| ResidentResourceGroup(Global) | 全局常驻资源(字体、通用图集等) | 永不释放 |
| ResidentResourceGroup(Scene) | 场景常驻资源 | 切换场景时释放 |
| TransientResourceGroup | 临时资源 | 加载后立即释放句柄 |
- 配置了内存压力阈值(ResourceMemoryConfig)
- 当内存超过阈值时自动触发资源释放
- 场景切换时自动清理场景级资源
// 异步加载资源 await FW.ResourceManager.LoadAssetAsync(assetPath, priority); await FW.ResourceManager.LoadGameObjectAsync(assetPath, priority);
// 预加载常驻资源 await FW.ResourceManager.PreloadGlobalResidentAssetAsync(assetPath); await FW.ResourceManager.PreloadSceneResidentGameObjectAsync(assetPath);
// 场景加载 await FW.ResourceManager.LoadSceneAsync(scenePath, loadMode, priority);
// 释放资源 FW.ResourceManager.Release(asset, delayTime);
优先级:60 | 基于 UGUI
- UIGroup(界面组):如 Background、Normal、Dialog、Tips,每个组有独立的深度范围
- UIForm(界面基类):所有 UI 界面继承此类,拥有完整的生命周期
- DepthFactor:UIGroup 之间深度间隔 10000,UIForm 之间深度间隔 100,确保层级不冲突
Init(首次创建)
│
├── BindInit() → 自动绑定 UI 元素
└── OnInit() → 子类初始化逻辑
│
Open(每次打开)
│
└── OnOpen() → 子类打开逻辑
│
├── Pause() ←→ Resume() → 被上层界面覆盖时暂停/恢复
├── Cover() ←→ Reveal() → 被遮挡/恢复可见
└── OnUpdate() → 每帧轮询
│
Close(关闭)
│
└── OnClose() → 子类关闭逻辑
│
Recycle(回收到对象池)
// Init 方法中自动完成: _cachedCanvas = gameObject.GetOrAddComponent(); // 添加 Canvas _cachedCanvas.overrideSorting = true; // 覆盖排序 _canvasGroup = gameObject.GetOrAddComponent(); // 添加 CanvasGroup rectTransform.anchorMin = Vector2.zero; // 全屏拉伸 rectTransform.anchorMax = Vector2.one; gameObject.GetOrAddComponent(); // 添加射线检测
UIForm 内置了完整的指针事件支持,通过位标记(Flags)选择性绑定:
- Click、DoubleClick、LongPress(开始/持续/结束)
- PointerEnter/Exit、PointerDown/Up
- BeginDrag/Drag/EndDrag/Drop
- Scroll、Select/Deselect
优先级:40 用于管理游戏中的动态对象(角色、NPC、怪物、特效等)。
- EntityGroup(实体组):按类型分组管理(如 Player、Monster、Effect)
- Entity(实体基类):继承 MonoBehaviour,拥有完整生命周期
- EntityData(实体数据):携带位置、旋转、配置表ID等初始化数据
- 父子关系:支持实体之间的附加/解除(如骑乘、装备挂载)
WillInit → Inited → WillShow → Showed → WillHide → Hidden → WillRecycle → Recycled
protected virtual void OnInit(object userData) { } // 首次创建 protected virtual void OnShow(object userData) { } // 显示(设置位置、旋转等) protected virtual void OnHide(object userData) { } // 隐藏 protected virtual void OnUpdate(float elapseSeconds, float realElapseSeconds) { } // 每帧更新 protected virtual void OnAttachTo(Entity parent, Transform attachPoint, object userData) { } // 附加到父实体 protected virtual void OnDetachFrom(Entity parent, object userData) { } // 从父实体解除 protected virtual void OnAttached(Entity child, Transform attachPoint, object userData) { } // 子实体附加到自己 protected virtual void OnDetached(Entity child, object userData) { } // 子实体从自己解除
优先级:80 | 三通道架构
| 通道 | 协议 | 用途 | 特点 |
|---|---|---|---|
| TcpChannel | TCP | 登录、背包、战斗指令等可靠逻辑 | 心跳检测、自动重连、粘包处理 |
| UdpChannel | UDP | 移动同步、战斗状态同步 | 低延迟、无连接 |
| WebSocketChannel | WebSocket | 排行榜、社交功能 | 浏览器兼容 |
[Length: 4字节, 小端序] + [MessageId: 2字节, 小端序] + [Body: 变长, Protobuf序列化]
- HeaderSize = 6 字节
- 最大消息长度 = 64KB
主线程(Unity Update)
├── UpdateHeartbeat() → 心跳检测
├── UpdateReconnect() → 重连逻辑
└── UpdateReceiveQueue() → 处理接收队列中的消息
发送线程(后台)
└── SendLoop()
├── _sendEvent.WaitOne() → 信号量等待(无数据时阻塞,不消耗CPU)
└── _sendQueue.Dequeue() → 从队列取数据发送
接收线程(后台)
└── ReceiveLoop()
├── _socket.Receive() → 阻塞接收数据
├── 追加到 _dataBuffer → 数据缓冲区
├── ProcessReceivedData() → 粘包处理
└── 解码后放入 _receiveQueue → 主线程消费
while (缓冲区数据 >= HeaderSize) { 读取 bodyLength(前4字节) if (缓冲区数据 < HeaderSize + bodyLength) break; // 数据不完整,等待更多数据 提取完整消息 → 解码 → 放入接收队列 移除已处理的数据(Array.Copy 前移) }
- 初始大小:8KB
- 最大大小:1MB
- 扩容策略:翻倍增长(8KB → 16KB → 32KB → ...)
- 缩容条件:缓冲区 > 初始大小×4 且 数据量 < 缓冲区的 1/4
- 心跳间隔:5秒发送一次心跳包(MessageId=0 的空包)
- 心跳超时:15秒未收到响应算一次超时
- 最大超时次数:3次 → 断开连接
- 优化:发送任何消息都重置心跳计时器(避免无谓的心跳包)
- 优化:收到任何消息都重置心跳接收计时器
- 最大重连次数:5次
- 重连间隔:3秒
- 触发条件:非主动断开 + 启用自动重连
- 重连流程:通知上层 → 等待间隔 → DoConnect() → 成功则重置计数,失败则继续尝试
- 主动断开(Disconnect)不触发重连
- 发送队列:lock(_sendLock) + AutoResetEvent 信号量
- 接收队列:lock(_receiveLock)
- 运行标志:volatile bool _isRunning
优先级:90
| 层级 | 类 | 用途 | 存储结构 |
|---|---|---|---|
| 重量级对象池 | ObjectPool | UI界面、实体、音频等 GameObject | LinkedList |
| 轻量级引用池 | ReferencePool | 事件参数、网络包等纯C#对象 | Dictionary<Type, Queue> |
// 获取对象(Spawn) T obj = objectPool.Spawn(name); // 遍历链表,找到名称匹配且未使用(或允许多次获取)的对象 // 找到则 SpawnCount++,返回对象 // 找不到则返回 null(由上层决定是否创建新实例)
// 归还对象(Unspawn) objectPool.Unspawn(target); // 遍历链表,找到 Target 匹配的对象 // SpawnCount--,触发 Release() 检查是否需要释放超量对象
// 自动释放 objectPool.Update(elapseSeconds, realElapseSeconds); // 累计时间 >= AutoReleaseInterval 时,释放超出容量的过期对象
- 计算过期参考时间 = 当前时间 - ExpireTime
- 遍历可释放对象(未使用的)
- 如果对象的 LastUseTime <= 过期参考时间 → 加入释放列表
- 释放数量达到 toReleaseCount 时停止
// 获取临时对象 GlobalEventArgs args = ReferencePool.Acquire();
// 使用完毕后归还 ReferencePool.Release(args); // 调用 args.Clear() 重置状态后放回池中
// 线程安全:内部使用 lock 同步
优先级:100 全局事件总线,用于模块间解耦通信。
// 订阅事件 FW.EventManager.Subscribe(eventId, handler);
// 发布事件(延迟模式 —— 放入队列,下一帧处理) FW.EventManager.Fire(sender, eventArgs);
// 发布事件(立即模式 —— 当场执行所有处理器) FW.EventManager.FireNow(sender, eventArgs);
// 取消订阅 FW.EventManager.Unsubscribe(eventId, handler);
- 事件处理器存储:Dictionary<int, EventHandler>(eventId → 多播委托)
- 延迟事件队列:Queue(线程安全,主线程 Update 时逐个处理)
- 事件参数通过 ReferencePool 池化,减少 GC
优先级:30
LoadScene(sceneID, sceneAssetName)
│
├── ① 卸载当前场景的 UI、实体、音频
├── ② 打开 Loading 界面
├── ③ 异步加载新场景(YooAsset)
├── ④ 清理旧场景资源(UnloadSceneAssetsAsync)
├── ⑤ 调用新场景的 OnPreload()(预加载场景资源)
├── ⑥ 调用新场景的 OnEnter()(进入场景逻辑)
└── ⑦ 关闭 Loading 界面
public abstract class SceneBase { public virtual async UniTask OnPreload() { } // 预加载资源 public virtual void OnEnter() { } // 进入场景 public virtual void OnUpdate(float elapseSeconds, float realElapseSeconds) { } // 每帧更新 public virtual void OnLeave() { } // 离开场景 }
优先级:60 泛型状态机,可用于游戏流程控制、AI 行为等。
// 创建状态机 IFsm fsm = FW.FsmManager.CreateFsm("GameFsm", owner, new IdleState(), new RunState(), new AttackState() );
// 启动状态机 fsm.Start();
- 状态数据存储:SetData(name, data) / GetData(name) —— 状态间共享数据
- 事件机制:FireEvent(sender, eventId) —— 状态内部可以触发事件
- 当前状态时间:自动记录当前状态已持续的时间
优先级:130 | 集成 Luban 管理由 Luban 工具生成的配置表数据。
- LoadAllDataTablesByTagAsync() → 从 YooAsset 加载所有配置表的字节数据(缓存到字典)
- LoadTable("tbentity") → 解析指定表的字节数据,创建表实例
- GetTable() → 获取已加载的表实例,查询数据
| 表名 | 类型 | 用途 |
|---|---|---|
| TbEntity | 实体表 | 实体配置(资源名、属性等) |
| TbLocalizationText | 本地化文本表 | 多语言文本(CN、EN) |
| TbMusic | 音乐表 | 背景音乐配置 |
| TbScene | 场景表 | 场景配置 |
| TbSound | 音效表 | 音效配置 |
| TbUISound | UI音效表 | UI交互音效 |
| TbMap | 地图表 | 地图资源和寻路数据 |
| TbRole | 角色表 | 角色资源配置 |
优先级:120 设计思路: 采用委托模式获取文本数据,不直接依赖具体的数据源,解耦了本地化系统和数据表系统。
// 设置支持的语言类型 FW.LocalizationManager.SetLanguageTypes(new string[] { "CN", "EN" });
// 设置数据获取委托(从 Luban 配置表读取) FW.LocalizationManager.SetLanguageData((id, language) => { TableLocalizationText text = FW.DataTableManager.GetTable()[id]; if (text == null) return null; return language switch { "CN" => text.CN, "EN" => text.EN, _ => text.CN }; });
// 获取本地化文本 string text = FW.LocalizationManager.GetText(textId);
// 切换语言(会触发事件通知所有绑定组件刷新) FW.LocalizationManager.SetLanguage("EN");
挂在 UI 文本上,配置 textId 后自动绑定,语言切换时自动刷新显示。
优先级:50
AudioManager
├── AudioGroup "Music" → 背景音乐(通常1个Agent)
│ └── AudioAgent → 封装 AudioSource
├── AudioGroup "Sound" → 游戏音效(多个Agent)
│ ├── AudioAgent
│ ├── AudioAgent
│ └── AudioAgent
└── AudioGroup "UISound" → UI音效(多个Agent)
├── AudioAgent
└── AudioAgent
// 播放音频(异步加载资源后播放) int? serialId = await FW.AudioManager.PlayAudio(assetName, "Music", priority, playParams);
// 控制播放 FW.AudioManager.PauseAudio(serialId); FW.AudioManager.ResumeAudio(serialId); FW.AudioManager.StopAudio(serialId);
// 组级控制 audioGroup.Mute = true; // 静音整个组 audioGroup.Volume = 0.5f; // 调整组音量
播放时遍历组内所有 Agent,优先选择空闲的;如果都在使用中,则替换优先级最低的。
优先级:85 基于 UnityWebRequest 封装的 HTTP 短连接客户端。
// GET 请求(泛型自动反序列化) HttpResponse resp = await FW.HttpManager.GetAsync(url);
// POST 请求(自动序列化请求体) HttpResponse resp = await FW.HttpManager.PostAsync(url, new { username, password });
// 文件下载(带进度回调) HttpResponse resp = await FW.HttpManager.DownloadAsync(url, headers, timeout, progress);
// 表单提交 HttpResponse resp = await FW.HttpManager.PostFormAsync(url, formData);
支持 Bearer Token 认证、自定义 Headers、超时配置、JSON 自动序列化/反序列化。
优先级:140 树形数据结构,类似文件系统路径,用于存储运行时全局数据。
// 路径式访问(支持 "."、"/"、"" 分隔符) FW.DataNodeManager.SetData("player/level", 10); FW.DataNodeManager.SetData("player/name", "Hero"); FW.DataNodeManager.SetData("game/score", 9999);
int level = FW.DataNodeManager.GetData("player/level");
// 数据树结构:
// Root
// ├── player
// │ ├── level = 10
// │ └── name = "Hero"
// └── game
// └── score = 9999
替代全局静态变量,提供结构化的运行时数据存储,方便模块间共享数据。
优先级:120 // 加载地图数据(JSON格式的网格数据) await FW.PathFindingManager.LoadMapAsync(mapJsonAssetPath);
// 网格坐标寻路 List path = FW.PathFindingManager.FindPath(startX, startY, endX, endY);
// 世界坐标寻路(自动转换) List path = FW.PathFindingManager.FindPath(startWorld, endWorld);
// 检查某个位置是否可行走 bool walkable = FW.PathFindingManager.IsWalkable(worldPosition);
支持多地图管理、对角线移动选项、网格坐标与世界坐标自动转换。
优先级:150 基于 PlayerPrefs 的持久化配置管理。
// 游戏速度控制 FW.SettingManager.SetGameSpeed(2.0f); // 2倍速 FW.SettingManager.PauseGame(); // 暂停(Time.timeScale = 0) FW.SettingManager.ResumeGame(); // 恢复
// 帧率设置 FW.SettingManager.SetFrameRate(60);
// 通用配置存储 FW.SettingManager.SetString("lastLogin", "2026-02-06"); FW.SettingManager.SetObject("userSettings", settingsObj); // JSON序列化存储 T obj = FW.SettingManager.GetObject("userSettings"); // JSON反序列化读取
// 条件编译,Release 版本自动移除日志代码 [Conditional("EnableLog")] public static void Info(string format, params object[] args);
[Conditional("EnableLog")] public static void Warn(string format, params object[] args);
[Conditional("EnableLog")] public static void Error(string format, params object[] args);
- 通过 [Conditional("EnableLog")] 实现零开销的日志移除(Release 版本不编译日志调用)
- 自动通过堆栈追踪获取调用者信息(类名、方法名)
- 支持多种日志处理器:ConsoleLogHandler(控制台)、FileLogHandler(文件)
两种单例基类,适配不同使用场景:
public abstract class MonoSingleton : MonoBehaviour where T : MonoSingleton { public static T Instance { get; } // 懒加载,自动创建 GameObject + DontDestroyOnLoad }
public abstract class ScriptSingleton where T : class, new() { public static T Instance { get; } // 懒加载 }
| 设计模式 | 应用位置 | 说明 |
|---|---|---|
| 门面模式 (Facade) | FW.cs | 统一入口,隐藏子系统复杂性 |
| 管理器模式 (Manager) | 所有 ManagerBase 子类 | 每个子系统一个管理器,职责单一 |
| 单例模式 (Singleton) | MonoSingleton、ScriptSingleton | 全局唯一实例 |
| 对象池模式 (Object Pool) | ObjectPool、ReferencePool | 减少 GC,复用对象 |
| 观察者模式 (Observer) | EventManager、EventPool | 全局事件订阅/发布,模块解耦 |
| 状态模式 (State) | Fsm、FsmState | 有限状态机,管理状态转换 |
| 策略模式 (Strategy) | NetworkChannelBase → TCP/UDP/WS | 同一接口,不同网络协议实现 |
| 模板方法 (Template Method) | UIForm、Entity、SceneBase | 基类定义流程骨架,子类重写具体步骤 |
| 工厂模式 (Factory) | FW.RegisterManager() | 通过反射创建管理器实例 |
| 组合模式 (Composite) | DataNode 树形结构 | 树形数据节点,路径式访问 |
| 生产者-消费者 | TcpChannel 收发队列 | 接收线程生产数据,主线程消费处理 |
1导入XHFrameworkClient之后
2在需要使用自动绑定工具的对象上面挂载组件,并指定需要写入的脚本

3这个对象包括子物体右边会有➕号

4点击加号会出现这个对象身上所有组件,选择组件就会自动保存你需要的组件,并显示在+号前面

5在显示所绑定的组件右键也可以删除和替换

6绑定组件上面也会显示你所绑定的组件和对象,点击生成会自动生成,脚本的partial脚本

7这个对象脚本就可以直接.出来对象,例如图上的LoadingForm._Scrollbar_LoadingScroll进行使用
1导入XHFrameworkClient之后,选择游戏工具!

2在配置工具可以设置luban导入路径和导出路径,点击导出即可

3 网络模块proto文件也是如此!

1导入XHFrameworkClient之后
2在地形预制体挂载MapPathFindingEditor组件

3点击scene视图画板

4选择画板绿色

5在地形 你想设置边界的矩形区域 任意两个对象填充绿色,即设置寻路区域边界

6再次选择红色方块画笔,在scene视图画不可行走区域

7设置地图信息和导出路径,点击生成json,就会将地图信息和区域大小,和每个方块信息导入json,

1导入XHFrameworkClient之后,选择游戏工具

2选择打包设置

3需要手动修改代码内资源服务器地址
启动请求时候资源服务器地址
打包工具时候上传服务器目录,本项目做了一个本地的服务器,详情可查看 https://gitee.com/xframework886/xframework-server

4配置构建信息
5本工具配置之后,全为自动化,等待出包或者热更完成即可
另外还有基于GAS模式的Unity技能框架与节点节能编辑器,非常值得一看
XHFrameworkSkill:https://github.com/XH-Unity/XHFrameworkSkill
