AS3 Starling extends Particle System 分析

来源:互联网 发布:centos中文 编辑:程序博客网 时间:2024/05/18 11:07
Starling extentions Particle System
Author : Gamua OG


分析作者:Jave.lin
原文:http://blog.csdn.net/linjf520/article/details/8701354


这是Starling扩展的粒子系统


下来源码,与DEMO运行后,发现效果很强大,于是开始研究其结构;


1、粒子的初始化:
初始化主要处理以下内容:决定粒子的初始值、与大部分的过渡值;部份过渡值只能在过渡时的公式下决定
在粒子的初始化时,可以考虑使用以下方式来初始化:
思路:每个值,都由:本来的值+波动值


2、粒子的过渡更新
主要是应用初始化决定的:目标值 与 终止值,而使用过渡值的一个更新过渡


function ranWave(value):Number{//波动函数
 return Math.random()*(value*2)-value;
}


function rw(v):Number{return ranWave(v);}


生命周期 a 10
生命周期波动值 b 5
则生命周期在生成时 c 10+5*(-1~1)


c=a+rw(b)


e.g.


class ColorArgb
{
 alpha:Number; //透明通道值:0~1
 red:Number; //红色通道值:0~1
 green:Number; //绿色通道值:0~1
 blue:Number; //蓝色通道值:0~1
 function toArgb():int;
 function fromArgb(v:int):void;
 function toRbg():int;
 function fromRgb(v:int):void;
}


class Particle //粒子基础数据定义--用于直接呈现的数据
{
 x:Number; //粒子x坐标位置
 y:Number; //粒子y坐标位置
 scale:Number; //缩放
 rotation:Number; //当前的弧度,可以理解为:自转,角度,实在不明白就:百度:自转,这里不加说明;
 color:uint; //当前的着色值
 currentTime:int; //当前已消耗的生命周期数值记录
 totalTime:int; //总的生命周期
}


class PDParticle //Proccess Distance ( or Delta ) values Particle 用于动画数据过度时处理的数据
extends Particle
{
 //放射型发射器用到的变量
 colorArgb:ColorArgb; //当前着色四个值的管理
 colorArgbDelta:ColorArgb; //当前的着色值的四通道值的过渡值(每帧处理的比率值)
 var startX:Number, startY:Number;//记录发射器的X,Y位置,当粒子与发射点距离,作旋转、重力、的控制
 var velocityX:Number, velocityY:Number;//当前X,Y上的轴速度
 //径向型发射器用到的变量
 var emitRadius:Number; //发射的半径(即,与startX,startY的相对距离值)
 var emitRadiusDelta:Number; //半径过程变量值
 var emitRotation:Number; //发射角度,相对startX,startY的角度,可以理解为:公转,角度,实在不明白就:百度:公转,这里不加说明;
 var emitRotationDelta:Number; //发射角度过程变量值
 var rotationDelta:Number; //粒子自身的对度发射点的角度变化过渡值
 var radialAcceleration:Number; //当前放射速度
 var tangentialAcceleration:Number;//这个在应用时的算法上比较难懂,但只要在纸上画一下,就是把速度向量方向-Math.PI的效果,这样就会有:螺旋效果了
 var scaleDelta:Number; //缩放过渡变化值
}


class ParticleEmitter extends DisplayObject implements IAnimatable//应用数据(即时数据),呈现发射器
{
 //单位粒子的纹理配置(供外部工具调整,而导出的配置之一的数据)
 var texture:Texture;


 function void advanceTime(passedTime:Number):void;
 function void advancePs(ps:Particle, passedTime:Number):void;
 function void start(duration:Number=Number.MAX_VALUE):void;
 function void stop(clearPs:Boolean=falsel):void;
}


class PDParticleEmitter extends ParticleEmitter//数据过渡处理发射器
{
 static const EMITTER_TYPE_GRAVITY:int = 0; //内聚型发射器(这里的Gravity译为:引力、吸引力,即为:内聚引力)
 static const EMITTER_TYPE_RADIAL:int = 1; //与内聚反向:发散型发射器
 //每帧的处理时间
 var frameTime:Number; //在单帧的update时,处理粒子的循环发射时使用的时间


