1 /** 2 * Hilo 3 * Copyright 2015 alibaba.com 4 * Licensed under the MIT License 5 */ 6 7 /** 8 * <iframe src='../../../examples/ParticleSystem.html?noHeader' width = '550' height = '400' scrolling='no'></iframe> 9 * <br/> 10 * @class 粒子系统 11 * @augments Container 12 * @module hilo/game/ParticleSystem 13 * @requires hilo/core/Hilo 14 * @requires hilo/core/Class 15 * @requires hilo/view/View 16 * @requires hilo/view/Container 17 * @requires hilo/view/Bitmap 18 * @requires hilo/view/Drawable 19 * @requires hilo/util/util 20 * @property {Number} [emitTime=0.2] 发射间隔 21 * @property {Number} [emitTimeVar=0] 发射间隔变化量 22 * @property {Number} [emitNum=10] 每次发射数量 23 * @property {Number} [emitNumVar=0] 每次发射数量变化量 24 * @property {Number} [emitterX=0] 发射器位置x 25 * @property {Number} [emitterY=0] 发射器位置y 26 * @property {Number} [totalTime=Infinity] 总时间 27 * @property {Number} [gx=0] 重力加速度x 28 * @property {Number} [gy=0] 重力加速度y 29 * @param {Object} properties 创建对象的属性参数。可包含此类所有可写属性。 30 * @param {Object} properties.particle 粒子属性配置 31 * @param {Number} [properties.particle.x=0] x位置 32 * @param {Number} [properties.particle.y=0] y位置 33 * @param {Number} [properties.particle.vx=0] x速度 34 * @param {Number} [properties.particle.vy=0] y速度 35 * @param {Number} [properties.particle.ax=0] x加速度 36 * @param {Number} [properties.particle.ay=0] y加速度 37 * @param {Number} [properties.particle.life=1] 粒子存活时间,单位s 38 * @param {Number} [properties.particle.alpha=1] 透明度 39 * @param {Number} [properties.particle.alphaV=0] 透明度变化 40 * @param {Number} [properties.particle.scale=1] 缩放 41 * @param {Number} [properties.particle.scaleV=0] 缩放变化速度 42 */ 43 var ParticleSystem = (function(){ 44 //粒子属性 45 var props = ['x', 'y', 'vx', 'vy', 'ax', 'ay', 'rotation', 'rotationV', 'scale', 'scaleV', 'alpha', 'alphaV', 'life']; 46 var PROPS = []; 47 for(var i = 0, l = props.length;i < l;i ++){ 48 var p = props[i]; 49 PROPS.push(p); 50 PROPS.push(p + "Var"); 51 } 52 53 //粒子默认值 54 var PROPS_DEFAULT = { 55 x: 0, 56 y: 0, 57 vx: 0, 58 vy: 0, 59 ax: 0, 60 ay: 0, 61 scale:1, 62 scaleV:0, 63 alpha:1, 64 alphaV:0, 65 rotation: 0, 66 rotationV: 0, 67 life: 1 68 }; 69 70 var diedParticles = []; 71 72 var ParticleSystem = Class.create(/** @lends ParticleSystem.prototype */{ 73 Extends:Container, 74 constructor:function(properties){ 75 this.id = this.id || properties.id || Hilo.getUid("ParticleSystem"); 76 77 this.emitterX = 0; 78 this.emitterY = 0; 79 80 this.gx = 0; 81 this.gy = 0; 82 this.totalTime = Infinity; 83 84 this.emitNum = 10; 85 this.emitNumVar = 0; 86 87 this.emitTime = .2; 88 this.emitTimeVar = 0; 89 90 this.particle = {}; 91 92 ParticleSystem.superclass.constructor.call(this, properties); 93 94 this.reset(properties); 95 }, 96 Statics:{ 97 PROPS:PROPS, 98 PROPS_DEFAULT:PROPS_DEFAULT, 99 diedParticles:diedParticles 100 }, 101 /** 102 * 重置属性 103 * @param {Object} cfg 104 */ 105 reset: function(cfg) { 106 util.copy(this, cfg); 107 this.particle.system = this; 108 if(this.totalTime <= 0){ 109 this.totalTime = Infinity; 110 } 111 }, 112 /** 113 * 更新 114 * @param {Number} dt 间隔时间 单位ms 115 */ 116 onUpdate: function(dt) { 117 dt *= .001; 118 if (this._isRun) { 119 this._totalRunTime += dt; 120 this._currentRunTime += dt; 121 if (this._currentRunTime >= this._emitTime) { 122 this._currentRunTime = 0; 123 this._emitTime = getRandomValue(this.emitTime, this.emitTimeVar); 124 this._emit(); 125 } 126 127 if (this._totalRunTime >= this.totalTime) { 128 this.stop(); 129 } 130 } 131 }, 132 /** 133 * 发射粒子 134 */ 135 _emit: function() { 136 var num = getRandomValue(this.emitNum, this.emitNumVar)>>0; 137 for (var i = 0; i < num; i++) { 138 this.addChild(Particle.create(this.particle)); 139 } 140 }, 141 /** 142 * 开始发射粒子 143 */ 144 start: function() { 145 this.stop(true); 146 this._currentRunTime = 0; 147 this._totalRunTime = 0; 148 this._isRun = true; 149 this._emitTime = getRandomValue(this.emitTime, this.emitTimeVar); 150 }, 151 /** 152 * 停止发射粒子 153 * @param {Boolean} clear 是否清除所有粒子 154 */ 155 stop: function(clear) { 156 this._isRun = false; 157 if (clear) { 158 for (var i = this.children.length - 1; i >= 0; i--) { 159 this.children[i].destroy(); 160 } 161 } 162 } 163 }); 164 165 /** 166 * @class 粒子 167 * @inner 168 * @param {Number} vx x速度 169 * @param {Number} vy y速度 170 * @param {Number} ax x加速度 171 * @param {Number} ay y加速度 172 * @param {Number} scaleV 缩放变化速度 173 * @param {Number} alphaV 透明度变换速度 174 * @param {Number} rotationV 旋转速度 175 * @param {Number} life 存活时间 176 */ 177 var Particle = Class.create({ 178 Extends:View, 179 constructor:function(properties){ 180 this.id = this.id || properties.id || Hilo.getUid("Particle"); 181 Particle.superclass.constructor.call(this, properties); 182 this.init(properties); 183 }, 184 /** 185 * 更新粒子。 186 */ 187 onUpdate: function(dt) { 188 dt *= .001; 189 if(this._died){ 190 return false; 191 } 192 var ax = this.ax + this.system.gx; 193 var ay = this.ay + this.system.gy; 194 195 this.vx += ax * dt; 196 this.vy += ay * dt; 197 this.x += this.vx * dt; 198 this.y += this.vy * dt; 199 200 this.rotation += this.rotationV; 201 202 if (this._time > .1) { 203 this.alpha += this.alphaV; 204 } 205 206 this.scale += this.scaleV; 207 this.scaleX = this.scaleY = this.scale; 208 209 this._time += dt; 210 if (this._time >= this.life || this.alpha <= 0) { 211 this.destroy(); 212 return false; 213 } 214 }, 215 /** 216 * 设置粒子图像。 217 */ 218 setImage: function(img, frame) { 219 this.drawable = this.drawable||new Drawable(); 220 frame = frame || [0, 0, img.width, img.height]; 221 222 this.width = frame[2]; 223 this.height = frame[3]; 224 this.drawable.rect = frame; 225 this.drawable.image = img; 226 }, 227 /** 228 * 销毁粒子 229 */ 230 destroy: function() { 231 this._died = true; 232 this.alpha = 0; 233 this.removeFromParent(); 234 diedParticles.push(this); 235 }, 236 /** 237 * 初始化粒子。 238 */ 239 init: function(cfg) { 240 this.system = cfg.system; 241 this._died = false; 242 this._time = 0; 243 this.alpha = 1; 244 for (var i = 0, l = PROPS.length; i < l; i++) { 245 var p = PROPS[i]; 246 var v = cfg[p] === undefined ? PROPS_DEFAULT[p] : cfg[p]; 247 this[p] = getRandomValue(v, cfg[p + 'Var']); 248 } 249 250 this.x += this.system.emitterX; 251 this.y += this.system.emitterY; 252 253 if (cfg.image) { 254 var frame = cfg.frame; 255 if(frame && frame[0].length){ 256 frame = frame[(Math.random() * frame.length) >> 0]; 257 } 258 this.setImage(cfg.image, frame); 259 if(cfg.pivotX !== undefined){ 260 this.pivotX = cfg.pivotX * frame[2]; 261 } 262 if(cfg.pivotY !== undefined){ 263 this.pivotY = cfg.pivotY * frame[3]; 264 } 265 } 266 }, 267 Statics:{ 268 /** 269 * 生成粒子。 270 * @param {Object} cfg 粒子参数。 271 */ 272 create:function(cfg) { 273 if (diedParticles.length > 0) { 274 var particle = diedParticles.pop(); 275 particle.init(cfg); 276 return particle; 277 } else { 278 return new Particle(cfg); 279 } 280 } 281 } 282 283 }); 284 285 /** 286 * Get the random value. 287 * @private 288 * @param {Number} value The value. 289 * @param {Number} variances The variances. 290 * @return {Number} 291 */ 292 function getRandomValue(value, variances){ 293 return variances ? value + (Math.random() - .5) * 2 * variances : value; 294 } 295 296 return ParticleSystem; 297 })();