大三时写的教程(2)~焰火效果-创建更高级的粒子系统

      创造另一个世界 2004-10-8 9:45
焰火效果--创建更高级的粒子系统
粒子系统是一个广泛应用的技巧,在电影、游戏中我们时时可以看到它的身影。在FLASH中,我们也可以用它创作出许多令人惊叹的效果。但在FLASH中如何更加有效地控制粒子的行为,以及尽可能地提高粒子效果的可重用性,还需要我们从其它领域吸取一些经验。下面我们就以大家早已熟悉的火焰效果为例,看一下怎样将面向对象的思想应用到我们的FLASH粒子系统的制作中来。

本次对经典效果做的改进主要有:
1.粒子的处理方面采用面向对象的思想:粒子将是可以独立存在并运动的,我们在影片中所做的只是在合适的地方创建它并给它一个合适的初始状态。
2.加入Z轴坐标,将焰火效果带入3D空间。
制作过程中还用到了另外一些小技巧,希望这些东东可以带给你一些帮助或是灵感。
现在就开始制作吧。作为参考,下面先给出做好的影片的层级关系图。

1.粒子
首先我们要做的就是创建我们的粒子。这是我们效果的最基础的部分。
先要做好图形部分:焰火的粒子应该体现其光亮的特征,我们可以用从中心到四周逐渐透明的方式来表现其发光的效果。
新建一个影片剪辑“ball”。在其中心位置用“椭圆工具”画一个正圆,将边删掉。然后将其填充改
为中心黄色到边缘透明的一个圆形渐变,如图:

我们在这个效果中的粒子要求可以随机变色,但FLASH MX并不支持在影片播放时用ACTION SCRIPT
改变影片的颜色,这时我们就要耍一点小手段:请在这一帧后面添加三个关键帧,然后改变这三个
关键帧中的圆形为不同的颜色(我把他们改成了红,蓝,绿,这样感觉鲜艳一点)。在以后的SCRIPT
中我们就可以使用 gotoAndStop()函数让影片显示不同的帧以达到变色的效果了。
放在场景中测试一下,感觉粒子不够亮。于是新建一个层,在这个层上画一个白色的小圆,使其位于粒子的中心,用它表现焰火粒子中心的高亮区。
最后的粒子如下图所示:

光是这样还不能表现粒子的动态,我们还希望我们的粒子可以闪动一下,这样更加符合焰火的真实情况。再建立一个影片剪辑“particle-fireworks”,用我们刚才创建的粒子“ball”在其中建立一个如下
的动画。并将这个动画中“ball”的INSTANCE改为“staticpoint”。


现在我们来写粒子的ACTION SCRIPT,画一个与影片大小相等的黑色矩形,以它为基本建立一个影片剪辑“background”,将他的INSTANCE改为“fireworks”。编辑“background”,新建一个层,创建一个“particle-fireworks”的实例,将其INSTANCE值改为“point”。然后在“point”里写入如下的ACTION SCRIPT:
onClipEvent(enterFrame)
{
if(
_alpha>0.1){ //如果粒子看不见的话就不进行处理
speed-=speed/Math.abs(speed)*0.05; //模拟空气阻力
_x+=speed*Math.cos(B)*Math.cos(A); //X轴上的运动

_y+=speed*Math.cos(B)*Math.sin(A); //Y轴上的运动
_y+=(ys+=0.05); //模拟加速度
z+=speed*Math.sin(B); //Z轴上的运动
_xscale=_yscale=80+z/2; //模拟3D效果:越远的东西看起来越小
_alpha-=1; //模拟焰火的逐渐消失
}
}
下面是详细的说明:
a.本系统采用的坐标系:

具体的做法就是粒子有一个合速度speed,再用三角函数求出各坐标轴上的速度分量,加到粒子的坐标上去。
b.模拟3D部分:
其实这只是一个近似的算法,并没有真的用到3D有关的算法,只是根据Z值的大小相应改变粒子的大小以模拟远近的效果罢了。
c.关于ys:
重力将使物体在竖直方向速度越来越快,作为对speed的补充,这个变量体现了这一点。
这样我们就有了一个可以控制自己行为的粒子。测试一下影片,粒子会因为加速度的存在而往下掉并逐渐消失。尝试改变一下粒子属性的一些初始值,你会发现它会以你限定的方式运动下去,而不需要任何其它代码。我们可以把它看成C++中的一个类,而下面我们要做的,就是在恰当的地点,恰当的时间产生一些这个类的实例(duplicateMovieClip),并正确地给予它一些初始值。
2.爆炸部分的实现
有了上面的粒子,焰火的实现就容易了。爆炸的任务就是要在某个位置产生一些上面的粒子。我们同样将这个功能“封装”成一个函数,以便我们在需要的地方调用它。
点击我们一始创建的那个实例名为“fireworks”的影片剪辑,加入以下代码:

