Hilo/docs/api-en/code/util/TextureAtlas.js
2017-12-11 14:05:40 +08:00

224 lines
7.6 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* Hilo
* Copyright 2015 alibaba.com
* Licensed under the MIT License
*/
/**
* @class TextureAtlas纹理集是将许多小的纹理图片整合到一起的一张大图。这个类可根据一个纹理集数据读取纹理小图、精灵动画等。
* @param {Object} atlasData 纹理集数据。它可包含如下数据:
* <ul>
* <li><b>image</b> - 纹理集图片。必需。</li>
* <li><b>width</b> - 纹理集图片宽度。若frames数据为Object时此属性必需。</li>
* <li><b>height</b> - 纹理集图片高度。若frames数据为Object时此属性必需。</li>
* <li><b>frames</b> - 纹理集帧数据可以是Array或Object。必需。
* <ul>
* <li>若为Array则每项均为一个纹理图片帧数据[[0, 0, 50, 50], [0, 50, 50, 50]。</li>
* <li>若为Object则需包含frameWidth(帧宽)、frameHeight(帧高)、numFrames(帧数) 属性。</li>
* </ul>
* </li>
* <li><b>sprites</b> - 纹理集精灵动画定义其每个值均定义一个精灵。为Object对象。可选。
* <ul>
* <li>若为Number即此精灵只包含一帧此帧为帧数据中索引为当前值的帧。如sprites:{'foo':1}。</li>
* <li>若为Array则每项均为一个帧的索引值。如sprites:{'foo':[0, 1, 2, 3]}。</li>
* <li>若为Object则需包含from(起始帧索引值)、to(末帧索引值) 属性。</li>
* </ul>
* </li>
* </ul>
* @module hilo/util/TextureAtlas
* @requires hilo/core/Class
*/
var TextureAtlas = (function(){
return Class.create(/** @lends TextureAtlas.prototype */{
constructor: function(atlasData){
this._frames = parseTextureFrames(atlasData);
this._sprites = parseTextureSprites(atlasData, this._frames);
},
_frames: null,
_sprites: null,
/**
* 获取指定索引位置index的帧数据。
* @param {Int} index 要获取帧的索引位置。
* @returns {Object} 帧数据。
*/
getFrame: function(index){
var frames = this._frames;
return frames && frames[index];
},
/**
* 获取指定id的精灵数据。
* @param {String} id 要获取精灵的id。
* @returns {Object} 精灵数据。
*/
getSprite: function(id){
var sprites = this._sprites;
return sprites && sprites[id];
},
Statics: /** @lends TextureAtlas */ {
/**
* Shorthand method to create spirte frames
* @param {String|Array} name Name of one animation|a group of animation
* @param {String} frames Frames message, eg:"0-5" means frame 0 to frame 5.
* @param {Number} w The width of each frame.
* @param {Number} h The height of each frame.
* @param {Boolean} loop Is play in loop.
* @param {Number} duration The time between each frame. default value is 1 (Frame), but if timeBased is true, default value will be duration(milli-second).
* @example
* //demo1 make one animation
* createSpriteFrames("walk", "0-5,8,9", meImg, 55, 88, true, 1);
* //demo2 make a group of animation
* createSpriteFrames([
* ["walk", "0-5,8,9", meImg, 55, 88, true, 1],
* ["jump", "0-5", meImg, 55, 88, false, 1]
* ]);
*/
createSpriteFrames:function(name, frames, img, w, h, loop, duration){
var i, l;
if(Object.prototype.toString.call(name) === "[object Array]"){
var res = [];
for(i = 0, l = name.length;i < l;i ++){
res = res.concat(this.createSpriteFrames.apply(this, name[i]));
}
return res;
}
else{
if(typeof(frames) === "string"){
var all = frames.split(",");
frames = [];
for(var j = 0, jl = all.length;j < jl;j ++){
var temp = all[j].split("-");
if(temp.length == 1){
frames.push(parseInt(temp[0]));
}
else{
for(i = parseInt(temp[0]), l = parseInt(temp[1]);i <= l;i ++){
frames.push(i);
}
}
}
}
var col = Math.floor(img.width/w);
for(i = 0;i < frames.length;i ++){
var n = frames[i];
frames[i] = {
rect:[w*(n%col), h*Math.floor(n/col), w, h],
image:img,
duration:duration
};
}
frames[0].name = name;
if(loop){
frames[frames.length-1].next = name;
}
else{
frames[frames.length-1].stop = true;
}
return frames;
}
}
}
});
/**
* Parse texture frames
* @private
*/
function parseTextureFrames(atlasData){
var i, len;
var frameData = atlasData.frames;
if(!frameData) return null;
var frames = [], obj;
if(frameData instanceof Array){ //frames by array
for(i = 0, len = frameData.length; i < len; i++){
obj = frameData[i];
frames[i] = {
image: atlasData.image,
rect: obj
};
}
}else{ //frames by object
var frameWidth = frameData.frameWidth;
var frameHeight = frameData.frameHeight;
var cols = atlasData.width / frameWidth | 0;
var rows = atlasData.height / frameHeight | 0;
var numFrames = frameData.numFrames || cols * rows;
for(i = 0; i < numFrames; i++){
frames[i] = {
image: atlasData.image,
rect: [i%cols*frameWidth, (i/cols|0)*frameHeight, frameWidth, frameHeight]
};
}
}
return frames;
}
/**
* Parse texture sprites
* @private
*/
function parseTextureSprites(atlasData, frames){
var i, len;
var spriteData = atlasData.sprites;
if(!spriteData) return null;
var sprites = {}, sprite, spriteFrames, spriteFrame;
for(var s in spriteData){
sprite = spriteData[s];
if(isNumber(sprite)){ //single frame
spriteFrames = translateSpriteFrame(frames[sprite]);
}else if(sprite instanceof Array){ //frames by array
spriteFrames = [];
for(i = 0, len = sprite.length; i < len; i++){
var spriteObj = sprite[i], frameObj;
if(isNumber(spriteObj)){
spriteFrame = translateSpriteFrame(frames[spriteObj]);
}else{
frameObj = spriteObj.rect;
if(isNumber(frameObj)) frameObj = frames[spriteObj.rect];
spriteFrame = translateSpriteFrame(frameObj, spriteObj);
}
spriteFrames[i] = spriteFrame;
}
}else{ //frames by object
spriteFrames = [];
for(i = sprite.from; i <= sprite.to; i++){
spriteFrames[i - sprite.from] = translateSpriteFrame(frames[i], sprite[i]);
}
}
sprites[s] = spriteFrames;
}
return sprites;
}
function translateSpriteFrame(frameObj, spriteObj){
var spriteFrame = {
image: frameObj.image,
rect: frameObj.rect
};
if(spriteObj){
spriteFrame.name = spriteObj.name || null;
spriteFrame.duration = spriteObj.duration || 0;
spriteFrame.stop = !!spriteObj.stop;
spriteFrame.next = spriteObj.next || null;
}
return spriteFrame;
}
function isNumber(value){
return typeof value === 'number';
}
})();