当前位置:网站首页>Unity 3D模型展示框架篇之资源打包、加载、热更(二)
Unity 3D模型展示框架篇之资源打包、加载、热更(二)
2022-08-09 07:37:00 【yxlalm】
本项目将整合之前Unity程序基础小框架专栏在Unity 3D模型展示项目基础上进行整合,并记录了集成过程中对原脚本的调整过程。增加了Asset Bundle+ILRuntime热更新技术流程。
本篇文章介绍如何对更新进行代码检测以及使用更新资源服务器进行资源热更新。
创建登录UI预制体LoginUI.prefab
,主要功能按钮如图所示:
添加项目启动脚本ProLaunch.cs
,主要进行热更资源检测、下载更新操作。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.AddressableAssets.ResourceLocators;
using UnityEngine.ResourceManagement.AsyncOperations;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
public class ProLaunch : MonoBehaviour
{
/// <summary>
/// 显示下载状态和进度
/// </summary>
public Text UpdateText;
public Text DownText;
public Button btnCheckAndUpdate;
public Button btnUpdate;
public Button btnDown;
public Button btnLogin;
public Slider Slider;//滑动条组件
private List<object> _updateKeys = new List<object>();
// Start is called before the first frame update
void Start()
{
//retryBtn.gameObject.SetActive(false);
btnCheckAndUpdate.onClick.AddListener(() =>
{
StartCoroutine(DoUpdateAddressadble());
});
btnUpdate.onClick.AddListener(() =>
{
UpdateCatalog();
});
// 默认自动执行一次更新检测
//StartCoroutine(DoUpdateAddressadble());
btnDown.onClick.AddListener(() =>
{
DownLoad();
});
btnLogin.onClick.AddListener(() =>
{
SceneManager.LoadScene(1);
//StartCoroutine(LoadScene("Test2"));
});
}
// Update is called once per frame
void Update()
{
}
public async void UpdateCatalog()
{
//初始化Addressable
var init = Addressables.InitializeAsync();
await init.Task;
//开始连接服务器检查更新
var handle = Addressables.CheckForCatalogUpdates(false);
await handle.Task;
Debug.Log("check catalog status " + handle.Status);
if (handle.Status == AsyncOperationStatus.Succeeded)
{
List<string> catalogs = handle.Result;
if (catalogs != null && catalogs.Count > 0)
{
foreach (var catalog in catalogs)
{
Debug.Log("catalog " + catalog);
}
Debug.Log("download catalog start ");
UpdateText.text = UpdateText.text + "\n下载更新catalog";
var updateHandle = Addressables.UpdateCatalogs(catalogs, false);
await updateHandle.Task;
foreach (var item in updateHandle.Result)
{
Debug.Log("catalog result " + item.LocatorId);
foreach (var key in item.Keys)
{
Debug.Log("catalog key " + key);
}
_updateKeys.AddRange(item.Keys);
}
Debug.Log("download catalog finish " + updateHandle.Status);
UpdateText.text = UpdateText.text + "\n更新catalog完成" + updateHandle.Status;
}
else
{
Debug.Log("dont need update catalogs");
UpdateText.text = "没有需要更新的catalogs信息";
}
}
Addressables.Release(handle);
}
public void DownLoad()
{
StartCoroutine(DownAssetImpl());
}
public IEnumerator DownAssetImpl()
{
var downloadsize = Addressables.GetDownloadSizeAsync(_updateKeys);
yield return downloadsize;
Debug.Log("start download size :" + downloadsize.Result);
UpdateText.text = UpdateText.text + "\n更新文件大小" + downloadsize.Result;
if (downloadsize.Result > 0)
{
var download = Addressables.DownloadDependenciesAsync(_updateKeys, Addressables.MergeMode.Union);
yield return download;
//await download.Task;
Debug.Log("download result type " + download.Result.GetType());
UpdateText.text = UpdateText.text + "\n下载结果类型 " + download.Result.GetType();
foreach (var item in download.Result as List<UnityEngine.ResourceManagement.ResourceProviders.IAssetBundleResource>)
{
var ab = item.GetAssetBundle();
Debug.Log("ab name " + ab.name);
UpdateText.text = UpdateText.text + "\n ab名称 " + ab.name;
foreach (var name in ab.GetAllAssetNames())
{
Debug.Log("asset name " + name);
UpdateText.text = UpdateText.text + "\n asset 名称 " + name;
}
}
Addressables.Release(download);
}
Addressables.Release(downloadsize);
}
IEnumerator LoadScene(string senceName)
{
// 异步加载场景(如果场景资源没有下载,会自动下载),
var handle = Addressables.LoadSceneAsync(senceName);
if (handle.Status == AsyncOperationStatus.Failed)
{
Debug.LogError("场景加载异常: " + handle.OperationException.ToString());
yield break;
}
while (!handle.IsDone)
{
// 进度(0~1)
float percentage = handle.PercentComplete;
Debug.Log("进度: " + percentage);
yield return null;
}
Debug.Log("场景加载完毕");
}
IEnumerator DoUpdateAddressadble()
{
AsyncOperationHandle<IResourceLocator> initHandle = Addressables.InitializeAsync();
yield return initHandle;
// 检测更新
var checkHandle = Addressables.CheckForCatalogUpdates(false);
yield return checkHandle;
if (checkHandle.Status != AsyncOperationStatus.Succeeded)
{
OnError("CheckForCatalogUpdates Error\n" + checkHandle.OperationException.ToString());
yield break;
}
if (checkHandle.Result.Count > 0)
{
var updateHandle = Addressables.UpdateCatalogs(checkHandle.Result, false);
yield return updateHandle;
if (updateHandle.Status != AsyncOperationStatus.Succeeded)
{
OnError("UpdateCatalogs Error\n" + updateHandle.OperationException.ToString());
yield break;
}
// 更新列表迭代器
List<IResourceLocator> locators = updateHandle.Result;
foreach (var locator in locators)
{
List<object> keys = new List<object>();
keys.AddRange(locator.Keys);
// 获取待下载的文件总大小
var sizeHandle = Addressables.GetDownloadSizeAsync(keys);
yield return sizeHandle;
if (sizeHandle.Status != AsyncOperationStatus.Succeeded)
{
OnError("GetDownloadSizeAsync Error\n" + sizeHandle.OperationException.ToString());
yield break;
}
long totalDownloadSize = sizeHandle.Result;
UpdateText.text = UpdateText.text + "\ndownload size : " + totalDownloadSize;
Debug.Log("download size : " + totalDownloadSize);
if (totalDownloadSize > 0)
{
// 下载
var downloadHandle = Addressables.DownloadDependenciesAsync(keys, Addressables.MergeMode.Union, false);
//yield return downloadHandle;
while (!downloadHandle.IsDone)
{
if (downloadHandle.Status == AsyncOperationStatus.Failed)
{
OnError("DownloadDependenciesAsync Error\n" + downloadHandle.OperationException.ToString());
yield break;
}
// 下载进度
float percentage = downloadHandle.PercentComplete;
Debug.Log($"已下载: {
percentage}");
DownText.text = $"已下载: {
Mathf.Round(percentage * 100)}%";
Slider.value = percentage;
if (percentage >= 0.9f)//如果进度条已经到达90%
{
Slider.value = 1; //那就让进度条的值编变成1
}
yield return null;
}
yield return downloadHandle;
if (downloadHandle.Status == AsyncOperationStatus.Succeeded)
{
Debug.Log("下载完毕!");
DownText.text = DownText.text + " 下载完毕";
}
}
}
}
else
{
UpdateText.text = UpdateText.text + "\n没有检测到更新";
}
// 进入游戏
EnterPro();
}
// 进入游戏
void EnterPro()
{
// TODO
UpdateText.text = UpdateText.text + "\n进入游戏场景";
Debug.Log("进入游戏");
}
private void OnError(string msg)
{
UpdateText.text = UpdateText.text + $"\n{
msg}\n请重试! ";
}
}
注意使用代码更新时,需要修改热AddressableAssetSettings更新设置否则代码将无法检测拦截更新信息
。
做完以上工作,进行热更Groups
的设置与修改。创建一个远程更新组并命名为RemoteGroup
,按照图中所示进行热更资源配置。
配置热更资源服务器,web服务器为IIS,如何创建应用程序这里不做赘述,有不懂的小伙伴留言。这里注意将热更新资源.bundle
、.hash
加入到应用程序的MIME中使得Unity项目可以访问到,否则404无法访问资源。
配置好IIS服务器后访问地址 http://www.btlfxx.cn/unity_cmj/tempas,没毛病!!!
Unity项目中配置远程更新服务器
配置信息
配置完成后New Build
一下,重新生成一下.bin
文件。
构建成功信息
打开本地构建热更资源的文件夹,看到如下文件信息。这些就是需要Copy到服务器上的热更文件,Copy服务器之后在进行如下配置。
确定项目热更新的工作模式
运行Unity项目
点击检测并更新
点击登录
后跳转场景
下面做热更操作,将Switch
预制体中的模块隐藏掉。重新构建资源热更包,将热更包Copy到服务器上。
运行项目,下面做一个能下载资源的热更包。
将RemoteGroup
组中的Switch
中的主体添加一个3D物体,重新打包。可以发现3个更新文件,组remotegroup
新生成一个资源包,只需要Copy这3个文件到服务器上。
演示效果
Unity AA热更新
边栏推荐
- View log common commands
- 【MySQL】update mysql.user set authentication_string=password(“123456“) where User=‘root‘; 报错
- 链表专项练习(三)
- JSONObject遍历的时候顺序不一致,导致数据对应出错
- DIMP:Learning Discriminative Model Prediction for Tracking 学习判别模型预测的跟踪
- imageio读取.exr报错 ValueError: Could not find a backend to open `xxx.exr‘ with iomode `r`
- 更改Jupyter Notebook默认打开目录
- SAP ALV data export many of the bugs
- Laravel文档阅读笔记-Rendering JSON(对JS变量进行赋值)
- 数据库索引原理
猜你喜欢
灵活好用的sql monitoring 脚本 part7
虚拟机网卡报错:Bringing up interface eth0: Error: No suitable device found: no device found for connection
Win10桌面图标排列混乱
pip安装更换镜像
子路由及路由出口配置
RK3568商显版开源鸿蒙板卡产品解决方案
低成本、大容量、高交互…Polkadot 引领 GameFi 实现新突破
jmeter concurrency and some limitations of the press
软件测试的岗位会越来越少吗?
PyTorch中 torch.nn与torch.nn.functional的区别
随机推荐
(error) NOAUTH Authentication required.
View log common commands
Rsync常见错误
浅识微服务架构
tianqf's problem-solving ideas
差分约束-图论
Lottie系列一:介绍与使用
Codeforces Round #359 (Div. 2) C. Robbers' watch 暴力枚举
list与string转换
【转载】Deep Learning(深度学习)学习笔记整理
灵活好用的sql monitoring 脚本 part7
Codeforces Round #359 (Div. 2) C. Robbers' watch Violent Enumeration
P1505 [国家集训队]旅游 树链剖分
数据一致性架构
【机器学习】随机森林、GBDT、XGBoost、LightGBM等集成学习代码练习
接口测试概念
Lottie系列四:使用建议
MYSQLWorkbench看数据库ER图
高项 03 项目立项管理
2017icpc沈阳 G Infinite Fraction Path BFS+剪枝