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);
                }
            }
        }

原文地址:https://www.cnblogs.com/chiguozi/p/9630543.html

时间: 2024-10-09 23:00:37

Laya资源加载小记的相关文章

让我们再聊聊浏览器资源加载优化

让我们再聊聊浏览器资源加载优化 让我们再聊聊浏览器资源加载优化

各浏览器对页面外部资源加载的策略

这个总结来源于一次优化的请求,最初某个页面的加载十分缓慢,load事件迟迟无法触发,因此希望可以通过对静态文件分域名等方式对页面的外部资源进行优化,拿得load事件尽可能早地触发. 于是我查看了页面的源码,并对外部资源进行了整理,基于下面2个理念画出了一个推测的瀑布图: 1.浏览器对同一个域只能并发2个HTTP请求 – 网上盛传已久.2.javascript文件的加载会阻塞浏览器其他资源的加载 – 同样网上盛传已久. 然而,当我看到各浏览器中实际的瀑布图时,我知道自己又犯了一个简单的错误:太过相

Webkit资源加载介绍

一.webkit资源分类 webkit中有多种资源,大致分为以下几种: HTML文本 CSS样式文本 - CachedCSSStyleSheet 字体 - CachedFont 图片 - CachedImage 只读资源 - CachedRawResource JavaScript文本 - CachedScript SVG - CachedSVGDocument 视频字幕 - CachedTextTrack XSL样式表 - CachedXSLStyleSheet 类图如下: HTML文本是网页

Unity3d热更新全书-资源加载(一)从AssetBundle说起

Unity3D动态下载资源,有没有解?有,AssetBundle就是通用解,任何一本书都会花大幅篇章来介绍AssetBundle. 我们也来说说AssetBundle 我们试全面的分析一下Unity3D提供的资源加载机制 1.Resources//内嵌资源,使用方法Resources.Load,可以加载任意种类的资源,不能动态修改,卒. 2.StreamingAssets//随包资源,使用方法IO或WWW.Load.WWW.Load可以加载任意种类资源,IO仅限bytes 和 text. 3.W

Cocos2d-x 3.0多线程异步资源加载

Cocos2d-x从2.x版本到上周刚刚才发布的Cocos2d-x 3.0 Final版,其引擎驱动核心依旧是一个单线程的"死循环",一旦某一帧遇到了"大活儿",比如Size很大的纹理资源加载或网络IO或大量计算,画面将 不可避免出现卡顿以及响应迟缓的现象.从古老的Win32 GUI编程那时起,Guru们就告诉我们:别阻塞主线程(UI线程),让Worker线程去做那些"大活儿"吧. 手机游戏,即便是休闲类的小游戏,往往也涉及大量纹理资源.音视频资

libgdx学习记录16——资源加载器AssetManager

AssetManager用于对游戏中的资源进行加载.当游戏中资源(图片.背景音乐等)较大时,加载时会需要较长时间,可能会阻塞渲染线程,使用AssetManager可以解决此类问题. 主要优点: 1. 大多数资源加载器AssetLoader都是异步加载,可以避免阻塞渲染线程. 2. 通过引用计数来进行释放资源. 3. 通过一个对象来管理所有其他资源. 主要函数: load(path,type)加载某个路径的资源文件,后面type指定所要加载的资源类型.这个函数只是将资源文件加入到资源队列中,并不会

《Spring揭秘》(十) ---- ApplicationContext之统一资源加载策略

Spring的resource Spring框架内部使用Resource接口作为所有资源的抽象和接口.例如: BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("...")); ClassPathResource就是Resource的一个特定类型的实现,代表的实位于Classpath中的资源. Resource接口可以根据资源的不同类型,或者资源所处的不同场合,给出相应的具体实现: a. ByteArr

chromium kernel资源加载、解析、三树合成浅析(chromium39)

每次尝试去看看chromium kernel中具体逻辑的实现的时候,都会费一些时间去看代码,找逻辑.当然了,网上很多资料可以参看,但是每次看完这些资料,我都会要问一问:确实如此么?新版本的kernel是否这块逻辑更改了呢? 所以,为了让自己释惑,还是要亲自去看源码,一点点查看调用堆栈.然后再能在整体上理解下kernel的原理. 最近了看了看chromium kernel中,blink kernel part的网页的加载.html解析.以及三树(Dom tree. Render Tree.Rend

也许是被误解的浏览器资源加载优化

几乎每一个前端程序员都知道应该把script标签放在页面底部.关于这个经典的论述可以追溯到Nicholas的 High Performance Javasript 这本书的第一章Loading and Execution中,他之所以建议这么做是因为: Put all <script> tags at the bottom of the page, just inside of the closing </body> tag. This ensures that the page c