• Laya资源加载小记


    • Laya.Loader负责资源的加载逻辑,被LoaderManager管理。
    • Laya支持多种类型资源加载,也支持自定义类型加载。不同类型的加载方式可能不同。
    • Laya.Loader缓存已经被加载过得资源,减少资源重复加载。
    • 提供清理资源接口,由LoaderManager封装接口。
    • 部分资源加载包含多步加载,如Atlas和Font都包含文本下载和图片下载。
    • 注意:Laya.loader是LoaderManager的实例,是Laya对外的通用加载接口。Laya.Loader由LoaderManager统一管理,一般情况下,开发是不需要自己创建Loader实例。
    内置类型
    • Laya内部支持的文件类型有:
    		/** 文本类型,加载完成后返回文本。*/
    		public static const TEXT:String = "text";
    		/** JSON 类型,加载完成后返回json数据。*/
    		public static const JSON:String = "json";
    		/** XML 类型,加载完成后返回domXML。*/
    		public static const XML:String = "xml";
    		/** 二进制类型,加载完成后返回arraybuffer二进制数据。*/
    		public static const BUFFER:String = "arraybuffer";
    		/** 纹理类型,加载完成后返回Texture。*/
    		public static const IMAGE:String = "image";
    		/** 声音类型,加载完成后返回sound。*/
    		public static const SOUND:String = "sound";
    		/** 图集类型,加载完成后返回图集json信息(并创建图集内小图Texture)。*/
    		public static const ATLAS:String = "atlas";
    		/** 位图字体类型,加载完成后返回BitmapFont。*/
    		public static const FONT:String = "font";
    		/** TTF字体类型,加载完成后返回null。*/
    		public static const TTF:String = "ttf";
    		/**@private */
    		public static const PKM:String = "pkm";
    
    • Laya3D扩展类型:
    		/**@private 层级文件资源标记。*/
    		private static const HIERARCHY:String = "SPRITE3DHIERARCHY";
    		/**@private 网格的原始资源标记。*/
    		private static const MESH:String = "MESH";
    		/**@private 材质的原始资源标记。*/
    		private static const MATERIAL:String = "MATERIAL";
    		/**@private PBR材质资源标记。*/
    		private static const PBRMATERIAL:String = "PBRMTL";
    		/**@private TextureCube原始资源标记。*/
    		private static const TEXTURECUBE:String = "TEXTURECUBE";
    		/**@private Terrain原始资源标记。*/
    		private static const TERRAIN:String = "TERRAIN";
    
    这几种类型通过扩展的方式,在Laya3D初始化时,注册了对应的加载函数。
    
    • Laya文件后缀与文件类型的映射:
        //Laya内置类型
        {"png": "image","jpg": "image","jpeg": "image",
        "txt": "text",
        "json": "json",
        "xml": "xml",
        "als": "atlas","atlas": "atlas",
        "mp3": "sound", "ogg": "sound", "wav": "sound", 
        "part": "json", 
        "fnt": "font", 
        "pkm": "pkm", 
        "ttf": "ttf"};
        
        //Laya3D扩展  
        //通过扩展LoaderManager.createMap添加对应类型的解析。只对LoaderManager.create方法有效。
    	createMap["lh"] = [Sprite3D, Laya3D.HIERARCHY];
    	createMap["ls"] = [Scene, Laya3D.HIERARCHY];
    	createMap["lm"] = [Mesh, Laya3D.MESH];
    	createMap["lmat"] = [StandardMaterial, Laya3D.MATERIAL];
    	createMap["lpbr"] = [PBRMaterial, Laya3D.MATERIAL];
    	createMap["ltc"] = [TextureCube, Laya3D.TEXTURECUBE];
    	createMap["jpg"] = [Texture2D, "nativeimage"];
    	createMap["jpeg"] = [Texture2D, "nativeimage"];
    	createMap["png"] = [Texture2D, "nativeimage"];
    	createMap["pkm"] = [Texture2D, Loader.BUFFER];
    	createMap["lsani"] = [AnimationTemplet, Loader.BUFFER];
    	createMap["lrani"] = [AnimationTemplet, Loader.BUFFER];
    	createMap["raw"] = [DataTexture2D, Loader.BUFFER];
    	createMap["mipmaps"] = [DataTexture2D, Loader.BUFFER];
    	createMap["thdata"] = [TerrainHeightData, Loader.BUFFER];
    	createMap["lt"] = [TerrainRes, Laya3D.TERRAIN];
    	createMap["lani"] = [AnimationClip, Loader.BUFFER];
    	createMap["lav"] = [Avatar, Loader.JSON];
    	createMap["ani"] = [AnimationTemplet, Loader.BUFFER];//兼容接口
    
    资源加载基础流程
    public function load(url:String, type:String = null, cache:Boolean = true, group:String = null, ignoreCache:Boolean = false):void
    加载资源。加载错误会派发 Event.ERROR 事件,参数为错误信息。
    
    Parameters
    
    url:String — 资源地址。
     
    type:String (default = null) — (default = null)资源类型。可选值为:Loader.TEXT、Loader.JSON、Loader.XML、Loader.BUFFER、Loader.IMAGE、Loader.SOUND、Loader.ATLAS、Loader.FONT。如果为null,则根据文件后缀分析类型。
     
    cache:Boolean (default = true) — (default = true)是否缓存数据。
     
    group:String (default = null) — (default = null)分组名称。
     
    ignoreCache:Boolean (default = false) — (default = false)是否忽略缓存,强制重新加载。
    
    • 缓存url、type、cache等数据,供加载完成或者后续加载使用。
    • 如果资源已经加载过,并且没有设置ignoreCache则直接出发COMPLETE事件,通知加载完成。
    • 如果定制了加载方法,如Laya3D中注册的方法,则直接使用对应方法进行加载。
    • 根据type选择对应加载方法加载资源,如果没有传type,则会根据资源后缀名确定类型。
    • 资源加载完成后,触发onLoaded方法,将加载完的数据根据类型进行封装或者后续加载(如atlas类型加载完资源后,会解析配置,再去加载对应的图片)。
    • 调用complete方法,将data缓存在loader中,再将loader放入到完成队列。
    • 执行endload方法,缓存资源,通知COMPLETE事件,LoaderManager触发传入的complete方法。
    • 如果累计回调时长大于100毫秒时,延时一帧再执行后续loader的endload方法。
            /**
    		 * 加载完成。
    		 * @param	data 加载的数据。
    		 */
    		protected function complete(data:*):void {
    			this._data = data;
    			if (_customParse) {
    				event(Event.LOADED, data is Array ? [data] : data);
    			} else {
    				_loaders.push(this);
    				if (!_isWorking) checkNext();
    			}
    		}
    		
    		/** @private */
    		private static function checkNext():void {
    			_isWorking = true;
    			var startTimer:Number = Browser.now();
    			var thisTimer:Number = startTimer;
    			while (_startIndex < _loaders.length) {
    				thisTimer = Browser.now();
    				_loaders[_startIndex].endLoad();
    				_startIndex++;
    				//@防止单次回调事件太长,卡进程
    				if (Browser.now() - startTimer > maxTimeOut) {
    					console.warn("loader callback cost a long time:" + (Browser.now() - startTimer) + " url=" + _loaders[_startIndex - 1].url);
    					Laya.timer.frameOnce(1, null, checkNext);
    					return;
    				}
    			}
    			
    			_loaders.length = 0;
    			_startIndex = 0;
    			_isWorking = false;
    		}
    		
    		/**
    		 * 结束加载,处理是否缓存及派发完成事件 <code>Event.COMPLETE</code> 。
    		 * @param	content 加载后的数据
    		 */
    		public function endLoad(content:* = null):void {
    			content && (this._data = content);
    			if (this._cache) cacheRes(this._url, this._data);
    			
    			event(Event.PROGRESS, 1);
    			event(Event.COMPLETE, data is Array ? [data] : data);
    		
    		}
    
    图片资源加载
    • 后缀为png、jpg、jpeg以及类型为htmlimage或者nativeimage的资源,是使用图片类型加载。
    • 图片类型的加载使用过使用H5的Browser.window.Image方式加载。
      • 创建一个Browser.window.Image的实例。
      • 设置src、onload、onerror方法。
      • 使用imgCache缓存image对象,防止被gc掉。
      • 当图片被加载完时,会触发onload回调,清理image的onerror和onload方法,传递给下级。
    • nativeimage类型的图片,会直接将Image的数据传递下去。其他类型图片会使用HtmlImage(Canvas模式下)/WebGLImage(WebGL模式下)将原生Image数据包装,然后再传递给后续调用。
    		/**
    		 * @private
    		 * 加载图片资源。
    		 * @param	url 资源地址。
    		 */
    		protected function _loadImage(url:String):void {
    			url = URL.formatURL(url);
    			var _this:Loader = this;
    			var image:*;
    			function clear():void {
    				image.onload = null;
    				image.onerror = null;
    				delete imgCache[url]
    			}
    			
    			var onload:Function = function():void {
    				clear();
    				_this.onLoaded(image);
    			};
    			var onerror:Function = function():void {
    				clear();
    				_this.event(Event.ERROR, "Load image failed");
    			}
    			
    			if (_type === "nativeimage") {
    				image = new Browser.window.Image();
    				image.crossOrigin = "";
    				image.onload = onload;
    				image.onerror = onerror;
    				image.src = url;
    				//增加引用,防止垃圾回收
    				imgCache[url] = image;
    			} else {
    				new HTMLImage.create(url, {onload: onload, onerror: onerror, onCreate: function(img:*):void {
    					image = img;
    					//增加引用,防止垃圾回收
    					imgCache[url] = img;
    				}});
    			}
    		}
    
    文本类型加载
    • 简单类型如json、buffer等类型,直接通过http请求下载。
    • Atlas/Font类型,会先通过这种方式下载配置文件,再执行后续操作。
    			var contentType:String;
    			switch (type) {
    			case ATLAS: 
    				contentType = JSON;
    				break;
    			case FONT: 
    				contentType = XML;
    				break;
    			case PKM: 
    				contentType = BUFFER;
    				break
    			default: 
    				contentType = type;
    			}
    			if (preLoadedMap[url])
    			{
    				onLoaded(preLoadedMap[url]);
    			}else
    			{
    				if (!_http) 
    				{
    					_http = new HttpRequest();
    					_http.on(Event.PROGRESS, this, onProgress);
    					_http.on(Event.ERROR, this, onError);
    					_http.on(Event.COMPLETE, this, onLoaded);
    				}
    				_http.send(url, null, "get", contentType);
    			}
    			
    
    声音类型加载
    • 对声音资源的加载,Laya封装到Sound类里面。Laya支持三种sound类型:H5方式、web audio api方式、微信小游戏方式。
    • H5方式通过原生audio标签去加载声音。
    • web audio方式是通过http请求方式下载。
    • 微信小游戏是微信提供方式下载。
    • 声音加载完成后,外部接受的为Sound对象,而不是语音的数据。
    		/**
    		 * @private
    		 * 加载声音资源。
    		 * @param	url 资源地址。
    		 */
    		protected function _loadSound(url:String):void {
    			var sound:Sound = (new SoundManager._soundClass()) as Sound;
    			var _this:Loader = this;
    			
    			sound.on(Event.COMPLETE, this, soundOnload);
    			sound.on(Event.ERROR, this, soundOnErr);
    			sound.load(url);
    			
    			function soundOnload():void {
    				clear();
    				_this.onLoaded(sound);
    			}
    			function soundOnErr():void {
    				clear();
    				sound.dispose();
    				_this.event(Event.ERROR, "Load sound failed");
    			}
    			function clear():void {
    				sound.offAll();
    			}
    		}
    
    图集加载
    • 图集类型一般包含一份配置文件和一张或多张贴图。
    • 先用Http方式下载配置文件。并且设置当前类型为ATLAS类型。
    • 当配置文件下载完成后,解析meta字段,获取需要下载的图片地址,使用下载图片的方式下载对应图片。
    • 所有图片下载完成后,解析配置的frames,解析图集内包含的图片信息,为每个图片创建一个Texture,并将Texture放入到loadedMap中,key为图片原始路径。即使图片在图集中,也可以通过设置单张图片的url来获取图片资源。
    • 将图集里所有的图片的url已数组的形式存入atlasmap中,key为图集地址。
    if (type === ATLAS) {
    				//处理图集
    				if (!data.src && !data._setContext) {
    					//@处理.atlas文件
    					if (!_data) {
    						this._data = data;
    						//构造加载图片信息
    						if (data.meta && data.meta.image) {
    							//带图片信息的类型
    							var toloadPics:Array = data.meta.image.split(",");
    							var split:String = _url.indexOf("/") >= 0 ? "/" : "\";
    							var idx:int = _url.lastIndexOf(split);
    							var folderPath:String = idx >= 0 ? _url.substr(0, idx + 1) : "";
    							//idx = _url.indexOf("?");
    							//var ver:String;
    							//ver = idx >= 0 ? _url.substr(idx) : "";
    							for (var i:int = 0, len:int = toloadPics.length; i < len; i++) {
    								toloadPics[i] = folderPath + toloadPics[i];
    							}
    						} else {
    							//不带图片信息
    							toloadPics = [_url.replace(".json", ".png")];
    						}
    						
    						//保证图集的正序加载
    						toloadPics.reverse();
    						data.toLoads = toloadPics;
    						data.pics = [];
    					}
    					event(Event.PROGRESS, 0.3 + 1 / toloadPics.length * 0.6);
    					return _loadImage(toloadPics.pop());
    				} else {
    					//处理图片
    					_data.pics.push(data);
    					if (_data.toLoads.length > 0) {
    						event(Event.PROGRESS, 0.3 + 1 / _data.toLoads.length * 0.6);
    						//有图片未加载
    						return _loadImage(_data.toLoads.pop());
    					}
    					var frames:Object = this._data.frames;
    					var cleanUrl:String = this._url.split("?")[0];
    					var directory:String = (this._data.meta && this._data.meta.prefix) ? this._data.meta.prefix : cleanUrl.substring(0, cleanUrl.lastIndexOf(".")) + "/";
    					var pics:Array = _data.pics;
    					var atlasURL:String = URL.formatURL(this._url);
    					var map:Array = atlasMap[atlasURL] || (atlasMap[atlasURL] = []);
    					map.dir = directory;
    					var scaleRate:Number = 1;
    					if (this._data.meta && this._data.meta.scale && this._data.meta.scale != 1)
    					{
    						scaleRate = parseFloat(this._data.meta.scale);
    						for (var name:String in frames) {
    							var obj:Object = frames[name];//取对应的图
    							var tPic:Object = pics[obj.frame.idx ? obj.frame.idx : 0];//是否释放
    							var url:String = URL.formatURL(directory + name);
    							tPic.scaleRate = scaleRate;
    							cacheRes(url, Texture.create(tPic, obj.frame.x, obj.frame.y, obj.frame.w, obj.frame.h, obj.spriteSourceSize.x, obj.spriteSourceSize.y, obj.sourceSize.w, obj.sourceSize.h));
    							loadedMap[url].url = url;
    							map.push(url);
    						}
    					}else{
    						for (name in frames) {
    							obj = frames[name];//取对应的图
    							tPic = pics[obj.frame.idx ? obj.frame.idx : 0];//是否释放
    							url = URL.formatURL(directory + name);
    							cacheRes(url, Texture.create(tPic, obj.frame.x, obj.frame.y, obj.frame.w, obj.frame.h, obj.spriteSourceSize.x, obj.spriteSourceSize.y, obj.sourceSize.w, obj.sourceSize.h));
    							loadedMap[url].url = url;
    							map.push(url);
    						}
    					}
    					delete _data.pics;
    					
    					/*[IF-FLASH]*/
    					map.sort();
    					complete(this._data);
    				}
    
    字体资源
    • Laya有两种字体,一种是TTF字体一种是bitmapfont。
    • 加载bitmapfont是先加载配置文件,再将.fnt改为.png去加载图片。资源都加在完成后,使用BitmapFont去解析图集字体信息。
    • TTF字体使用TTFLoader去加载,通过根据情况有多种加载方式,有使用FontFace方式,也有通过CSS等方式等。
                var tArr:Array = fontPath.split(".ttf")[0].split("/");
    			fontName = tArr[tArr.length - 1];
    			if (Browser.window.conch)
    			{
    				_loadConch();
    			}else
    			if (Browser.window.FontFace) {
    				this._loadWithFontFace()
    			}
    			else {
    				this._loadWithCSS();
    			}
    
    资源清理方式
    		/**
    		 * 清理指定资源地址的缓存。
    		 * 如果是Texture,则采用引用计数方式销毁,【注意】如果图片本身在自动合集里面(默认图片小于512*512),内存是不能被销毁的,此图片会被大图合集管理器管理
    		 * @param	url 资源地址。
    		 * @param	forceDispose 是否强制销毁,有些资源是采用引用计数方式销毁,如果forceDispose=true,则忽略引用计数,直接销毁,比如Texture,默认为false
    		 */
    		public static function clearRes(url:String, forceDispose:Boolean = false):void {
    			url = URL.formatURL(url);
    			//删除图集
    			var arr:Array = getAtlas(url);
    			if (arr) {
    				for (var i:int = 0, n:int = arr.length; i < n; i++) {
    					var resUrl:String = arr[i];
    					var tex:Texture = getRes(resUrl);
    					delete loadedMap[resUrl];
    					if (tex) tex.destroy(forceDispose);
    					
    				}
    				arr.length = 0;
    				delete atlasMap[url];
    				delete loadedMap[url];
    			} else {
    				var res:* = loadedMap[url];
    				if (res) {
    					delete loadedMap[url];
    					if (res is Texture && res.bitmap) Texture(res).destroy(forceDispose);				
    				}
    			}
    		}
    		
    		/**
    		 * 销毁Texture使用的图片资源,保留texture壳,如果下次渲染的时候,发现texture使用的图片资源不存在,则会自动恢复
    		 * 相比clearRes,clearTextureRes只是清理texture里面使用的图片资源,并不销毁texture,再次使用到的时候会自动恢复图片资源
    		 * 而clearRes会彻底销毁texture,导致不能再使用;clearTextureRes能确保立即销毁图片资源,并且不用担心销毁错误,clearRes则采用引用计数方式销毁
    		 * 【注意】如果图片本身在自动合集里面(默认图片小于512*512),内存是不能被销毁的,此图片被大图合集管理器管理
    		 * @param	url	图集地址或者texture地址,比如 Loader.clearTextureRes("res/atlas/comp.atlas"); Loader.clearTextureRes("hall/bg.jpg");	
    		 */
    		public static function clearTextureRes(url:String):void {
    			url = URL.formatURL(url);
    			//删除图集
    			var arr:Array = Loader.getAtlas(url);
    			var res:* = (arr && arr.length>0) ? Loader.getRes(arr[0]) : Loader.getRes(url);
    			if (res && res.bitmap) {
    				if (Render.isConchApp) {
    					//兼容老版本
    					if (res.bitmap.source.releaseTexture) {
    						res.bitmap.source.releaseTexture();
    					}
    				} else if (res.bitmap._atlaser == null) {
    					res.bitmap.releaseResource(true);
    				}
    			}
    		}
    
  • 相关阅读:
    hadoop系列二:HDFS文件系统的命令及JAVA客户端API
    hadoop系列一:hadoop集群安装
    解决tomcat下面部署多个项目log4j的日志输出会集中输出到一个项目中的问题
    HandlerMethodArgumentResolver数据绑定无效
    MyBatis 元素类型为 "configuration" 的内容必须匹配 ".....
    jquery.uploadify 异常 “__flash__removeCallback”未定义
    fusioncharts图例(legend)属性
    Flex Error #2156问题
    HTML注释引起的问题
    Asp.net Mvc4 使用Cas单点登录
  • 原文地址:https://www.cnblogs.com/chiguozi/p/9630543.html
Copyright © 2020-2023  润新知