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;
}
}
好了,就分析到这里;
AS3 Starling extends Particle System 分析
关注
打赏