Unity3d中制作异步Loading进度条所遇到的问题

背景

通常游戏的主场景包括的资源较多,这会导致载入场景的时间较长。为了避免这个问题,能够首先载入Loading场景。然后再通过Loading场景来载入主场景。

由于Loading场景包括的资源较少,所以载入速度快。在载入主场景的时候通常会在Loading界面中显示一个进度条来告知玩家当前载入的进度。

在Unity中能够通过调用Application.LoadLevelAsync函数来异步载入游戏场景,通过查询AsyncOperation.progress的值来得到场景载入的进度。

尝试——遇到问题

第一步当载入完Loading场景后。调用例如以下的LoadGame函数開始载入游戏场景,使用异步载入的方式载入场景1(Loading场景为0,主场景为1),通过Unity提供的Coroutine机制,我们能够方便的在每一帧结束后调用SetLoadingPercentage函数来更新界面中显示的进度条的数值。

public void LoadGame() {
    StartCoroutine(StartLoading_1(1));
}

private IEnumerator StartLoading_1(int scene) {
    AsyncOperation op = Application.LoadLevelAsync(scene);
    while(!op.isDone) {
        SetLoadingPercentage(op.progress * 100);
        yield return new WaitForEndOfFrame();
    }
}

最后进度条的效果显演示样例如以下:

进度条并没有连续的显示载入的进度,而是停顿一下切换一个数字,再停顿一下切换一个数子,最后在没有显示100%就情况下就切换到主场景了。究其原因在于Application.LoadLevelAsync并非真正的后台载入,它在每一帧载入一些游戏资源,并给出一个progress值,所以在载入的时候还是会造成游戏卡顿。AsyncOperation.progress的值也不够精确。

当主场景载入完成后Unity就自己主动切换场景,所以上述代码中的while循环体内的代码是不会被调用的,导致进度条不会显示100%。

修补——100%完毕

为了让进度条能显示100%,取巧一点的办法是将AsyncOperation.progress的值乘上2,这样当载入到50%的时候界面上就显示100%了。缺点是当界面上显示100%的时候,用户还要等待一段时间才会进入游戏。事实上Unity提供了手动切换场景的方法。把AsyncOperation.allowSceneActivation设为false就能够禁止Unity载入完成后自己主动切换场景。改动后的StartLoading_2代码例如以下:

// this function is not work
private IEnumerator StartLoading_2(int scene) {
    AsyncOperation op = Application.LoadLevelAsync(scene);
    op.allowSceneActivation = false;
    while(!op.isDone) {
        SetLoadingPercentage(op.progress * 100);
        yield return new WaitForEndOfFrame();
    }
    op.allowSceneActivation = true;
}

我们首先将AsyncOperation.allowSceneActivation设为false。当载入完毕后再设为true

代码看上去没有错,可是运行的结果是进度条最后会一直停留在90%上。场景不会切换。

通过打印log发现AsyncOperation.isDone一直为falseAsyncOperation.progress的值添加到0.9后就保持不变了,也就是说场景永远不会被载入完毕。

在这个帖子中找到了答案。原来把allowSceneActivation设置为false后,Unity就仅仅会载入场景到90%,剩下的10%要等到allowSceneActivation设置为true后才载入,这不得不说是一个坑。所以代码改为例如以下。

AsyncOperation.progress到达0.9后。就直接把进度条的数值更新为100%,然后设置AsyncOperation.allowSceneActivationture,让Unity继续载入未完毕的场景。

private IEnumerator StartLoading_3(int scene) {
    AsyncOperation op = Application.LoadLevelAsync(scene);
    op.allowSceneActivation = false;
    while(op.progress < 0.9f) {
        SetLoadingPercentage(op.progress * 100);
        yield return new WaitForEndOfFrame();
    }
    SetLoadingPercentage(100);
    yield return new WaitForEndOfFrame();
    op.allowSceneActivation = true;
}

最后的效果例如以下:

打磨——添加动画

上述的进度条尽管攻克了100%显示的问题,但因为进度条的数值更新不是连续的。所以看上去不够自然和美观。为了看上去像是在连续载入。能够每一次更新进度条的时候插入过渡数值。

这里我採用的策略是当获得AsyncOperation.progress的值后,不马上更新进度条的数值,而是每一帧在原有的数值上加1,这样就会产生数字不停滚动的动画效果了。迅雷中显示下载进度就用了这种方法。

private IEnumerator StartLoading_4(int scene) {
    int displayProgress = 0;
    int toProgress = 0;
    AsyncOperation op = Application.LoadLevelAsync(scene);
    op.allowSceneActivation = false;
    while(op.progress < 0.9f) {
        toProgress = (int)op.progress * 100;
        while(displayProgress < toProgress) {
            ++displayProgress;
            SetLoadingPercentage(displayProgress);
            yield return new WaitForEndOfFrame();
        }
    }

    toProgress = 100;
    while(displayProgress < toProgress){
        ++displayProgress;
        SetLoadingPercentage(displayProgress);
        yield return new WaitForEndOfFrame();
    }
    op.allowSceneActivation = true;
}

displayProgress用来记录要显示在进度条上的数值。最后进度条的动画例如以下:

