当前位置:网站首页>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热更新
边栏推荐
- 01 自然语言处理NLP介绍
- Four departments including the Ministry of Industry and Information Technology promote green smart home products to the countryside
- tianqf's problem-solving ideas
- SSM整合开发案例
- 高项 03 项目立项管理
- 【Oracle 11g】Redhat 6.5 安装 Oracle11g
- tianqf的解题思路
- 高项 04 项目变更管理
- Codeforces Round #359 (Div. 2) C. Robbers' watch Violent Enumeration
- 2017icpc沈阳 G Infinite Fraction Path BFS+剪枝
猜你喜欢

错误:为 repo ‘oracle_linux_repo‘ 下载元数据失败 : Cannot download repomd.xml: Cannot download repodata/repomd.

排序第二节——选择排序(选择排序+堆排序)(两个视频讲解)

基于布朗运动的文本生成方法-LANGUAGE MODELING VIA STOCHASTIC PROCESSES

c语言位段

排序第三节——交换排序(冒泡排序+快速排序+快排的优化)(5个视频讲解)

链表专项练习(三)

排序第四节——归并排序(附有自己的视频讲解)

SSM整合开发案例

数据库索引原理

Colors that Tkinter can choose from
随机推荐
redis学习笔记
JSONObject遍历的时候顺序不一致,导致数据对应出错
js数组相关知识复习
金九银十即将到来,求职套路多,面试指南我来分享~
差分约束-图论
排序第三节——交换排序(冒泡排序+快速排序+快排的优化)(5个视频讲解)
一键登陆服务器脚本
【Template】Tree Chain Segmentation P3384
Win10桌面图标排列混乱
Codeforces Round #359 (Div. 2) C. Robbers' watch 暴力枚举
设备指纹详解之识别垃圾账号
训练好的深度学习模型,多种部署方式
神经网络优化器
【ROS2原理8】节点到参与者的重映射
Four departments including the Ministry of Industry and Information Technology promote green smart home products to the countryside
【报错】Root Cause com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure
vlucas/phpdotenv phpdotenv获取变量内容偶尔出现返回false
Pytorch 训练技巧
Tkinter可以选择的颜色
MUV LUV EXTRA 2019CCPC秦皇岛站J题 KMP