Unity3D教程:Json实现资源动态加载
![Unity3D教程:Json实现资源动态加载_第1页](https://file5.zhuangpeitu.com/fileroot5/2022-10/7/f4d533bd-d466-4422-82db-a3293a39ac5c/f4d533bd-d466-4422-82db-a3293a39ac5c1.gif)
![Unity3D教程:Json实现资源动态加载_第2页](/images/s.gif)
![Unity3D教程:Json实现资源动态加载_第3页](/images/s.gif)
《Unity3D教程:Json实现资源动态加载》由会员分享,可在线阅读,更多相关《Unity3D教程:Json实现资源动态加载(15页珍藏版)》请在装配图网上搜索。
1、Unity3D 教程: Json实现资源动态加载 Posted on 2013 年06月05日by U3d / Unity3D 基础教程/被围观142次 用Unity3D制作基于web的网络游戏,不可避免的会用到一个技术-资源动态加载。 比如想加载一个大场景的资源,不应该在游戏的开始让用户长时间等待全部资源的加载完 毕。应该优先加载用户附近的场景资源,在游戏的过程中,不影响操作的情况下,后台加 载剩余的资源,直到所有加载完毕。 本文包含一些代码片段讲述实现这个技术的一种方法。本方法不一定是最好的,希望 能抛砖引玉。代码是C#写的,用到了 Json,还有C#的事件机制。 在讲述代码之前,
2、先想象这样一个网络游戏的开发流程。首先美工制作场景资源的 3D建模,游戏设计人员把3D建模导进Unity3D,托托拽拽编辑场景,完成后把每个 gameobject导出成XXX.unity3d格式的资源文件(参看BuildPipeline ),并且把整个 场景的信息生成一个配置文件,xml或者Json格式(本文使用Json )。最后还要把资源 文件和场景配置文件上传到服务器,最好使用CMS管理。客户端运行游戏时,先读取服 务器的场景配置文件,再根据玩家的位置从服务器下载相应的资源文件并加载,然后开始 游戏,注意这里并不是下载所有的场景资源。在游戏的过程中,后台继续加载资源直到所 有加载完毕。
3、 一个简单的场景配置文件的例子: MyDemoSe nce.txt Json代码 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 4 6 47 48 49 “AssetList" : [{ “Name" : “Chair 1", Source" : 、'Prefabs/
4、Chair001.unity3d", ''Position" : [2,0,-5], ''Rotation" : [0.0,60.0,0.0] “Name" : “Chair 2", Source" : “Prefabs/Chair001.unity3d", Position" : [1,0,-5], ''Rotation" : [0.0,0.0,0.0] }, ''Name" : “Vanity", Source" : “Prefabs/vanity001.unity3d", ''Position" : [0,0,-4], “Rotation" : [0.0,0.0,0
5、.0] “Name" : 'Writing Table", Source" : “Prefabs/writingTable001.unity3d 'Position" : [0,0,-7], 'Rotation" : [0.0,0.0,0.0], 50 51 52 53 54 55 56 57 58 59 60 61 62 63 “
6、Name” : “Lamp”, Source” : “Prefabs/lampOOl.unity3d”, “Position” : [—0.5,0・7,—7], “Rotation” : [0.0,0.0,0.0] AssetList :场景中资源的列表,每一个资源都对应一个unity3D的gameobject Name : gameobject的名字,一个场景中不应该重名 Source :资源的物理路径及文件名 Position : gameobject 的坐标 Rotation : gameobject 的旋转角度
7、你会注意到Writing Table里面包含了 Lamp,这两个对象是父子的关系。配置文件 应该是由程序生成的,手工也可以修改。另外在游戏上线后,客户端接收到的配置文件应 该是加密并压缩过的。 主程序: C#代码 01 02 public class MainMonoBehavior : MonoBehaviour { 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 pub
8、lic delegate void MainEventHandler(GameObject dispatcher); public event MainEventHandler StartEvent; public event MainEventHandler UpdateEvent; public void Start() { ResourceManaqer.getInstance().LoadSence(“Scenes/MyDemoSence.txt”); if(StartEvent != null){ StartEvent(this.qameObject); public
9、void Update() { if (UpdateEvent != null) { UpdateEvent(this.qameObject); 这里面用到了 c#的事件机制,大家可以看看我以前翻译过的国外一个牛人的文章。C#事 件和 Unity3D 在start方法里调用ResourceManager,先加载配置文件。每一次调用update方 法,Mai nMon oBehavior 会把 update 事件分发给 ResourceMa nager,因为 ResourceManager注册了 MainMonoBehavior 的 update 事件。 ResourceMa
10、nager.cs
C#代码
01
02
03
private MainMonoBehavior mainMonoBehavior;
04
05
06
07
08
09
10
private Scene mScene;
private Asset mSceneAsset;
private ResourceManager() {
11
mainMonoBehavior = GameObject.Find(“Main
Camera”).GetComponent 11、thUtil・ qetResourcePath();
15
16
17
public void LoadSence(string fileName) {
18
19
mSceneAsset = new Asset();
20
21
mSceneAsset.Type = Asset.TYPE JSON;
22
23
24
mSceneAsset ・ Source
fileName;
private string mResourcePath;
25
mainMonoBehavior.UpdateEvent += OnUpdate;
26
27
在LoadS 12、enee方法里先创建一个Asset的对象,这个对象是对应于配置文件的,设 置 type 是 Json,source 是传进来的 “Seenes/MyDemoSence.txt”。然后注册 MainMonoBehavior 的 update 事件。
C#代码
01
02
03
04
05
06
07
08
09
public void OnUpdate(GameObject dispatcher) {
if (mSceneAsset != null) {
LoadAsset(mSceneAsset);
if (!mSceneAsset.isLoadFinished) 13、{
return;
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
}
//clear mScene and mSceneAsset for next LoadSence call
mScene = null;
mSceneAsset = null;
}
mainMonoBehavior.UpdateEvent -= OnUpdate;
}
On Update方法里调用LoadAsset加载配置文件对象及所有资源对象。每一帧都要判断 是否加载结束,如果结束清空mScene和mSceneAsset对象为 14、下一次加载做准备,并且 取消update事件的注册。
最核心的LoadAsset方法:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
private Asset LoadAsset(Asset asset) {
string fullFileName = mResourcePath + “/” + asset ・ Source;
//if www resource is new, set into www cache
if (!wwwCacheMap.ContainsKe 15、y(fullFileName)) {
if (asset.www == null
asset.www = new WWW(fullFileName);
return null;
if (!asset.www.isDone) {
return null;
C#代码
22
23
wwwCacheMap.Add(fullFileName, asset.www);
24
25
26
传进来的是要加载的资源对象,先得到它的物理地址,mResourcePath是个全局变量保 存资源服务器的网址,得到fullFileName类似 http://www.mydemogame.eom/ 16、asset/Prefabs/xxx.u ni ty3d。然后通过 wwwCacheMap判断资源是否已经加载完毕,如果加载完毕把加载好的www对象放到 Map里缓存起来。看看前面Json配置文件,Chair 1和Chair 2用到了同一个资源 ChairOOl.unity3d,加载Chair 2的时候就不需要下载了。如果当前帧没有加载完毕,返 回null等到下一帧再做判断。这就是WWW类的特点,刚开始用WWW下载资源的时候 是不能马上使用的,要等待诺干帧下载完成以后才可以使用。可以用yield返回www,这 样代码简单,但是C#要求调用yield的方法返回IEnumerator类型,这样限制太 17、多不灵 活。
继续LoadAsset方法:
01
02
03
04
05
06
07
08
09
Lf (asset.Type
if (mScene
Asset.TYPE JSON) { //Json
null) {
string jsonTxt = mSceneAsset ・ www.text;
mScene = JsonMapper.ToObject 18、0
31
32
33
//load scene
foreach (Asset sceneAsset in mScene.AssetList) {
if (sceneAsset.isLoadFinished) {
continue;
} else {
LoadAsset(sceneAsset);
if (!sceneAsset.isLoadFinished) {
return null;
代码能够运行到这里,说明资源都已经下载完毕了。现在开始加载处理资源了。第一 次肯定是先加载配置文件,因为是Js on格式,用Js on Mapper类把它转换成C#对象,我 用的是L 19、itJson开源类库。然后循环递归处理场景中的每一个资源。如果没有完成,返回 null,等待下一帧处理。
继续LoadAsset方法:
C#代码
0
else if (asset.Type == Asset.TYPE GAMEOBJECT) { //Gameobject
1
0
2
0
if (asset.gameObject == null) {
3
0
4
0
wwwCacheMap[fullFileName].assetBundle.LoadAll();
5
0
6
0
7
GameObject go = 20、
(GameObject)GameObject.Instantiate(wwwCacheMap[fullFileName].assetBundle.m ainAsset);
0
8
0
UpdateGameObject(go, asset);
9
1
0
1
asset.gameObject = go;
1
1
2
1
}
3
1
4
1
if (asset.AssetList != null) {
5
1
6
1
foreach (Asset assetChild in asset. 21、AssetList) {
7
1
8
1
if (assetChild.isLoadFinished) {
9
2
0
2
continue;
1
2
2
2
} else {
3
2
4
2
Asset assetRet = LoadAsset(assetChild);
5
2
6
2
if (assetRet != null) {
7
2
8
2
assetRet.gameObject.transform.parent = asset.gameObject.t 22、ransform;
9
3
0
3
} else {
1
3
2
3
return null;
3
3
4
3
}
5
3
6
3
}
7
3
8
3
}
9
4
0
4
1
4
2
4
3
4
4
4
5
4
6
4
7
4
8
4
9
5
0
asset.isLoadFinished
true;
return asset;
终于开始处理真正的资源了,从缓存中找到WWW对象,调用In sta ntiate方法实例化 23、成 Unity3D 的 gameobject。UpdateGameObject 方法设置 gameobject 各个属性,如位 置和旋转角度。然后又是一个循环递归为了加载子对象,处理gameobject的父子关系。 注意如果LoadAsset返回null,说明www没有下载完毕,等到下一帧处理。最后设置加 载完成标志返回asset对象。
UpdateGameObject 方法:
C#代码
01
02
03
04
05
06
07
08
09
private void UpdateGameObject(GameObject go, Asset asset) {
//na 24、me
go ・ name = asset ・ Name;
//position
Vector3 vector3 = new Vector3 (( ) asset ,
(float)asset ・Position[1], (float)asset ・Position[2]);
11
12
13
14
15
16
17
18
19
go.transform.position = vector3;
//rotation
vector3 = new Vector3 (( ) asset ,
(float)asset.Rotation[1], (float)asse 25、t.Rotation[2]);
go.transform.eulerAngles = vector3;
这里只设置了 gameobject的3个属性,眼力好的同学一定会发现这些对象都是"死 的”,因为少了脚本属性,它们不会和玩家交互。设置脚本属性要复杂的多,编译好的脚 本随着主程序下载到本地,它们也应该通过配置文件加载,再通过C#的反射创建脚本对 象,赋给相应的gameobject。
最后是Scene和asset代码:
C#代码
001
002
003
004
005
006
007
008
009
010
011
012
013
014 26、
015
016
017
018
019
020
021
022
023
024
025
public class Scene {
public List 27、ECT;
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
08 28、0
081
082
083
084
public byte Type {
get;
set;
public string Name {
get;
set;
public string Source {
get;
set;
public double[] Bounds {
get;
set;
public double[] Position {
get;
set;
public double[] Rotation {
get;
set;
public List 29、sLoadFinished {
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
get;
set;
public WWW www {
get;
set;
public Gam 30、eObject qameObject {
get;
set;
代码就讲完了,在我实际测试中,会看到gameobject—个个加载并显示在屏幕中, 并不会影响到游戏操作。代码还需要进一步完善适合更多的资源类型,如动画资源,文本, 字体,图片和声音资源。
动态加载资源除了网络游戏必需,对于大公司的游戏开发也是必须的。它可以让游戏 策划(负责场景设计),美工和程序3个角色独立出来,极大提高开发效率。试想如果策 划改变了什么NPC的位置,美工改变了某个动画,或者改变了某个程序,大家都要重新 倒入一遍资源是多么低效和麻烦的一件事。
- 温馨提示:
1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
2: 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
3.本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。