对照第一种的进度条

总结

假设在载入游戏主场景之前还须要解析数据表格,生成对象池。进行网络连接等操作,那么能够给这些操作赋予一个权值。利用这些权值就能够计算载入的进度了。

假设你的场景载入速度很快,那么能够使用一个假的进度条,让玩家看上几秒钟的loading动画,然后再载入场景。总之进度条尽管小,但要做好也是不easy的。

參考

  1. 阿高.Unity 显示Loading(载入)进度 对于网上流行的方法进行更正
  2. Unity3d官方论坛.using allowSceneActivation
时间: 2024-10-21 16:51:54

Unity3d中制作异步Loading进度条所遇到的问题的相关文章

unity3d___UGui中如何创建loading...进度条

http://blog.sina.com.cn/s/blog_e82e8c390102wh2z.html 实现方法:通过Image组件中Image Type属性中Fill Amount,通过代码改变Fill Amount的值就可以实现进度条效果 首先在Hierarchy中创建UI>Image,调整Image Type为Filled,Fill Method为Horizontal,拉动Fill Amount查看图片效果 代码篇:

Android loading进度条使用简单总结

在这里,总结一下loading进度条的使用简单总结一下. 一.说起进度条,必须说说条形进度条,经常都会使用到嘛,特别是下载文件进度等等,还有像腾讯QQ安装进度条一样,有个进度总给人良好的用户体验. 先来找图看看,做这个图完成不用图片就可以做到了. 看下xml布局文件,其实就是直接用xml写的在加两个属性设置一下就好了,一个style,另一个是background. <ProgressBar android:id="@+id/pb_progressbar" style="

图解CSS3制作圆环形进度条的实例教程

圆环形进度条制作的基本思想还是画出基本的弧线图形,然后CSS3中我们可以控制其旋转来串联基本图形,制造出部分消失的效果,下面就来带大家学习图解CSS3制作圆环形进度条的实例教程 首先,当有人说你能不能做一个圆形进度条效果出来时,如果是静态完整圆形进度条,那么就很简单了: .circleprogress{        width: 160px;        height: 160px;        border:20px solid red;        border-radius: 50

Chromium中网页加载进度条研究

1.     Shell.java中有成员变量:mProgressDrawable. 该成员变量在方法:onFinishInflate中被初始化. 在该类中有方法:onLoadProgressChanged,该方法中对进度条的值进行改变,并且对刷新完成事件进行反馈. 2.     上面的这个方法是在cc文件中被调用的. 上面方法对应的cc方法是shell_android.cc文件中的LoadProgressChanged方法. voidShell::LoadProgressChanged(Web

PHP+ajaxForm异步带进度条上传文件实例

在使用ajaxForm方法之前,首先需要安装form.js的插件,网上有: 一.首先说用法,ajaxForm可以接收0或1个参数,该参数可以是一个变量.一个对象或回调函数,这个对象主要有以下参数: var object= {                     url:url, //form提交数据的地址   type:type,   //form提交的方式(method:post/get)   target:target, //服务器返回的响应数据显示的元素(Id)号           

Android中的webview的进度条

<application android:icon="@drawable/hunqin" android:label="@string/app_name" android:theme="@android:style/Theme.Light" > 主题 android:theme------->必须不能使Theme.Light.NoTitleBar 否则不起作用 requestWindowFeature(Window.FEATUR

模态框的理解 ,jQ: loading,进度条, 省级联动 ,富文本编辑器 表单验证 插件

模态框: 打开一个弹框 不关闭它就不能做框外的操作 必须关闭或弹出另外的弹框 加载延迟loading + 进度条只要有请求 就处理一下监控ajax 全局事件jquery: 开始     $('#box').ajaxStart() 多个ajax共享一个Start 发送 .ajaxSend() 成功 .ajaxSuccess() 完成 . ajaxComplete() 完成后有错误 .ajaxError() 停止 .ajaxStop()多个ajax共享一个Stop Nprogress:进度条引入 c

【转】Unity3d中制作Loading场景进度条所遇到的问题 LoadLevelAsync,AsyncOperation

背景 通常游戏的主场景包含的资源较多,这会导致加载场景的时间较长.为了避免这个问题,可以首先加载Loading场景,然后再通过Loading场景来加载主场景.因为Loading场景包含的资源较少,所以加载速度快.在加载主场景的时候一般会在Loading界面中显示一个进度条来告知玩家当前加载的进度.在Unity中可以通过调用Application.LoadLevelAsync函数来异步加载游戏场景,通过查询AsyncOperation.progress的值来得到场景加载的进度. 尝试--遇到问题

异步加载场景及Loading进度条制作

实现功能:点击开始游戏以后UI界面进入Loading界面,Loading结束以后自动进入游戏场景. 在这之前先在Build Settings中Add要使用的场景 在场景A中添加StartGame方法: Application.LoadLevel(1)://同步加载Loading界面(因为Loading界面资源较少速度快所以此处用同步方法) 在Loading场景中加入进度条图片:分为上下两层,上层负责显示进度 将上层的进度条Image组件中的Image Ttpe改为Filled 接下来再Loadi