GensouFramework开发记录-Unity资源加载器
1105
自上次完成Genscript的基础解释器并搭建GitHub仓库后,已经过去了两周。
这两周,我在专注开发UI管理器的同时,明确了框架的定位。
框架定位
Gensou视觉小说框架是一个轻量级、简单、开源的视觉小说框架,支持Unity和Godot,旨在帮助用户快速构建视觉小说原型。用户可以在基础框架上进行扩展,无论是直接修改源码,还是使用可能推出的插件系统。
因此,Gensou视觉小说框架的完整版本只具有以下能够完整地构建一个基础的视觉小说的功能:
- UI管理
- 存读档
- 控制音频播放
- 背景与立绘切换
- 创建对话与剧情分支选项
- 插件系统(可能提供)
发布完整版本后,很可能不再添加新功能,但会持续进行维护(因为我之后要去学美术)
所以,Live2D支持、UI动效、视频播放等拓展功能,就看大家的啦~
开发记录
在开发功能时,我先针对Unity平台进行开发,再开发Godot平台,因为这两者的使用难度差异较大。
Unity是一个相对较难上手的游戏引擎,许多框架的基础功能需要额外开发。而Godot则更容易上手。因此,框架可能会针对这两个平台有不同的衍生系统。
比如这次要说的,针对Unity平台所开发的资源加载器在Godot平台上可能就不需要。
我为什么要针对Unity开发资源加载器呢?
因为两个引擎在加载资源的方式上有很大的不同:
对于Unity,开发者通常将明确且不会重复引用的资源拖拽到挂载在游戏对象的脚本中,以引用/加载该资源。
对于Godot,开发者一般通过代码来引用/加载资源,无论是明确的还是需要动态加载的。
var image = preload("res://image.png") # GDScript
Texture2D texture = ResourceLoader.Load<Texture2D>("res://image.png"); // C#
在实际开发中,UI、背景、立绘等资源往往需要动态切换,因此在Unity中需要专门写封装方法来实现动态切换资源。
当然,Unity也有动态切换资源的方法,但它的局限性很大,尤其是只能加载Asset/Resources
文件夹下的资源:
Resources.Load<T>(string path)
而为了让大家能够自由选择资源存放路径,我专门为Unity的两个不同的资源加载方式写了一个资源加载器
资源加载器
Unity常用的资源加载有两种,UnityEngine.Resources
和Addressables
,
前者是Unity原生支持,后者则需要安装Unity官方的扩展包,同时也是目前Unity官方所推荐的资源管理方式。
而我也为这两种资源加载方式封装了同样的方法
public static string GetResourcePath(string category, string name) // 根据加载方式生成完整的资源路径或地址
public static T GetLoadedAsset<T>(string path) where T : Object // 获取已加载的资源
public static T GetLoadedAsset<T>(string address) where T : Object // 获取已加载的资源
public static GameObject Instantiate(string path, bool load = false) // 实例化游戏对象。如果资源已加载,直接实例化;如果未加载,按需加载并实例化
public static GameObject Instantiate(string address, bool load = false) // 实例化游戏对象。如果资源已加载,直接实例化;如果未加载,按需加载并实例化
public static async Task<GameObject> InstantiateAsync(string path, bool load = false) // 异步实例化游戏对象。如果资源已加载,直接实例化;如果未加载,按需加载并实例化
public static async Task<GameObject> InstantiateAsync(string address, bool load = false) // 异步实例化游戏对象。如果资源已加载,直接实例化;如果未加载,按需加载并实例化
public static void LoadResource<T>(string path) where T : UnityEngine.Object // 加载指定路径的资源
public static void LoadResource<T>(string address) where T : UnityEngine.Object // 加载指定地址的资源
public static async Task LoadResourceAsync<T>(string path) where T : UnityEngine.Object // 异步加载指定路径的资源
public static async Task LoadResourceAsync<T>(string address) where T : UnityEngine.Object // 异步加载指定地址的资源
public static void ReleaseResource(string path) // 释放指定已加载的资源
public static void ReleaseResource(string address) // 释放指定已加载的资源
但是,如果资源加载方式的不同,方法的具体使用也就不同
Addressables
:所有address
参数都需要传入资源的地址,一般来说是文件名,只要使用了我的工具(后面会提到),你就不需要手动去设置。UnityEngine.Resources
:所有的path
参数需要传入资源相对于Resources
文件夹的路径,不需要包含文件后缀。例如,如果资源在Asset/Resources/Image.png
,则需要传入Image
,如果在Asset/Resources/Image/Image.png
,则传入Image/Image
。
UnityEngine.Resources
为了简化UI管理器等需要动态加载资源的方法的调用,在调用时,资源将统一同步加载,并且无需传入资源路径。
GetResourcePath
方法正是为此设计的,它负责生成正确的资源路径。
因此,有一个约定:如果使用UnityEngine.Resources
加载方式,框架支持的资源应该放在指定的文件夹中:
- UI:
Asset/Resources/UI/
- 音频:
Asset/Resources/Audio/
- 背景:
Asset/Resources/Backgrounds/
- 立绘:
Asset/Resources/Characters/
Addressables
同样地,Addressables
资源加载方式下,UI管理器等需要动态加载资源的方法,也是同步加载资源,调用它们只需要传入在Addressables
中注册的地址即可。
但是,每个资源的地址必须是唯一的。如果使用了我的工具,即使资源位于不同的文件夹下,也不能重名,因为工具会根据文件名自动设置资源的地址。
自动配置Addressables工具
为了方便那些不熟悉Addressables
的用户,我写了一个工具,能够自动配置资源的分组和设置地址。用户只需要填写资源路径和分组名即可。
工具会自动筛选路径下有效的文件类型并进行添加。
当然,使用我的工具进行自动配置后,你仍然可以在Addressables
的group
窗口手动修改资源地址。
注意:使用地址后,绝对不要修改资源地址!
默认的资源加载器
尽管我推荐大家使用Addressables
来加载资源,但为了方便使用,我将默认资源加载方式设为了UnityEngine.Resources
。
你可以在框架设置中切换当前的资源加载方式
如果你没有安装Addressables
包,在尝试切换资源加载方式为Addressables
时,系统会弹出提示,告知你需要通过包管理器安装它(弹窗关闭后不会自动打开包管理器)。
包管理器安装Addressables
:
如果没有安装
Addressables
包,会阻止你切换资源加载方式,因为相关代码无法编译。成功将资源加载方式切换为
Addressables
后,你就能在工具一栏看到Configure Addressables
选项了
结语
在设计理念上,我封装的Unity资源加载器类属于框架的底层。
而在实际开发过程中,你不需要直接使用它们来进行资源的加载,
因为在框架所支持的功能上:切换背景、立绘、音频以及UI,这些行为都会动态加载资源,而这些行为都会自动调用底层的资源加载器来处理资源加载。