# FusionFrameworks
**Repository Path**: yajink/FusionFrameworks
## Basic Information
- **Project Name**: FusionFrameworks
- **Description**: Unity Frameworks
- **Primary Language**: C#
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 1
- **Forks**: 1
- **Created**: 2022-12-05
- **Last Updated**: 2025-09-24
## Categories & Tags
**Categories**: Uncategorized
**Tags**: Unity, Csharp, Framework
## README
# FusionFrameworks
Unity客户端框架,包含资源管理、音频管理、场景管理、UI管理、Excel工具、打包工具、热更新、网络等。
## 使用插件
1. Protobuf v23.3
2. ILRuntime 2.1.0
3. EPPlus
## 安装
1. **Window -> Package Manager -> + -> Add package from git URL...**
2. 输入`https://gitee.com/yajink/FusionFrameworks.git?path=Assets/[模块包名]#v[MAJOR.MINOR.PATCH]`, 点击Add
> [模块包名]
> 1. com.fusion.utilities 工具模块(*必选)
> 2. com.fusion.async 异步处理模块(*必选)
> 3. com.fusion.frameworks 主框架(*必选)
> * com.fusion.protobuf Protobuf模块(可选)
> * com.fusion.net 网络模块(可选)
> * com.fusion.hotfix 热更模块(可选)由于热更模块中已经对网络模块做了配置,因此需要先导入网络模块。
## 实例
### 测试工程
https://gitee.com/yajink/fusion-test
### 游戏示例
https://gitee.com/yajink/cyber-zero
## 文档
### 一、资源管理
#### 资源路径
所有需要打包为AssetBundle(以下简称AB)的资源都需要存放在 **Assets/GameAssets/[xxx]** 文件夹下,可以根据自己的习惯为不同的资源划分多个子文件夹,但根目录必须创建一个 **BuildSetting** 配置文件,并且GameAssets下不能放资源。
> BuildSetting 可以通过 **Assets/Create/FusionConfig/Build Setting** 来创建
***注意:相同目录下资源不能重名,后缀名不同也不行。例如:a.jpg 和 a.mat 不能存放在相同文件夹中。**
* **BuildSetting参数说明**
| 参数 | 说明 |
| :---: | --- |
| Build Mode | *打包模式*
1. Debug 调试版本
2. Release 正式版本 |
| Compress Type | *压缩方式*
1. LZMA
2. Uncompress 不压缩
3. LZ4 |
| Build Target Type | *平台*
1. Use Current Target 使用当前平台
2. Android
3. Standalone Windows
4. Standalone Windows 64
* 暂时不支持其他平台 |
| Init Scene | *初始场景*
初始场景文件会由Unity打入单独的AssetBundle中,因此不需要放在GameAssets下 |
| Version | *版本号*
在打完AssetBundle后,会与老版本的资源进行对比,若Large Middle Small相同,并且Resource大于老版本,就会生成一个对应老版本的Patch文件用于热更新 |
#### 资源AssetBundle名称规则
AB名称会在打AssetBundle时自动设置。
为某个资源设置AB名称时,会在当前文件夹中查找 **BuildProperty** 配置文件,若找不到,则递归寻找父文件夹。
若到GameAssets文件夹还未找到,则使用默认 **BuildProperty** 配置。
> BuildProperty 可以通过 **Assets/Create/FusionConfig/Build Property** 来创建
* **BuildProperty参数说明**
| 参数 | 说明 |
| :---: | --- |
| Type | *AB命名方式*
1. None 名称为null
2. File 用文件名命名
3. Folder 用所在文件夹名称命名 |
| Compress *Type* | *压缩方式*
* 若压缩方式与Build Setting配置不同,则该资源不会被记录在依赖资源文件中,只能作为主要资源加载
1. LZMA
2. Uncompress 不压缩
3. LZ4
4. Use Build Setting 使用Build Setting中的压缩方式 |
若需要将Sprite打入图集,可以通过 **AtlasProperty** 配置文件,该配置文件的查找方式与 **BuildProperty** 相同。
只会将符合配置条件的Sprite打入图集,其余资源还是按照 **BuildProperty** 来设置。
> AtlasProperty 可以通过 **Assets/Create/FusionConfig/Atlas Property** 来创建
* **AtlasProperty参数说明**
| 参数 | 说明 |
| :---: | --- |
| Pack Unit | *图集粒度*
0 文件夹中所有符合条件的Sprite打入一张图集
-1 不打图集
[n] 符合条件的n张Sprite打入一张图集 |
| Ignore Size | *过滤Sprite分辨率*
X Sprite的宽
Y Sprite的高
大于这个分辨率的Sprite不会被打入图集 |
#### AssetBundle打包
将资源放入指定文件夹并且完成上述配置后,就可以通过 **Build/BuildAssets** 菜单选项进行打包。AssetBundle会被入 **StreamingAssets/ManagedAssets** 文件夹中。
可以在 **项目根目录/FusionTemp** 文件夹下找到当前版本的资源、老版本资源MD5以及热更Patchs等。
* **打包选项**
| 操作 | 说明 |
| :---: | --- |
| **Build/BuildAssets** | 打AssetsBundle |
| **Build/BuildPlayer** | 直接打可执行文件 |
| **Build/BuildDynamic** | 打出热更文件 |
| **Build/Build** | 打AssetsBundle,并且打出可执行文件 |
| **AssetsManager/ClearAssetBundleName** | 清除AssetBundle名称 |
| **AssetsManager/CopyAssetsToStreamingAssets** | 将FusionTemp下的资源拷贝到StreamingAssets下 |
| **AssetsManager/SwichEditorAssetLoadType** | 切换Editor下资源加载方式
AssetBundle
AssetDatabase |
| **AssetsManager/Build** | 打AssetsBundle,但不会拷贝到StreamingAssets下 |
#### 资源加载与销毁
可以通过 **AssetsManager** 或 **AssetsUtility** 来对资源进行加载和销毁。
> 资源应的AssetBundle拥有两个引用值:**非持久引用**、**持久引用**。
> 当调用资源加载方法时,其对应的AssetBundle的引用值(persistentAsset=false为**非持久引用**,true为**持久引用**)会加1。
> 当调用资源销毁方法时,其对应的AssetBundle的引用值(persistentAsset=false为**非持久引用**,true为**持久引用**)会减1。
> 当AssetBundle **非持久引用** 和 **持久引用** 和(后续使用引用值表示它们的和)为0时,AssetBundle会被销毁。
> 切换场景时,**非持久引用** 会被清零。
> 默认加载资源引用是 **非持久引用**。
* **同步加载**
```c#
Sprite sprite = AssetsManager.Instance.Load("Sprites/hearts");
```
> persistentAsset 传入 true,可将资源标记为持久资源。
* **异步加载资源**
```c#
AssetsManager.Instance.LoadAsync("Sprites/hearts", delegate (Sprite sprite)
{
//在回调中对加载的资源进行处理
});
```
> persistentAsset 传入 true,可将资源标记为持久资源。
* **资源销毁资源**
```c#
AssetsUtility.Release("Sprites/hearts");
```
> 引用值为0时,为防止AssetBundle销毁后又立刻被加载,会有一个5秒的延迟。
> persistentAsset 传入 true,可销毁持久资源。
```c#
AssetsUtility.ReleaseImmediate("Sprites/hearts");
```
> 引用值为0时,AssetBundle立刻被销毁。
> persistentAsset 传入 true,可销毁持久资源。
* **同步加载预制体**
```c#
GameObject go = AssetsUtility.CreateGameObject("Prefabs/Cube");
```
* **异步加载预制体**
```c#
AssetsUtility.CreateGameObjectAsync("Prefabs/Cube", finishCallback: delegate (GameObject go)
{
//在回调中可以处理加载的对象
});
```
* **销毁预制体**
```c#
AssetsUtility.Release(go);
```
> 引用值为0时,为防止AssetBundle销毁后又立刻被加载,会有一个5秒的延迟。
```c#
AssetsUtility.ReleaseImmediate(go);
```
> 引用值为0时,AssetBundle立刻被销毁。
* **其他资源操作**
```c#
AssetsUtility.SetSpriteOfImage(gameObject, "Sprites/hearts");
```
> 为Image设置图片。
> 当Image对象或父对象被销毁时,资源对应的AssetBundle的非持久引用会减去1。
```c#
AssetsUtility.SetAudioSourceClip(audioSource, "Audios/1");
```
> 为AudioSource设置图片。
> 当AudioSource对象或父对象被销毁时,资源对应的AssetBundle的非持久引用会减去1。
### 二、音频管理
音频播放需要 **AudioPlayer** 对象
#### 音频操作
```c#
AudioPlayer audioPlayer = new AudioPlayer();
```
> 构造方法中可传入gameObject,这样可以让AudioPlayer变为3D播放。
> 构造方法中可传入persistent,标记该音频播放器是持久的。持久音频切换场景不会被销毁,只有在切换音频时,会将上一个音频销毁。
* **淡入淡出**
```c#
audioPlayer.FadeInSetter(1.0f);
audioPlayer.FadeOutSetter(1.0f);
```
> duration 淡入淡出的时间
* **循环**
```c#
audioPlayer.LoopSetter(true);
```
* **音量**
```c#
audioPlayer.VolumeSetter(0.5f);
```
> 参数为[0.0, 1.0] 区间的浮点数
* **播放**
```c#
audioPlayer.Play("Audios/1");
```
* **停止**
```c#
audioPlayer.Stop();
```
* **暂停**
```c#
audioPlayer.Pause();
```
* **销毁**
```c#
audioPlayer.Release();
```
#### 音频标签
为音频播放器设置标签,可以批量修改某个标签下的所有音频播放器的参数。
* **设置标签**
```c#
audioPlayer.TagSetter("BGM");
```
* **设置标签音量**
```c#
AudioManager.Instance.SetTagVolume("BGM", 0.5f);
```
### 三、场景管理
#### 场景加载
* **同步加载**
```c#
ScenesManager.Instance.Load("Scenes/First");
```
> LoadSceneMode.Single 加载单个场景 LoadSceneMode.Additive 额外场景
> clearFlag 是否清理资源
* **异步加载**
```c#
ScenesManager.Instance.LoadAsync("Scenes/First");
```
> LoadSceneMode.Single 加载单个场景 LoadSceneMode.Additive 额外场景
> startCallback 回调方法参数为 AsyncOperation
> finishCallback 加载结束回调
> clearFlag 是否清理资源
#### 异步加载任务
异步加载任务是通过LoadAsyncTask类来加载场景,这种加载方式可以加载一个Single场景和多个Addtion场景并且自动合并Single与Addition的加载进度。除此之外,还提供了场景数据的保存于加载功能。
* **创建LoadAsyncTask**
```c#
ScenesManager.LoadAsyncTask loadAsyncTask = new ScenesManager.LoadAsyncTask("Scenes/First");
```
* **添加额外场景**
```c#
loadAsyncTask.AddAdditive("Scenes/Second");
```
* **回调方法**
```c#
loadAsyncTask.updateCallback = delegate (float progress)
{
//在此处理进度变更逻辑
};
```
```c#
loadAsyncTask.finishCallback = delegate ()
{
//在此处理加载完成逻辑
};
```
* **添加额外场景**
```c#
loadAsyncTask.AddAdditive("Scenes/Second");
```
* **添加场景数据处理器**
```c#
loadAsyncTask.AddSceneDataHandler(new SceneUIHandler());
```
> SceneUIHandler 可以保存旧场景的UI栈。
> 当从场景A跳转到场景B时,SceneUIHandler会保存场景A的UI栈。下一次跳转回场景A时,会自动加载SceneUIHandler中的UI栈。
>
> 自定义SceneHandler
> * 新建一个类,实现SceneDataHandler接口。
> * 在接口Save中写保存数据的逻辑。
> * 在Load中写加载数据的逻辑。
* **开始异步任务**
```c#
ScenesManager.LoadAsyncOperation loadAsyncOperation = loadAsyncTask.Schedule();
```
> loadAsyncOperation 中也可以获取到进度Progress,以及是否完成IsDone。
### 四、UI管理
使用UI管理功能之前,需要将Prefab **Packages/com.fusion.frameworks/Runtime/Prefabs/UI/UI** 拖入初始场景中。
**可以修改UI Prefab的属性,但不能更改子节点的层级关系。**
**UI支持热更,详情在热更部分**
#### 创建UI页面
一个UI Prefab需要对应一个UI脚本。
UI Prefab所在的相对路径就是创建UI页面的路径。
UI脚本的命名空间+类名,必须与UI Prefab路径对应。
以 **Prefabs/UI/Page1** 为例:
```c#
using Fusion.Frameworks.UI;
namespace Prefabs.UI
{
public class Page1 : UIObject
{
public Page1()
{
}
public Page1(UIData data) : base(data)
{
}
public override void Init()
{
base.Init();
}
public override void Update()
{
base.Update();
}
public override void OnFinished()
{
base.OnFinished();
}
public override void OnDestroy()
{
base.OnDestroy();
}
}
}
```
> 必须有一个默认构造函数,反射需要调用。
> 生命周期函数
> Init 仅在UI创建的时候执行一次。
> Update 创建UI时,会执行一次Update。当UI对象的updateLastUI属性为true时,Finish会自动调用上一个页面的Update方法进行页面更新。
> OnFinished 当调用UI的Finish方法时,会触发此回调。
> OnDestroy 当页面被销毁时,会触发此回调。
* **同步创建UI**
```c#
UIManager.Instance.Launch("Prefabs/UI/Page1");
```
>
* **异步创建UI**
```c#
UIManager.Instance.LaunchAsync("Prefabs/UI/Page1");
```
#### 数据传递
向UI页面传递数据,需要一个数据类。
这个类继承自UIData
```c#
public class PageData : UIData
{
// 可以添加自定义的变量,例如下面的text变量。
public string text;
}
```
```c#
PageData pageData = new PageData();
pageData.text = "Passed Value";
UIManager.Instance.LaunchAsync("Prefabs/UI/Page1", pageData);
```
可以在UI脚本的有参构造方法中初始化数据
```c#
PageData pageData;
public Page1(UIData data) : base(data)
{
pageData = (PageData)data;
}
```
#### 控件设置
在 **Init** 方法中获取控件。
```c#
TextMeshProUGUI text;
Image image;
Button jumpToBtn;
Button closeBtn;
public override void Init()
{
base.Init();
text = Utility.Find(gameObject, "Text");
image = Utility.Find(gameObject, "Image");
jumpToBtn = Utility.Find