 //发射器配置(供外部工具调整,而导出的配置之一的数据)
 var emitterType:int; //发射器类型:目前只有两种:发散型、内聚型
 var emitterX:Number,emitterY:Number; //发射器x,y,决定,单个粒子的起始位置的变量之一
 var emitterXVariance:Number,emitterYVariance:Number;//发射器x,y的位置波动值
 var emitterDuration:Number; //发射器的持续时间(相当于:发射器的生命周期),默认以:Number.MAX_VALUE时,说明是无限循环的方式
 var emitterRate:Number; //该可以理解为:创建单个粒子的时间,在初始化时,根据:maxNumPs/lifespan(最大粒子数/单个粒子生命周期),来定值


 //粒子配置(供外部工具调整,而导出的配置之一的数据)
 var maxNumPs:int; //最大粒子数
 var lifespan:Number; //单个粒子生命周期
 var lifespanVariance; //在初始化时,加到:单个粒子生命周期的波动值
 var angle:Number; //发射粒子的角度(单位:弧度)
 var angleVariance:Number; //角度的波动值
 var startSize:Number; //初始大小值(注意,这里不是缩放值,而是width,height之类的大小(size)值,而不是缩放(scale),但最终运行时,会与大小相除转成对应的缩放值)
 var startSizeVariance:Number; //初始大小波动值
 var endSize:Number; //终止(目标)大小值
 var endSizeVariance:Number; //终止大小波动值
 var startRotation:Number; //初始角度(弧度)
 var startRotationVariance:Number; //初始角度波动值
 var endRotation:Number; //终止角度
 var endRotationVariance:Number; //终止角度波动值


 //重力、运动速度配置(供外部工具调整,而导出的配置之一的数据)
 var speed:Number; //粒子的速度值
 var speedVariance:Number; //速度波动值
 var radialAcceleration:Number; //放射型的放射速度(单个粒子的自身:startX,startY:发射器位置,与当前位置:x,y的距离连线,形成的向量(放射向量))上的加速度
 var radialAccelerationVariance:Number; //放射速度波动值 
 var tangentialAcceleration:Number; //正切--tan的加成速度(螺旋速度值)
 var tangentialAccelerationVariance:Number;//螺旋波动值
 var gravityX:Number; //重力向量X值
 var gravityY:Number; //重力向量Y值

 //放射型粒子配置(供外部工具调整,而导出的配置之一的数据)
 var maxRadius:Number; //最大的发射半径
 var maxRadiusVariance:Number; //最大半径波动值
 var minRadius:Number; //最小的发射半径
 var rotatePerSecond:Number; //每秒的旋转弧度
 var rotatePerSecondVariance:Number; //旋转弧度的波动值


 //颜色配置(供外部工具调整,而导出的配置之一的数据)
 var startColor:ColorArgb; //初始颜色
 var startColorVariance:ColorArgb; //初始颜色波动值
 var endColor:ColorArgb; //终止(目标)颜色
 var endColorVariance:ColorArgb; //终止颜色波动值


