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