1 2 /** 3 * @class 动画精灵类。 4 * @augments View 5 * @module hilo/view/Sprite 6 * @requires hilo/core/Hilo 7 * @requires hilo/core/Class 8 * @requires hilo/view/View 9 * @requires hilo/view/Drawable 10 * @param properties 创建对象的属性参数。可包含此类所有可写属性。此外还包括: 11 * <ul> 12 * <li><b>frames</b> - 精灵动画的帧数据对象。</li> 13 * </ul> 14 * @property {number} currentFrame 当前播放帧的索引。从0开始。 15 * @property {number} numFrames 精灵动画的总帧数。 16 * @property {boolean} paused 判断精灵是否暂停。默认为false。 17 * @property {boolean} loop 判断精灵是否可以循环播放。默认为true。 18 * @property {boolean} timeBased 指定精灵动画是否是以时间为基准。默认为false,即以帧为基准。 19 * @property {number} interval 精灵动画的帧间隔。如果timeBased为true,则单位为毫秒,否则为帧数。 20 */ 21 var Sprite = Class.create(/** @lends Sprite.prototype */{ 22 Extends: View, 23 constructor: function Sprite(properties){ 24 properties = properties || {}; 25 this.id = this.id || properties.id || Hilo.getUid("Sprite"); 26 Sprite.superclass.constructor.call(this, properties); 27 28 this._frames = []; 29 this._frameNames = {}; 30 this.drawable = new Drawable(); 31 if(properties.frames) this.addFrame(properties.frames); 32 }, 33 34 _frames: null, //所有帧的集合 35 _frameNames: null, //带名字name的帧的集合 36 _frameElapsed: 0, //当前帧持续的时间或帧数 37 _currentFrame: 0, //当前帧的索引 38 39 paused: false, 40 loop: true, 41 timeBased: false, 42 interval: 1, 43 currentFrame: { 44 get: function(){ 45 return this._currentFrame; 46 } 47 }, 48 numFrames: { 49 get: function(){ 50 return this._frames ? this._frames.length : 0; 51 } 52 }, 53 54 /** 55 * 往精灵动画序列中增加帧。 56 * @param {Object} frame 要增加的精灵动画帧数据。 57 * @returns {Sprite} Sprite对象本身。 58 */ 59 addFrame: function(frame){ 60 var total = this._frames.length; 61 if(frame instanceof Array){ 62 for(var i = 0, len = frame.length; i < len; i++){ 63 this.setFrame(frame[i], total + i); 64 } 65 }else{ 66 this.setFrame(frame, total); 67 } 68 return this; 69 }, 70 71 /** 72 * 设置精灵动画序列指定索引位置的帧。 73 * @param {Object} frame 要设置的精灵动画帧数据。 74 * @param {Int} index 要设置的索引位置。 75 * @returns {Sprite} Sprite对象本身。 76 */ 77 setFrame: function(frame, index){ 78 var frames = this._frames, 79 total = frames.length; 80 index = index < 0 ? 0 : index > total ? total : index; 81 frames[index] = frame; 82 if(frame.name) this._frameNames[frame.name] = frame; 83 if(index == 0 && !this.width || !this.height){ 84 this.width = frame.rect[2]; 85 this.height = frame.rect[3]; 86 } 87 return this; 88 }, 89 90 /** 91 * 获取精灵动画序列中指定的帧。 92 * @param {Object} indexOrName 要获取的帧的索引位置或别名。 93 * @returns {Object} 精灵帧对象。 94 */ 95 getFrame: function(indexOrName){ 96 if(typeof indexOrName === 'number'){ 97 var frames = this._frames; 98 if(indexOrName < 0 || indexOrName >= frames.length) return null; 99 return frames[indexOrName]; 100 } 101 return this._frameNames[indexOrName]; 102 }, 103 104 /** 105 * 获取精灵动画序列中指定帧的索引位置。 106 * @param {Object} frameValue 要获取的帧的索引位置或别名。 107 * @returns {Object} 精灵帧对象。 108 */ 109 getFrameIndex: function(frameValue){ 110 var frames = this._frames, 111 total = frames.length, 112 index = -1; 113 if(typeof frameValue === 'number'){ 114 index = frameValue; 115 }else{ 116 var frame = typeof frameValue === 'string' ? this._frameNames[frameValue] : frameValue; 117 if(frame){ 118 for(var i = 0; i < total; i++){ 119 if(frame === frames[i]){ 120 index = i; 121 break; 122 } 123 } 124 } 125 } 126 return index; 127 }, 128 129 /** 130 * 播放精灵动画。 131 * @returns {Sprite} Sprite对象本身。 132 */ 133 play: function(){ 134 this.paused = false; 135 return this; 136 }, 137 138 /** 139 * 暂停播放精灵动画。 140 * @returns {Sprite} Sprite对象本身。 141 */ 142 stop: function(){ 143 this.paused = true; 144 return this; 145 }, 146 147 /** 148 * 跳转精灵动画到指定的帧。 149 * @param {Object} indexOrName 要跳转的帧的索引位置或别名。 150 * @param {Boolean} pause 指示跳转后是否暂停播放。 151 * @returns {Sprite} Sprite对象本身。 152 */ 153 goto: function(indexOrName, pause){ 154 var total = this._frames.length, 155 index = this.getFrameIndex(indexOrName); 156 157 this._currentFrame = index < 0 ? 0 : index >= total ? total - 1 : index; 158 this.paused = pause; 159 return this; 160 }, 161 162 /** 163 * 渲染方法。 164 * @private 165 */ 166 _render: function(renderer, delta){ 167 var frameIndex = this._nextFrame(delta), 168 frame = this._frames[frameIndex]; 169 170 this.drawable.init(frame); 171 Sprite.superclass._render.call(this, renderer, delta); 172 }, 173 174 /** 175 * @private 176 */ 177 _nextFrame: function(delta){ 178 var frames = this._frames, 179 total = frames.length, 180 frameIndex = this._currentFrame, 181 frame = frames[frameIndex], 182 duration = frame.duration || this.interval, 183 elapsed = this._frameElapsed; 184 185 //calculate the current frame elapsed frames/time 186 var value = (frameIndex == 0 && !this.drawable) ? 0 : elapsed + (this.timeBased ? delta : 1); 187 elapsed = this._frameElapsed = value < duration ? value : 0; 188 189 if(frame.stop || !this.loop && frameIndex >= total - 1){ 190 this.stop(); 191 } 192 193 if(!this.paused && elapsed == 0){ 194 if(frame.next != null){ 195 //jump to the specified frame 196 frameIndex = this.getFrameIndex(frame.next); 197 }else if(frameIndex >= total - 1){ 198 //at the end of the frames, go back to first frame 199 frameIndex = 0; 200 }else if(this.drawable){ 201 //normal go forward to next frame 202 frameIndex++; 203 } 204 205 this._currentFrame = frameIndex; 206 } 207 208 if(this.onEnterFrame) this.onEnterFrame(frameIndex); 209 210 return frameIndex; 211 }, 212 213 /** 214 * 精灵动画的播放头进入新帧时的回调方法。默认值为null。 215 * @type Function 216 */ 217 onEnterFrame: null 218 219 });