 //初始化函数
 function initializePs(ps:PDParticle):void
 {
  var ls:Number = lifespan + rw(lifespanVariance);//生命周期
  if(ls == 0) reutrn; //生命周期为0的,可以忽略不处理
  
  ps.currentTime = 0; //重置当前粒子已消耗的生命时间
  ps.totoalTime = ls; //设置粒子的最大生命周期


  ps.x = emitterX + rw(emitterXVariance);//设置当前位置
  ps.y = emitterY + rw(emitterYVariance);
  ps.startX = emitterX; //记录射点起来位置
  ps.startY = emitterY;
  
  var a:Number = emitterAngle + rw(angleVariance);
  var s:Number = emitterSpeed + rw(speedVariance);
  ps.velocityX = s * Math.cos(a); //x,y轴上的轴速度;(可以封装2D向量处理也可以,不过粒子的封装最好不要过多层次,能以最小的封装来处理,性能上会好一些)
  ps.velocityY = s * Math.sin(a);


  ps.emitRadius = maxRadius + rw(maxRadiusVariance);
  ps.emitRadiusDelta = maxRadius / ls; //与该粒子的生命期周时间作一个等分为比率过渡值


  ps.emitRotation = angle + rw(angleVariance);//在径向型的发射器处理时,与分散型的发射角度一样
  ps.emitRotationDelta = rotatePerSecond + rw(rotatePerSecondVariance);//发射器角度过渡变化值


  ps.radialAcceleration = radialAcceleration + rw(radialAccelerationVariance);//放射加速度,放射速度如果为很大的负数-Max,那就是像个黑洞一样;将所有粒子向内发射,然后爆炸的效果,我设置为-3800的时候就比较像黑洞内聚力效果
  ps.tangentialAcceleration = tangentialAccelertaion + rw(tangentialAccelerationVariance);


  var ss:Number = startSize + rw(startSizeVariance);
  var es:Number = endSize + rw(endSizeVariance);
  if(ss < .1) ss = .1;
  if(es < .1) es = .1;
  ps.scale = ss / texture.width;
  ps.scaleDelta = ((es - ss) / ls) / texture.width;//用终止值-始化值=距离值,再用这个距离值,除:该粒子的生命周期,即:得到:变化率,再用变化率(尺寸值比率) * 原纹理尺寸值大小,最终得到该值:缩放过渡变化值,这里为啥只乘宽度,因为我们先这里只处理,等比例缩放,不做不等比例;


  // colors
            
  var sc:ColorArgb = ps.colorArgb; //用于决定初始化颜色
  var colorDelta:ColorArgb = ps.colorArgbDelta; //用于决定过渡处理时的颜色,四通道,各种的变化率
            
  sc.red   = startColor.red;
  sc.green = startColor.green;
  sc.blue  = startColor.blue;
  sc.alpha = startColor.alpha;


  if (startColorVariance.red != 0)   sc.red   += rw(startColorVariance.red);//如果初始颜色,各通道有值才处理波动累加;
  if (startColorVariance.green != 0) sc.green += rw(startColorVariance.green);
  if (startColorVariance.blue != 0)  sc.blue  += rw(startColorVariance.blue);
  if (startColorVariance.alpha != 0) sc.alpha += rw(startColorVariance.alpha);


  var ecRed:Number   = endColor.red;
  var ecGreen:Number = endColor.green;
  var ecBlue:Number  = endColor.blue;
  var ecAlpha:Number = endColor.alpha;


  if (endColorVariance.red != 0)   ecRed   += rw(endColorVariance.red);//终止初始颜色,各通道有值才处理波动累加;
  if (endColorVariance.green != 0) ecGreen += rw(endColorVariance.green);
  if (endColorVariance.blue != 0)  ecBlue  += rw(endColorVariance.blue);
  if (endColorVariance.alpha != 0) ecAlpha += rw(endColorVariance.alpha);


  colorDelta.red   = (ecRed   - sc.red)   / ls; //以(目标值-初始值)/总消时(生命周期)=每次单位(这里可以是:秒,或是毫秒,这里可以自由转,或是其它单位)更新过渡变化率值,外国人都喜欢把这些变化值叫:delta
  colorDelta.green = (ecGreen - sc.green) / ls;
  colorDelta.blue  = (ecBlue  - sc.blue)  / ls;
  colorDelta.alpha = (ecAlpha - sc.alpha) / ls;


  // rotation


  var sr:Number = startRotation + rw(startRotationVariance);
  var er:Number   = endRotation   + rw(endRotationVariance);


  ps.rotation = sr; //决定初始角度、终止角度
  ps.rotationDelta = (er - sr) / ls;
 }


