1 /** 2 * Hilo 3 * Copyright 2015 alibaba.com 4 * Licensed under the MIT License 5 */ 6 7 /** 8 * @language=zh 9 * <iframe src='../../../examples/Sprite.html?noHeader' width = '550' height = '400' scrolling='no'></iframe> 10 * <br/> 11 * @class 动画精灵类。 12 * @augments View 13 * @module hilo/view/Sprite 14 * @requires hilo/core/Hilo 15 * @requires hilo/core/Class 16 * @requires hilo/view/View 17 * @requires hilo/view/Drawable 18 * @param properties 创建对象的属性参数。可包含此类所有可写属性。此外还包括: 19 * <ul> 20 * <li><b>frames</b> - 精灵动画的帧数据对象。</li> 21 * </ul> 22 * @property {number} currentFrame 当前播放帧的索引。从0开始。只读属性。 23 * @property {boolean} paused 判断精灵是否暂停。默认为false。 24 * @property {boolean} loop 判断精灵是否可以循环播放。默认为true。 25 * @property {boolean} timeBased 指定精灵动画是否是以时间为基准。默认为false,即以帧为基准。 26 * @property {number} interval 精灵动画的帧间隔。如果timeBased为true,则单位为毫秒,否则为帧数。 27 */ 28 var Sprite = Class.create(/** @lends Sprite.prototype */{ 29 Extends: View, 30 constructor: function(properties){ 31 properties = properties || {}; 32 this.id = this.id || properties.id || Hilo.getUid("Sprite"); 33 Sprite.superclass.constructor.call(this, properties); 34 35 this._frames = []; 36 this._frameNames = {}; 37 this.drawable = new Drawable(); 38 if(properties.frames) this.addFrame(properties.frames); 39 }, 40 41 _frames: null, //所有帧的集合 Collection of all frames 42 _frameNames: null, //带名字name的帧的集合 Collection of frames that with name 43 _frameElapsed: 0, //当前帧持续的时间或帧数 Elapsed time of current frame. 44 _firstRender: true, //标记是否是第一次渲染 Is the first render. 45 46 paused: false, 47 loop: true, 48 timeBased: false, 49 interval: 1, 50 currentFrame: 0, //当前帧的索引 Index of current frame 51 52 /** 53 * @language=zh 54 * 返回精灵动画的总帧数。 55 * @returns {Uint} 精灵动画的总帧数。 56 */ 57 getNumFrames: function(){ 58 return this._frames ? this._frames.length : 0; 59 }, 60 61 /** 62 * @language=zh 63 * 往精灵动画序列中增加帧。 64 * @param {Object} frame 要增加的精灵动画帧数据。 65 * @param {Int} startIndex 开始增加帧的索引位置。若不设置,默认为在末尾添加。 66 * @returns {Sprite} Sprite对象本身。 67 */ 68 addFrame: function(frame, startIndex){ 69 var start = startIndex != null ? startIndex : this._frames.length; 70 if(frame instanceof Array){ 71 for(var i = 0, len = frame.length; i < len; i++){ 72 this.setFrame(frame[i], start + i); 73 } 74 }else{ 75 this.setFrame(frame, start); 76 } 77 return this; 78 }, 79 80 /** 81 * @language=zh 82 * 设置精灵动画序列指定索引位置的帧。 83 * @param {Object} frame 要设置的精灵动画帧数据。 84 * @param {Int} index 要设置的索引位置。 85 * @returns {Sprite} Sprite对象本身。 86 */ 87 setFrame: function(frame, index){ 88 var frames = this._frames, 89 total = frames.length; 90 index = index < 0 ? 0 : index > total ? total : index; 91 frames[index] = frame; 92 if(frame.name) this._frameNames[frame.name] = frame; 93 if(index == 0 && !this.width || !this.height){ 94 this.width = frame.rect[2]; 95 this.height = frame.rect[3]; 96 } 97 return this; 98 }, 99 100 /** 101 * @language=zh 102 * 获取精灵动画序列中指定的帧。 103 * @param {Object} indexOrName 要获取的帧的索引位置或别名。 104 * @returns {Object} 精灵帧对象。 105 */ 106 getFrame: function(indexOrName){ 107 if(typeof indexOrName === 'number'){ 108 var frames = this._frames; 109 if(indexOrName < 0 || indexOrName >= frames.length) return null; 110 return frames[indexOrName]; 111 } 112 return this._frameNames[indexOrName]; 113 }, 114 115 /** 116 * @language=zh 117 * 获取精灵动画序列中指定帧的索引位置。 118 * @param {Object} frameValue 要获取的帧的索引位置或别名。 119 * @returns {Object} 精灵帧对象。 120 */ 121 getFrameIndex: function(frameValue){ 122 var frames = this._frames, 123 total = frames.length, 124 index = -1; 125 if(typeof frameValue === 'number'){ 126 index = frameValue; 127 }else{ 128 var frame = typeof frameValue === 'string' ? this._frameNames[frameValue] : frameValue; 129 if(frame){ 130 for(var i = 0; i < total; i++){ 131 if(frame === frames[i]){ 132 index = i; 133 break; 134 } 135 } 136 } 137 } 138 return index; 139 }, 140 141 /** 142 * @language=zh 143 * 播放精灵动画。 144 * @returns {Sprite} Sprite对象本身。 145 */ 146 play: function(){ 147 this.paused = false; 148 return this; 149 }, 150 151 /** 152 * @language=zh 153 * 暂停播放精灵动画。 154 * @returns {Sprite} Sprite对象本身。 155 */ 156 stop: function(){ 157 this.paused = true; 158 return this; 159 }, 160 161 /** 162 * @language=zh 163 * 跳转精灵动画到指定的帧。 164 * @param {Object} indexOrName 要跳转的帧的索引位置或别名。 165 * @param {Boolean} pause 指示跳转后是否暂停播放。 166 * @returns {Sprite} Sprite对象本身。 167 */ 168 goto: function(indexOrName, pause){ 169 var total = this._frames.length, 170 index = this.getFrameIndex(indexOrName); 171 172 this.currentFrame = index < 0 ? 0 : index >= total ? total - 1 : index; 173 this.paused = pause; 174 this._firstRender = true; 175 return this; 176 }, 177 178 /** 179 * @language=zh 180 * 渲染方法。 181 * @private 182 */ 183 _render: function(renderer, delta){ 184 var lastFrameIndex = this.currentFrame, frameIndex; 185 186 if(this._firstRender){ 187 frameIndex = lastFrameIndex; 188 this._firstRender = false; 189 }else{ 190 frameIndex = this._nextFrame(delta); 191 } 192 193 if(frameIndex != lastFrameIndex){ 194 this.currentFrame = frameIndex; 195 var callback = this._frames[frameIndex].callback; 196 callback && callback.call(this); 197 } 198 199 //NOTE: it will be deprecated, don't use it. 200 if(this.onEnterFrame) this.onEnterFrame(frameIndex); 201 202 this.drawable.init(this._frames[frameIndex]); 203 Sprite.superclass._render.call(this, renderer, delta); 204 }, 205 206 /** 207 * @language=zh 208 * @private 209 */ 210 _nextFrame: function(delta){ 211 var frames = this._frames, 212 total = frames.length, 213 frameIndex = this.currentFrame, 214 frame = frames[frameIndex], 215 duration = frame.duration || this.interval, 216 elapsed = this._frameElapsed; 217 218 //calculate the current frame elapsed frames/time 219 var value = (frameIndex == 0 && !this.drawable) ? 0 : elapsed + (this.timeBased ? delta : 1); 220 elapsed = this._frameElapsed = value < duration ? value : 0; 221 222 if(frame.stop || !this.loop && frameIndex >= total - 1){ 223 this.stop(); 224 } 225 226 if(!this.paused && elapsed == 0){ 227 if(frame.next != null){ 228 //jump to the specified frame 229 frameIndex = this.getFrameIndex(frame.next); 230 }else if(frameIndex >= total - 1){ 231 //at the end of the frames, go back to first frame 232 frameIndex = 0; 233 }else if(this.drawable){ 234 //normal go forward to next frame 235 frameIndex++; 236 } 237 } 238 239 return frameIndex; 240 }, 241 242 /** 243 * @language=zh 244 * 设置指定帧的回调函数。即每当播放头进入指定帧时调用callback函数。若callback为空,则会删除回调函数。 245 * @param {Int|String} frame 要指定的帧的索引位置或别名。 246 * @param {Function} callback 指定回调函数。 247 * @returns {Sprite} 精灵本身。 248 */ 249 setFrameCallback: function(frame, callback){ 250 frame = this.getFrame(frame); 251 if(frame) frame.callback = callback; 252 return this; 253 }, 254 255 /** 256 * @language=zh 257 * 精灵动画的播放头进入新帧时的回调方法。默认值为null。此方法已废弃,请使用addFrameCallback方法。 258 * @type Function 259 * @deprecated 260 */ 261 onEnterFrame: null 262 263 }); 264