onClipEvent(load)
{
function bomb(x,y) {
//duplicateMovieClip(flash,"flash1",9999);
//flash1._x=x;
//flash1._y=y;
for (count=0; count<40; count++) {
duplicateMovieClip(point, "point"+count, count);
eval("point"+count)._x=x;
eval("point"+count)._y=y;
eval("point"+count)._alpha=100;
eval("point"+count).speed = Math.random()*2+2;
eval("point"+count).B = (Math.random()*360)/180*Math.PI;
eval("point"+count).A = (Math.random()*360)/180*Math.PI;
eval("point"+count).staticpoint.gotoAndStop(Math.ceil(Math.random()*4));
}
}
}

说明:在(x,y)点处生成40个粒子,并给予它们随机的速度(speed),方向(角A和角B),颜色(记得上面创建粒子时做的工作吗);初始是完全可见的(_alpha=100)。
3.更真实的爆炸:
你肯定注意到加了注释符号的那几行代码。他们是用来产生闪光效果的。烟花爆炸的时候你不是都会觉得眼前猛地一闪吗?做一个大大的圆,用白色到透明的圆形渐变填充它。以它生成一个电影剪辑并作一个闪光消失(alpha->100~0)的动画。放到我们的“background”中去,再把它的INSTANCE改为“flash”,你就可以把那几行代码前面的注释符号去掉了。你会发现其实这种看起来拙劣的模拟产生的效果还是不错的。
好了,焰火的模拟工作现在已经基本完成了。你可以在影片的某一帧调用一下Bomb(x,y)--注意函数的调用路径:_root.fireworks.Bomb(x,y)才对--你就会看见美丽的焰火了。以后我们要做的就只是调用一下Bomb(x,y)这个函数,就可以炸开花了!编程时的基本思想在FLASH中运用也能大大提高效率。其实方法是相通的,软件只是一种工具而已。
4.更多的爆炸效果
为什么生成粒子时都用随机函数呢?这是因为我们想要模拟一下真实的焰火。其实有些焰火爆炸时粒子的发射是有规律的。炸开后会形成特定的形状,比如一个球。这种焰火比那种炸开来乱飞的焰火制作时要难些。但在FLASH的世界里,还有什么不可能的呢?通过修改Bomb(x,y)函数,规律化粒子生成时的初始值,你可以让你的FLASH焰火以任何形状炸开来。这种效果也更能体现我们加入的Z轴的作用。但由于不是用的真的3D算法,有些效果显示出来的样子可能与预想的不大相同,我们可以跳过这些效果。如果效果真的棒到舍不得丢掉,我们也只需要改一下粒子本身的ACTION SCRIPT,改成真3D算法。只需要改一个地方,我们就能让我们的影片大变样。
5.粒子的重用
C++的类都具有可重用性。也许你也还想将我们做的“particle-fireworks”这种粒子用到其它影片中去,但你却不能在库中直接把“particle-fireworks”这个粒子拖过去,因为库中的“particle-fireworks”中并未有我们在影片中为粒子所写的ACTION SCRIPT。解决方法之一是你可以通过复制-粘贴的办法将它从我们这个影片中粘过去。当然还有更好的办法:我们将写好ACTION SCRIPT粒子再放到一个空的电影剪辑中去(这样是为了保存我们为粒子写的ACTION SCRIPT),然后在代码中作一些修改:在“_x,_y,_alpha”这些类似的值前加上“_parent.”,大功告成,粒子现在已被完全“封装”。以后就可以从库中将这个新电影剪辑拖过去使用了。
其实FLASH本来就是面向对象的,各个影片剪辑在其中都是作为单独的对象来对待。正因为如此,我们在FLASH中创建一个这样的对象并不是什么难事,关键是我们要把这种思想贯穿到我们的制作过程中去。好好地利用FLASH的这一特性,我们就能体会到FLASH制作更多的乐趣。
源代码
标签集:TAGS:
回复Comments() 点击Count()

回复Comments

{commentauthor}
{commentauthor}
{commenttime}
{commentnum}
{commentcontent}
作者:
{commentrecontent}