[Unity3D]Unity3D游戏开发之异步记载场景并实现进度条读取效果
大家好,我是秦元培。欢迎大家关注我的博客,我的博客地址是:blog.csdn.net/qinyuanpei。终于在各种无语的论文作业中解脱了,所以立即抓紧时间来这里更新博客。博主本来计划在Unity3D游戏开发之从《魂斗罗》游戏说起(上)——目标追踪这篇文章后再写一篇《Unity3D游戏开发之从《魂斗罗》游戏说起(下)》,只是眼下博主的项目进度有些缓慢,所以想等项目稳定下来以后再和大家分享。
作为大家等待博主更新博客的回报,我们今天来说一说Unity3D中的游戏场景异步载入。那么什么是游戏场景异步载入呢?异步载入就是系统在载入数据(如地图数据、模型数据、玩家数据等)时能够运行其他的任务。事实上就是我们熟悉的多线程啦。相反地,在单线程中。我们通常须要等待数据载入完毕以后才干继续运行任务。我们能够从《仙剑奇侠传》、《古剑奇谭》等游戏中找到这种样例。比方《仙剑奇侠传四》中的五毒兽勇气读条效果:
再比方《古剑奇谭》中融入了游戏特色介绍的读条效果:
从上面的这些样例我们能够看出,在游戏设计中通过合理的游戏场景载入方式,降低玩家等待的时间。对于一个游戏来说是设计的时候须要好好考虑的一个问题。在Web设计中一个好的Web设计通常要考虑要将用户等待页面响应的时间降到最低,这样才不会导致用户流量的缺失。在一个注重用户体验的时代。不管设计什么样的产品,带给用户最为极致的体验才是最重要的。我们注意到这两款游戏都採用了异步载入的方式。由于在载入游戏的过程中,系统在运行界面GUI元素的绘制工作。那么,好了,在了解了异步载入的概念和异步载入的原理以后,我们就来实现今天的内容,如图是我们今天要来实现的效果图,我们希望实如今游戏载入的过程中,能够在进度条下方交替显示不同的提示内容:
那么详细怎么实现呢?在Unity3D中提供了一个LoadLevelAsync()方法。该方法能够用于异步载入场景资源。
该方法返回一个 AsyncOperation类型的返回值,该返回值有两个重要的属性:1、 isDone:能够查询是否载入完毕;2、progress:一个介于0-1之间的值,能够表示载入的进度
好了。通过这两个属性和这种方法。我们就能够实现今天的内容啦,一起開始吧!
首先创建一个场景,我们这里使用系统默认的GUI系统,如图:
这个界面就是我们今天的载入界面,在界面载入的过程中,我们能够在背景下方显示游戏中的Tips和游戏进度。通常情况下。我们须要三个界面来完毕一个完整的界面载入效果。
第一个界面称为触发界面,主要负责响应用户的触发操作。第二个就是我们今天这里在讲的载入界面,主要负责读条及UI刷新。第三个界面就是我们终于要呈现给玩家的界面。
这比方在《仙剑奇侠传》游戏中。当玩家靠近房屋时会在门口显示一个箭头的效果。这样能够提示玩家即将进入场景载入的触发区域。当玩家进入这个范围时,就会触发载入界面的显示。这样我们就能看到五毒兽勇气的读条效果了。当读条结束后,会进入第三个界面,这是我们终于要显示给玩家的界面。。好了,这就是异步载入游戏场景的一个完整的过程了。
我们以下来编写脚本实现今天的功能,对于载入过程这个界面,我们主要用到我们的LoadLevelAsync()方法:
using UnityEngine;
using System.Collections; public class Loading : MonoBehaviour { //异步对象
private AsyncOperation mAsyn;
//绑定Tip的GUIText
private GUIText mTip;
//Tip集合,实际开发中须要从外部文件里读取
private string[] mTips=new string[]
{
"异步载入过程中你能够浏览游戏攻略",
"异步载入过程中你能够查看当前进度",
"异步载入过程中你能够推断是否载入完毕",
"博主不理解轩6的读条为什么那样慢",
"难道是由于DOOM不懂Unity3D",
}; //更新Tip的时间
private const float UpdateTime=2.0F;
//上一次更细的时间
private float lastTime=0.0F; void Start ()
{
mTip=GameObject.Find("GUITips").GetComponent<GUIText>();
StartCoroutine("Load");
} IEnumerator Load()
{
mAsyn=Application.LoadLevelAsync("Main");
yield return mAsyn;
} void Update ()
{
//假设场景没有载入完则显示Tip
if(mAsyn!= null && !mAsyn.isDone)
{
//假设达到了更新的时间
if(Time.time-lastTime>=UpdateTime)
{
lastTime=Time.time;
mTip.guiText.text=mTips[Random.Range(0,5)]+"("+(float)mAsyn.progress * 100+"%"+")";
}
}else
{
Application.LoadLevel("Main");
}
}
}
这里的代码非常好理解。假设载入完毕了就载入终于界面,否则就随机显示Tips和载入的进度。
这里博主为了节省时间,使用的是前一篇文章中的场景。如图:
而对于触发载入事件的界面,我们仅仅须要使用普通的载入方式就能够了:
using UnityEngine;
using System.Collections; public class TriggerToLoad : MonoBehaviour { void OnGUI()
{
if(GUILayout.Button("载入Loading场景",GUILayout.Height(30)))
{
Application.LoadLevel("Scene2");
}
}
}
显然,这是一个当用户点击button时载入场景的方法,所以不再做太多的解释。由于这种方法仅仅支持Pro版本号的Unity3D,因此博主的免费版Unity3D注定是无法运行了,所以这里无法给大家做程序演示,希望大家谅解啊。在Unity3D异步载入场景的问题中,有两个常见的问题:
1、使用 AsyncOperation的progress获取载入进度,载入进度不变
2、无法捕捉到场景载入完毕的事件:使用DontDestroyOnLoad能够解决
好了,今天的内容就是这样了,博主的能力有限,能够理解到的仅仅有这么多啦。不管怎么样。还是希望能和大家一起成长啊,呵呵。
參考文章:
每日箴言:勇者不是没有眼泪的人。而是含着眼泪微笑奔跑的人。
喜欢我的博客请记住我的名字:秦元培,我博客地址是blog.csdn.net/qinyuanpei。
转载请注明出处。本文作者:秦元培,本文出处:http://blog.csdn.net/qinyuanpei/article/details/30836567
2015年11月30日更新:
有朋友问起这篇文章中的效果无法实现,这是由于这篇文章写作时间较长。并且当时博主所使用的Unity3D版本号是免费版本号,所以异步载入这块的内容并没有经过深度地測试。
既然大家问起这个问题,就在这里补充着说一下吧,这个问题在网上已经有了比較好的解决方式。
首先。我们要明白的一点是异步载入和同步载入不同。异步载入是非堵塞的,所以在这个过程中我们能够使用一个进度条或者载入界面来过渡场景的载入过程。其次,Unity3D的异步载入有一个Bug是当进度载入到0.9的时候就停止了载入。并且会在这里卡顿一下。因此我们不能以1.0作为载入完毕的一个推断标志。Unity3D中的AsyncOperation是我们在处理场景异步载入时的一个类。这个类中封装了场景载入相关的信息。如场景是否载入完毕的isDone和当前场景载入的进度progress。这里。我们想重点说说allowSceneActivation这个属性。这个属性能够决定当场景载入到0.9的时候是否由Unity3D自己主动完毕剩余部分内容的载入,默认这个属性为true,所以当我们载入到0.9的时候,场景会略微地卡顿一下。那么,好了,我们怎么解决问题呢?这里分成两部分来处理,即前面的0.9由Unity3D来进行载入。而剩下的0.1则由我们完毕手动载入。我们一起来看以下的代码:
IEnumerator LoadSceneAsync(string levelName)
{
///当前进度
int currentProgress = 0;
///目标进度
int targetProgress = 0;
AsyncOperation op = Application.LoadLevelAsync(levelName); //载入前面的0.9
op.allowSceneActivation = false;
while(op.progress < 0.9f)
{
//计算目标进度
targetProgress = (int)op.progress * 100;
//在当前进度和目标进度间进行平滑
while(currentProgress < targetProgress)
{
++currentProgress;
//在这里处理载入相关的逻辑
yield return new WaitForEndOfFrame();
}
} //载入剩下的0.1
targetProgress = 100;
//在当前进度和目标进度间进行平滑
while(currentProgress < targetProgress)
{
++currentProgress;
//在这里处理载入相关的逻辑
yield return new WaitForEndOfFrame();
}
op.allowSceneActivation = true;
}
在这段代码中,我们实际上是利用allowSceneActivation属性控制了场景载入的过程,前面的0.9是正常的载入过程,而剩下0.1却是为了掩人耳目而补充的载入过程。
这里我们还使用了一个平滑的过程,这是由于假设直接以目标进度来设置载入相关的逻辑如进度条。那么表现出来的情况就是载入的进度不均匀,由于载入的进度是跳跃性的。
但是实际上载入的进度能百分之百的控制为均匀吗?答案是不行的。由于载入过程中的资源本身就不是均匀的啊。所以本质上进度条就是游戏资源载入过程中的遮羞布,它本身就带有非常强的欺骗感,比方进度都已经记载了99%了,结果最后的1%却载入了好长好长的时间,这科学吗?这显然不科学啊。这是博主又一次找到原始项目后又一次编写代码实现的场景载入进度条效果:
好了,这块儿基本没什么好说的了,再次提醒不读代码直接抄代码的各位,我本身不是什么大神。我写的代码一直非常渣,我从来没打算给大家一个开箱即用的编程体验,由于编程的过程本身就是迷惑的,须要你一步步地去探索。假设你仅仅是把我写的代码拷贝到编辑器中,却不知道该怎么用这个脚本,脚本中哪里有什么错误。我认为我真的没有必要在这样无私地奉献下去了,我自己从开源社区中收益良多。所以我自己愿意将自己了解到的、探索过的东西分享给大家,但是这并非各位懒惰的理由对吗?很多新手认为我对新手的要求特别严苛。大概新手们都认为假设我会了我还会来问你?可问题是新手不懂得该怎么提问甚至不懂得如何思考,我做本科毕业论文的时候尽管面对的是自己不喜欢的专业。可我比班里每个同学都认真,即使到了论文答辩的时候大家的结果不会由太大的区别,但是我挺喜欢这个过程的,由于它让我知道了怎么样去思考,毫无疑问,向别人求教是要做功课的,假设不懂得怎么提问,能够常常上上知乎,假设你希望的是我直接把代码写好给你、甚至帮你调试代码寻找Bug,抱歉我没有这种义务。有个读者从上周開始就向我频繁地索要一篇文章中没有给出源码的一个IO类的代码。我自认我已经将这个类的作用解释的特别清楚了,它没有做特别复杂的事情。仅仅是对System.IO这个命名空间的简单封装。我认为不论什么一个有编程基础的人都应该熟悉IO部分。但是将近一周过去了,这个读者还是没有自己实现这部分功能,试问就算我把代码给你了,你难道就会认认真真地看完然后从中有所收获?呵呵。我真不想为某些人的懒惰而愤慨了。我愿意分享技术是我的自由。我不愿提供完整的代码相同是我的自由。强迫是没有不论什么意义的。除了让你变得更加无知。好了,这次更新就是这样子!
[Unity3D]Unity3D游戏开发之异步记载场景并实现进度条读取效果的更多相关文章
- 关于《Unity3D/2D游戏开发从0到1》书籍再版说明
关于<Unity3D/2D游戏开发从0到1>第一版本在2015年7月1日全国发行,累计得到不少国内高校教师.培训机构的好评.但是由于Unity官方对于技术不断的升级与版本的快速迭代,基于U ...
- 《Unity3D/2D游戏开发从0到1(第二版本)》 书稿完结总结
前几天,个人著作<Unity3D/2D游戏开发从0到1(第二版)>经过七八个月的技术准备以及近3个月的日夜编写,在十一长假后终于完稿.今天抽出一点时间来,给广大热心小伙伴们汇报一下书籍概况 ...
- Unity3D 入门 游戏开发 Unity3D portal game development
Unity3D 入门 游戏开发 Unity3D portal game development 作者:韩梦飞沙 Author:han_meng_fei_sha 邮箱:313134555@qq.com ...
- Unity3D手机游戏开发
<Unity3D手机游戏开发> 基本信息 作者: 金玺曾 出版社:清华大学出版社 ISBN:9787302325550 上架时间:2013-8-7 出版日期:2013 年8月 开本:16开 ...
- 《Unity3D/2D游戏开发从0到1》正式出版发行
<Unity3D/2D游戏开发从0到1>正式出版发行 去年个人编写的Unity书籍正式在2015年7月正式发行,现在补充介绍一下个人著作.书籍信息: 书籍的名称: <Uni ...
- Unity 游戏开发技巧集锦之使用忍者飞镖创建粒子效果
Unity 游戏开发技巧集锦之使用忍者飞镖创建粒子效果 使用忍者飞镖创建粒子效果 游戏中,诸如烟.火.水滴.落叶等粒子效果,都可以使用粒子系统(particle system)来实现.例如,<明 ...
- Unity3D独立游戏开发日记(二):摆放建筑物
在沙盒游戏里,能自由建造是很重要的特点,比如说风靡全球的<我的世界>,用一个个方块就能搭建出规模宏大的世界.甚至有偏激的人说,没有自由建造,就不是一个真正的沙盒游戏.的确,沙盒游戏的魅力有 ...
- Unity3D独立游戏开发日记(一):动态生成树木
目前写的独立游戏是一个沙盒类型的游戏.游戏DEMO视频如下: 提到沙盒类型的游戏,就有人给出了这样的定义: 游戏世界离现实世界越近,自由度.随机度越高才叫沙盒游戏.所谓自由度,就是你在游戏里想干啥就干 ...
- Unity3D手游开发日记(3) - 场景加载进度条的完美方案
我以为做个进度条很简单,分分钟解决,结果折腾了一天才搞定,Unity有很多坑,要做完美需要逐一解决. 问题1:最简单的方法不能实现100%的进度 用最简单的方法来实现,不能实现100%的进度,原因是U ...
随机推荐
- 谈HTTPS中间人攻击与证书校验(一)
一.前言 随着安全的普及,https通信应用越发广泛,但是由于对https不熟悉导致开发人员频繁错误的使用https,例如最常见的是未校验https证书从而导致“中间人攻击”,并且由于修复方案也一直是 ...
- [GCJ2017R3]Cooclement
题目大意: 一种数列按照如下方式变化: 新数列第i位等于原数中数字i的出现次数. 变化过程中数列长度不变. 例如数列12的变化过程为12-11-20-01-10. 现在告诉你一个数列x,请求出x可能是 ...
- 10.十进制转m进制
时间限制: 1 s 空间限制: 128000 KB 题目等级 : 白银 Silver 题解 查看运行结果 题目描述 Description 将十进制数n转换成m进制数 m<=16 n<=1 ...
- 新手必须掌握的Linux命令(上)
1.1强大好用的Shell 通常来讲,计算机硬件是有运算器,控制器,存储器,输入/ 输出设备等共同组成的,而让各种硬件设备各司其职且又能协同运行的东西就是系统内核.Linux系统的内核负责完成对 ...
- Codeforces Round #346 (Div. 2) F. Polycarp and Hay 并查集 bfs
F. Polycarp and Hay 题目连接: http://www.codeforces.com/contest/659/problem/F Description The farmer Pol ...
- JSoup 用法详解
清单 1 // 直接从字符串中输入 HTML 文档 String html = "<html><head><title> 开源中国社区 </titl ...
- 【前台】【单页跳转】整个项目实现单页面跳转,抛弃iframe
即如下: [想做到点击nav侧边栏,仅替换右边div中的内容,而不是跳转到新的页面,这样的话,其实整个项目中就只有一个完整的页面,其他的页面均只写<body>内的部分即可,或者仅仅写要替换 ...
- JACOB的语法
转自:http://www.bitscn.com/pdb/java/200904/161117.html 如果你想写一个JAVA代码,其中需要调用JACOB提供的功能,而你还是新手,也许篇文章会大大降 ...
- Tui-x 基础使用
本章以Tui-x3.x仓库里的HelloTuiCpp项目来做具体解说.[ 由于HelloTuiCpp里面演示的全部控件,本文篇幅有限,不能一一说明,所以仅仅能列举两个控件,后面的文章会有针对性地解说其 ...
- 网络游戏MMORPG服务器架构
转载于:http://justdo2008.iteye.com/blog/1936795 1.网络游戏MMORPG整体服务器框架,包括早期,中期,当前的一些主流架构 .关键词 网络协议 网络IO 消息 ...