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