Files
UnityAI/业务开发指南.md

16 KiB
Raw Blame History

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 注册和触发事件

事件系统分为两类

  • STCEventServer To Client服务器到客户端消息
  • CTCEventClient 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需要继承AbsHFSingleMonoBehaviourAbsHFSingleRunTime

类型 说明 适用场景
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 需求分析

  1. 明确需求:理解业务需求,确定需要实现的功能
  2. 评估复杂度:判断是否需要核心库支持或扩展
  3. 设计方案:规划代码结构和调用关系

4.2 代码编写

  1. 创建目录:在GameBusiness下创建对应模块目录
  2. 编写代码遵循编码规范使用核心库提供的API
  3. 测试验证在Unity中测试功能正确性

4.3 代码审查

  1. 自我检查:检查是否符合规范,是否有潜在问题
  2. 团队审查:提交代码进行团队审查
  3. 修复问题:根据审查意见修改代码

4.4 集成测试

  1. 模块测试:测试单个模块功能
  2. 集成测试:测试模块间交互
  3. 回归测试:确保不影响现有功能

五、最佳实践

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项目业务开发人员