 //更新 “初始值” 到 “终止值” 的函数
 override function advancePs(ps:Particle,passedTime:Number):void
 {
  //过渡变化处理,以下我都简称为:pd'
  var pdps:PDParticle = ps as PDParticle;
  
  var restTime:Number = pdps.totalTime - pdps.currentTime;
  passedTime = restTime > passedTime ? passedTime : restTime;//因为以会passedTime来做一些过渡因数,所以这里调整为,还剩最后一次更新的粒子的时间因数作调整
  pdps.currentTime += passedTime;


  if(emitterType == EMITTER_TYPE_GRAVITY)
  {//内聚型
   pdps.emitRotation += pdps.emitRotationDelta* passTime;//pd'粒子对应emitterX,Y的角度;
   pdps.emitRadius -= pdps.emitRadiusDelta* passTime;//pd'粒子距离emitterX,Y半径
   pdps.x = emitterX - Math.cos(pdps.emitRotation) * pdps.emitRadius;
   pdps.y = emitterY - Math.sin(pdps.emitRotation) * pdps.emitRadius;
   
   if(pdps.emitRadius < minRadius) //当半径值比最小值还小时,就相当于,该粒子已‘挂’(生命周期为止)
    pdps.currentTime = pdps.totalTime;
  }
  else
  {//发散型
   var disX:Number = pdps.x - pdps.startX;//前面我说了,startX只是拿来作该粒子初始化时,记录emtterX的位置;这里使用当前位置-记录发射器位置,就是求该粒子当次生命周期中的,已发散距离
   var disY:Number = pdps.y - pdps.startY;//同上
   var disScale:Number = Math.sqrt(disX*disX + disY*disY);//这里的运算原理,我也不知道;同求解;同公式中可以知道,disX,disY与disScale是成倍的正比
   if(disScale < .01) disScale = .01; //作者这里调整最小于不低于:.01的意思:1、以下应用有作为除数;2、即时粒子已发散距离很小,但至少还得很微量的动画调整因数作用
   
   var rX:Number = disX / disScale;
   var rY:Number = disY / disScale;
   var tanX:Number = rX; //这里我前面讲到过,就是作:螺旋转速度的因数;
   var tanY:Number = rY;
   
   rX *= pdps.radialAcceleration; //粒子的发散加速应用
   rY *= pdps.radialAcceleration;


   var dumpTanX:Number = tanX; //备份一下tanX,这里开始就是我上面所说的,螺旋运算,转-90度的方向调整
   tanX = -tanY * pdps.tangentialAcceleration;
   tanY = dumTanX * pdps.tangentialAcceleration;


   pdps.velocityX += passedTime * (gravityX + radialX + tanX);//注意这里的passedTime作用,前面我说到,passedTime的调整,最后一次为最后生命时间,这样效果才是比较合理的
   pdps.velocityY += passedTime * (gravityY + radialY + tanY);//所有:重力、发散、螺旋 ,等等,这些速度,都与passedTime有关,如果当前这帧的时间很小(说明FPS很高),那么过渡动画数据就会呈现越细
   pdps.x += pdps.velocityX * passedTime; //pd'重力、发散、螺旋
   pdps.y += pdps.velocityY * passedTime;
  }


  pdps.scale += pdps.scaleDelta * passedTime; //pd'缩放
  pdps.rotation += pdps.rotaionDelta * passedTime; //pd'自转角度


  pdps.colorArgb.red += pdps.colorArgbDelta.red* passedTime;//pd'颜色
  pdps.colorArgb.green += pdps.colorArgbDelta.green* passedTime;
  pdps.colorArgb.blue += pdps.colorArgbDelta.blue* passedTime;
  pdps.colorArgb.alpha += pdps.colorArgbDelta.alpha* passedTime;


  pdps.color = pdps.colorArgb.toRgb(); //最终应用颜色值RGB
  pdps.alpha = pdps.colorArgb.alpha;
 }
}


好了,就分析到这里;
原创粉丝点击