1 /** 2 * Hilo 3 * Copyright 2015 alibaba.com 4 * Licensed under the MIT License 5 */ 6 7 /** 8 * @class TextureAtlas纹理集是将许多小的纹理图片整合到一起的一张大图。这个类可根据一个纹理集数据读取纹理小图、精灵动画等。 9 * @param {Object} atlasData 纹理集数据。它可包含如下数据: 10 * <ul> 11 * <li><b>image</b> - 纹理集图片。必需。</li> 12 * <li><b>width</b> - 纹理集图片宽度。若frames数据为Object时,此属性必需。</li> 13 * <li><b>height</b> - 纹理集图片高度。若frames数据为Object时,此属性必需。</li> 14 * <li><b>frames</b> - 纹理集帧数据,可以是Array或Object。必需。 15 * <ul> 16 * <li>若为Array,则每项均为一个纹理图片帧数据,如:[[0, 0, 50, 50], [0, 50, 50, 50]。</li> 17 * <li>若为Object,则需包含frameWidth(帧宽)、frameHeight(帧高)、numFrames(帧数) 属性。</li> 18 * </ul> 19 * </li> 20 * <li><b>sprites</b> - 纹理集精灵动画定义,其每个值均定义一个精灵。为Object对象。可选。 21 * <ul> 22 * <li>若为Number,即此精灵只包含一帧,此帧为帧数据中索引为当前值的帧。如:sprites:{'foo':1}。</li> 23 * <li>若为Array,则每项均为一个帧的索引值。如:sprites:{'foo':[0, 1, 2, 3]}。</li> 24 * <li>若为Object,则需包含from(起始帧索引值)、to(末帧索引值) 属性。</li> 25 * </ul> 26 * </li> 27 * </ul> 28 * @module hilo/util/TextureAtlas 29 * @requires hilo/core/Class 30 */ 31 var TextureAtlas = (function(){ 32 33 return Class.create(/** @lends TextureAtlas.prototype */{ 34 constructor: function(atlasData){ 35 this._frames = parseTextureFrames(atlasData); 36 this._sprites = parseTextureSprites(atlasData, this._frames); 37 }, 38 39 _frames: null, 40 _sprites: null, 41 42 /** 43 * 获取指定索引位置index的帧数据。 44 * @param {Int} index 要获取帧的索引位置。 45 * @returns {Object} 帧数据。 46 */ 47 getFrame: function(index){ 48 var frames = this._frames; 49 return frames && frames[index]; 50 }, 51 52 /** 53 * 获取指定id的精灵数据。 54 * @param {String} id 要获取精灵的id。 55 * @returns {Object} 精灵数据。 56 */ 57 getSprite: function(id){ 58 var sprites = this._sprites; 59 return sprites && sprites[id]; 60 }, 61 62 Statics: /** @lends TextureAtlas */ { 63 /** 64 * 创建精灵帧数据的快捷方法。 65 * @param {String|Array} name 动画名称|一组动画数据 66 * @param {String} frames 帧数据 eg:"0-5"代表第0到第5帧 67 * @param {Number} w 每帧的宽 68 * @param {Number} h 每帧的高 69 * @param {Bollean} loop 是否循环 70 * @param {Number} duration 每帧间隔 默认单位帧, 如果sprite的timeBased为true则单位是毫秒,默认一帧 71 * @example 72 * //方式一 单个动画 73 * createSpriteFrames("walk", "0-5,8,9", meImg, 55, 88, true, 1); 74 * //方式二 多组动画 75 * createSpriteFrames([ 76 * ["walk", "0-5,8,9", meImg, 55, 88, true, 1], 77 * ["jump", "0-5", meImg, 55, 88, false, 1] 78 * ]); 79 */ 80 createSpriteFrames:function(name, frames, img, w, h, loop, duration){ 81 if(Object.prototype.toString.call(name) === "[object Array]"){ 82 var frames = []; 83 for(var i = 0, l = name.length;i < l;i ++){ 84 frames = frames.concat(this.createSpriteFrames.apply(this, name[i])); 85 } 86 return frames; 87 } 88 else{ 89 if(typeof(frames) === "string"){ 90 var all = frames.split(","); 91 frames = []; 92 for(var j = 0, jl = all.length;j < jl;j ++){ 93 var temp = all[j].split("-"); 94 if(temp.length == 1){ 95 frames.push(parseInt(temp[0])); 96 } 97 else{ 98 for(var i = parseInt(temp[0]), l = parseInt(temp[1]);i <= l;i ++){ 99 frames.push(i); 100 } 101 } 102 } 103 } 104 105 var col = Math.floor(img.width/w); 106 for(var i = 0;i < frames.length;i ++){ 107 var n = frames[i]; 108 frames[i] = { 109 rect:[w*(n%col), h*Math.floor(n/col), w, h], 110 image:img, 111 duration:duration 112 } 113 } 114 frames[0].name = name; 115 if(loop){ 116 frames[frames.length-1].next = name; 117 } 118 else{ 119 frames[frames.length-1].stop = true; 120 } 121 return frames; 122 } 123 } 124 } 125 }); 126 127 /** 128 * 解析纹理集帧数据。 129 * @private 130 */ 131 function parseTextureFrames(atlasData){ 132 var frameData = atlasData.frames; 133 if(!frameData) return null; 134 135 var frames = [], obj; 136 137 if(frameData instanceof Array){ //frames by array 138 for(var i = 0, len = frameData.length; i < len; i++){ 139 obj = frameData[i]; 140 frames[i] = { 141 image: atlasData.image, 142 rect: obj 143 }; 144 } 145 }else{ //frames by object 146 var frameWidth = frameData.frameWidth; 147 var frameHeight = frameData.frameHeight; 148 var cols = atlasData.width / frameWidth | 0; 149 var rows = atlasData.height / frameHeight | 0; 150 var numFrames = frameData.numFrames || cols * rows; 151 for(var i = 0; i < numFrames; i++){ 152 frames[i] = { 153 image: atlasData.image, 154 rect: [i%cols*frameWidth, (i/cols|0)*frameHeight, frameWidth, frameHeight] 155 } 156 } 157 } 158 159 return frames; 160 } 161 162 /** 163 * 解析精灵数据。 164 * @private 165 */ 166 function parseTextureSprites(atlasData, frames){ 167 var spriteData = atlasData.sprites; 168 if(!spriteData) return null; 169 170 var sprites = {}, sprite, spriteFrames, spriteFrame; 171 172 for(var s in spriteData){ 173 sprite = spriteData[s]; 174 if(isNumber(sprite)){ //single frame 175 spriteFrames = translateSpriteFrame(frames[sprite]); 176 }else if(sprite instanceof Array){ //frames by array 177 spriteFrames = []; 178 for(var i = 0, len = sprite.length; i < len; i++){ 179 var spriteObj = sprite[i], frameObj; 180 if(isNumber(spriteObj)){ 181 spriteFrame = translateSpriteFrame(frames[spriteObj]); 182 }else{ 183 frameObj = spriteObj.rect; 184 if(isNumber(frameObj)) frameObj = frames[spriteObj.rect]; 185 spriteFrame = translateSpriteFrame(frameObj, spriteObj); 186 } 187 spriteFrames[i] = spriteFrame; 188 } 189 }else{ //frames by object 190 spriteFrames = []; 191 for(var i = sprite.from; i <= sprite.to; i++){ 192 spriteFrames[i - sprite.from] = translateSpriteFrame(frames[i], sprite[i]); 193 } 194 } 195 sprites[s] = spriteFrames; 196 } 197 198 return sprites; 199 } 200 201 function translateSpriteFrame(frameObj, spriteObj){ 202 var spriteFrame = { 203 image: frameObj.image, 204 rect: frameObj.rect 205 }; 206 207 if(spriteObj){ 208 spriteFrame.name = spriteObj.name || null; 209 spriteFrame.duration = spriteObj.duration || 0; 210 spriteFrame.stop = !!spriteObj.stop; 211 spriteFrame.next = spriteObj.next || null; 212 } 213 214 return spriteFrame; 215 } 216 217 function isNumber(value){ 218 return typeof value === 'number'; 219 } 220 221 })();