16 KiB
16 KiB
StrayFog 框架业务开发指南
一、开发前准备
1.1 核心概念理解
1.1.1 框架层级关系
┌─────────────────────────────────────────────────────────────┐
│ 开发层级视图 │
├─────────────────────────────────────────────────────────────┤
│ 业务层 (你开发的代码) │
│ ├── UI界面、业务逻辑、游戏数据 │
│ │ │
│ │ ┌───────────────────────────────────────────────────┐ │
│ │ │ 核心库 (只读,框架团队维护) │ │
│ │ │ ├── Core: 模拟行为、全局数据 │ │
│ │ │ ├── HF: 资源管理、事件系统、相机管理 │ │
│ │ │ └── General: 状态机、工具类 │ │
│ │ └───────────────────────────────────────────────────┘ │
│ │ │
│ └─────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
1.1.2 核心库访问原则
| 原则 | 说明 |
|---|---|
| 只读访问 | 核心库代码只可读取,不可修改 |
| 接口优先 | 通过接口访问服务,而非直接实例化实现类 |
| 继承扩展 | 通过继承抽象类实现自定义逻辑 |
| 依赖注入 | 通过管理器获取实例,而非硬编码 |
二、业务代码结构
2.1 目录组织规范
Assets/Game/GameHFScripte/GameFunction/
├── Event/ # 消息处理
│ ├── ServerToClient/ # 服务器到客户端消息
│ ├── ClientToClient/ # 客户端内部消息
│ └── Handle/ # 消息处理器
├── GameRoot/ # 框架调用入口
│ ├── HFGameStart.cs # 热更新进入入口
│ ├── HFFunCatalogue.cs # 框架统一调用入口
│ ├── HFFunCatalogue_Function.cs # 功能调用方法
│ └── ...
├── HFDownLoadSubPackage/ # 分包下载
│ ├── HFSubPackageManager.cs # 分包管理器
│ ├── HFGameStartAssetsCheckManager.cs # 资源检查
│ └── ...
├── HFExtends/ # Class扩展方法
│ ├── UI/ # UI扩展
│ ├── Material/ # 材质扩展
│ ├── String/ # 字符串扩展
│ └── ...
├── Logic/ # 游戏主要业务逻辑(存放各功能Manager)
│ ├── User/ # 用户相关
│ ├── Login/ # 登录系统
│ ├── Fight/ # 战斗系统
│ ├── CardDeck/ # 卡组系统
│ ├── Bag/ # 背包系统
│ └── ...
├── UIWindows/ # UI窗口业务逻辑
│ ├── Login/ # 登录窗口
│ ├── Lobby/ # 大厅窗口
│ ├── Fight/ # 战斗窗口
│ ├── Shop/ # 商店窗口
│ └── ...
├── GameEntity/ # 游戏实体
│ ├── Entity/ # 实体定义
│ ├── EntityPool/ # 实体对象池
│ └── ...
├── SoundManagerPro/ # 音效管理
├── SceneManager/ # 场景管理
├── SDK/ # SDK集成
└── MonoCompent/ # Mono组件
2.2 文件命名规范
| 文件类型 | 命名规则 | 示例 |
|---|---|---|
| 窗口类 | XXXWindow.cs |
LoginWindow.cs |
| 组件类 | XXXComponent.cs |
ItemCellComponent.cs |
| 管理器类 | XXXManager.cs |
UIManager.cs |
| 数据类 | XXXData.cs |
PlayerData.cs |
| 配置类 | XXXConfig.cs |
SkillConfig.cs |
三、核心库使用指南
3.1 对象池使用
3.1.1 GameObject对象池
public class BulletManager : MonoBehaviour
{
[SerializeField] private GameObject bulletPrefab;
private HFObjectMemPool m_BulletPool;
void Awake()
{
// 创建对象池
m_BulletPool = new HFObjectMemPool(bulletPrefab, transform);
}
public void Fire(Vector3 position, Quaternion rotation)
{
bool isNew;
GameObject bullet = m_BulletPool.GetItem(out isNew);
bullet.transform.position = position;
bullet.transform.rotation = rotation;
// 如果是新创建的对象,初始化组件
if (isNew)
{
bullet.GetComponent<BulletComponent>().Initialize();
}
}
public void RecycleBullet(GameObject bullet)
{
m_BulletPool.GiveBack(bullet);
}
void OnDestroy()
{
// 清理对象池
m_BulletPool.Recycle();
}
}
3.1.2 脚本对象池
public class EventArgPool : MonoBehaviour
{
private HFScriptMemPool<GameEventArgs> m_ArgPool;
void Awake()
{
m_ArgPool = new HFScriptMemPool<GameEventArgs>();
}
public GameEventArgs GetEventArgs(GameEventId eventId)
{
bool isNew;
GameEventArgs arg = m_ArgPool.GetItem(out isNew);
arg.eventId = eventId;
return arg;
}
public void RecycleEventArgs(GameEventArgs arg)
{
m_ArgPool.GiveBack(arg);
}
}
3.2 事件系统使用
3.2.1 定义事件枚举和参数
// 事件ID枚举
public enum GameEventId
{
PlayerLevelUp,
EnemyKilled,
GoldChanged
}
// 事件参数基类
public class GameEventArgs : IHFEventArg<GameEventId>, IHFRecycle
{
public GameEventId eventId { get; set; }
public void Recycle()
{
// 重置状态
eventId = default;
}
}
// 具体事件参数
public class PlayerLevelUpEventArgs : GameEventArgs
{
public int playerId;
public int oldLevel;
public int newLevel;
}
3.2.2 注册和触发事件
事件系统分为两类:
- STCEvent:Server To Client(服务器到客户端消息)
- CTCEvent:Client To Client(客户端内部消息)
注册事件监听:
/// <summary>
/// 卡组窗口
/// </summary>
[HFAssetBundlePath(enHFLanguageRootFolder.ASSETS_GAME_GAMEHFRESOURCE, "UIWindows/CardDeck/CardDeckWindow.prefab")]
[HFUIWindowLayer(enHFUICanvasLayer.UIWindow, enHFUIWindowLayer.Dynamic, isIgnoreCloseByESC = false)]
public class CardDeckWindow : AbsHFUIWindow
{
/// <summary>
/// 初始化(仅调用一次)
/// </summary>
protected override void OnRunAwake()
{
base.OnRunAwake();
// 初始化UI组件引用
// 绑定事件监听(如按钮点击等)
}
/// <summary>
/// 打开窗口(每次打开调用)
/// </summary>
protected override void OnOpen(Action _onOpenComplete)
{
base.OnOpen(_onOpenComplete);
// 注册客户端内部消息监听(CTCEvent)
HFFunCatalogue.Event.CTCEvent.AddListener<HFEvent_CTC_CardUpdate>(enHFCTCEvent.CardUpdate, OnCardUpdate);
}
/// <summary>
/// 关闭窗口
/// </summary>
protected override void OnClose(Action _onCloseComplete)
{
base.OnClose(_onCloseComplete);
// 取消客户端内部消息监听
HFFunCatalogue.Event.CTCEvent.RemoveListener<HFEvent_CTC_CardUpdate>(enHFCTCEvent.CardUpdate, OnCardUpdate);
}
void OnCardUpdate(HFEventArgBase arg)
{
HFEvent_CTC_CardUpdate cardArg = arg as HFEvent_CTC_CardUpdate;
// 更新卡组UI显示
}
}
注意:UI窗口中不监听服务器事件(STCEvent),服务器事件应在Logic层的Manager中监听。
Manager类型定义:
Manager需要继承AbsHFSingleMonoBehaviour或AbsHFSingleRunTime:
| 类型 | 说明 | 适用场景 |
|---|---|---|
AbsHFSingleMonoBehaviour |
生成GameObject,可注册MonoBehaviour事件 | 需要Update/FixedUpdate等生命周期 |
AbsHFSingleRunTime |
纯内存单例,无GameObject | 不需要生命周期事件 |
示例1:使用AbsHFSingleMonoBehaviour(需要Update)
public class PlayerManager : AbsHFSingleMonoBehaviour<PlayerManager>
{
/// <summary>
/// 注册模拟Behaviour事件
/// 通过此属性声明需要监听的事件
/// </summary>
protected override int[] simulateBehaviourEvents => new int[]
{
enHFSimulateBehaviourEvent.Mono_Update,
enHFSimulateBehaviourEvent.Mono_FixedUpdate
};
/// <summary>
/// 单例创建时调用(仅一次)
/// </summary>
protected override void OnAfterCreateInstance()
{
base.OnAfterCreateInstance();
// 初始化逻辑
RegisterServerEvents();
}
/// <summary>
/// 模拟Update事件(通过simulateBehaviourEvents注册后自动调用)
/// 注:这是封装后的事件,非Unity原生MonoBehaviour.Update
/// </summary>
protected override void OnRunUpdate()
{
// 每帧更新逻辑
}
/// <summary>
/// 模拟FixedUpdate事件
/// </summary>
protected override void OnRunFixedUpdate()
{
// 物理更新逻辑
}
/// <summary>
/// 注册服务器事件监听
/// </summary>
void RegisterServerEvents()
{
HFFunCatalogue.Event.STCEvent.AddListener<HFEvent_STC_PlayerInfo>(enHFSTCEvent.PlayerInfo, OnPlayerInfo);
}
void OnPlayerInfo(HFEventArgBase arg)
{
HFEvent_STC_PlayerInfo info = arg as HFEvent_STC_PlayerInfo;
// 处理服务器返回的玩家信息
// 触发客户端事件通知UI更新
HFEvent_CTC_PlayerLevelUp evt = HFFunCatalogue.New<HFEvent_CTC_PlayerLevelUp>();
evt.playerId = info.playerId;
evt.newLevel = info.level;
HFFunCatalogue.Event.CTCEvent.Dispatch(evt);
}
}
示例2:使用AbsHFSingleRunTime(纯逻辑)
public class ConfigManager : AbsHFSingleRunTime<ConfigManager>
{
/// <summary>
/// 单例创建时调用(仅一次)
/// </summary>
protected override void OnAfterCreateInstance()
{
base.OnAfterCreateInstance();
// 加载配置表
LoadConfigTables();
}
void LoadConfigTables()
{
// 加载配置数据
}
}
3.3 资源加载使用
3.3.1 加载AssetBundle资源
public class ResourceLoader : MonoBehaviour
{
public void LoadPlayerModel(int resId, Action<GameObject> onLoaded)
{
// 通过HFFunCatalogue统一入口加载资源
// resId: 从Res配置表中读取的资源ID
HFFunCatalogue.Asset.LoadAsset(resId, (res, obj) =>
{
if (obj != null)
{
GameObject model = res.GetAsset<GameObject>();
onLoaded?.Invoke(model);
}
else
{
Debug.LogError($"加载失败: resId={resId}");
}
});
}
}
实体资源加载示例:
// 在Entity中加载资源
HFFunCatalogue.Asset.LoadAsset(data.EntityRes.Id, (res, obj) => {
if (!entity.isDeath)
{
var Boddy = res.GetAsset<GameObject>();
data.SetBoddy(Boddy);
}
});
3.4 相机管理使用
3.4.1 创建自定义相机
public class UIOverlayCamera : AbsHFCameraItem
{
[SerializeField] private Camera uiCamera;
[SerializeField] private int weight = 10;
public override Camera CameraItem => uiCamera;
public override int Weight => weight;
protected override void OnInitialize()
{
base.OnInitialize();
// 自定义初始化逻辑
uiCamera.clearFlags = CameraClearFlags.Depth;
uiCamera.depth = 100;
}
}
3.4.2 管理相机堆栈
public class CameraController : MonoBehaviour
{
void Start()
{
// 获取相机管理器
HFCameraManager cameraMgr = HFCameraManager.Instance;
// 添加自定义相机
UIOverlayCamera uiCamera = GetComponent<UIOverlayCamera>();
cameraMgr.AddCamera(uiCamera);
// 获取主相机
Camera mainCam = cameraMgr.mainCamera.MainCamera;
}
void OnDestroy()
{
UIOverlayCamera uiCamera = GetComponent<UIOverlayCamera>();
HFCameraManager.Instance.RemoveCamera(uiCamera);
}
}
四、开发流程
4.1 需求分析
- 明确需求:理解业务需求,确定需要实现的功能
- 评估复杂度:判断是否需要核心库支持或扩展
- 设计方案:规划代码结构和调用关系
4.2 代码编写
- 创建目录:在
GameBusiness下创建对应模块目录 - 编写代码:遵循编码规范,使用核心库提供的API
- 测试验证:在Unity中测试功能正确性
4.3 代码审查
- 自我检查:检查是否符合规范,是否有潜在问题
- 团队审查:提交代码进行团队审查
- 修复问题:根据审查意见修改代码
4.4 集成测试
- 模块测试:测试单个模块功能
- 集成测试:测试模块间交互
- 回归测试:确保不影响现有功能
五、最佳实践
5.1 性能优化
5.1.1 对象池使用
- 频繁创建销毁的对象必须使用对象池
- 合理设置对象池初始容量
- 定期清理空闲对象避免内存泄漏
5.1.2 资源管理
- 及时释放不再使用的资源
- 使用异步加载避免卡顿
- 合理使用资源缓存
5.2 代码组织
5.2.1 单一职责
- 每个类只负责一个功能
- 避免庞大的God类
5.2.2 依赖管理
- 通过管理器获取依赖,而非硬编码
- 使用接口解耦依赖关系
5.3 错误处理
5.3.1 异常捕获
- 在关键路径添加异常处理
- 记录错误日志便于排查
5.3.2 防御性编程
- 检查参数合法性
- 处理空引用情况
六、常见问题
6.1 如何扩展核心库功能?
通过继承抽象类或实现接口来扩展,不要直接修改核心库代码。
6.2 核心库有Bug怎么办?
提交Issue到框架团队,由框架团队修复并发布新版本。
6.3 如何获取核心库的最新版本?
关注内部通知,定期更新核心库引用。
6.4 如何调试核心库代码?
可以设置断点调试,但不允许修改代码。
附录
A. 常用核心库API
| 类别 | 管理器 | 常用方法 |
|---|---|---|
| 对象池 | HFObjectMemPool |
GetItem(), GiveBack() |
| 事件 | IHFEventHandle |
AddListener(), Dispatch() |
| 资源 | HFABMgr |
OnStartLoad() |
| 相机 | HFCameraManager |
AddCamera(), GetCamera() |
B. 核心库只读目录
Assets/StrayFog/Core/
Assets/Game/GameHFScripte/CopyToHF/
Assets/Game/GameGeneralScripte/
版本: v1.0
生效日期: 2024年
适用范围: OnlineGame项目业务开发人员