天花无数月中开,五采祥云绕绛台。堕地忽惊星彩散,飞空旋作雨声来。怒撞玉斗翻晴雪,勇踏金轮起疾雷。更漏已深人渐散,闹竿挑得彩灯回。
——明·瞿佑·《烟火戏》
记得每年过春节的那段时间,除了欣赏隆冬的景色,剩下的就是欣赏天空中美丽的烟花了。
成都的冬天,天空中总是灰蒙蒙的,像是织了一层薄薄的轻纱,把阳光挡走了一部分。路边的枫树上,没有了夏日整天“知了”,“知了”的小家伙,是否有鸟儿,我却也忘了。树上的枫叶寥寥无几,可能是在某一时候,悄无声息地飘落了;有时路过一棵年岁已高的树,也不知是地球引力还是什么的原因,一片叶子会自然地落下来,不留神的话就会掉到你头顶上,顶着它走几里路了,还没发现。
大冷的天,躲在屋里,有时大风挂起,看着不停散落的枫叶,都开始害怕他们会冻成冰。有时敲代码不知不觉就到了傍晚,天更灰了,回身看看窗外的枫树,只见一片片的红云飘逸在眼前,随着风起而凋零。
除夕夜里,一般是在亲戚家过的,吃完了饭,一家人便一边欣赏提前放飞的烟花,一边聊天。屋里暖暖的,想到还在外面劳作的人们,不觉得会为他们打个寒战。
有时我和父母还有哥哥会提前回家,告别了众亲戚,便往屋里赶,希望还能赶上春节联欢晚会的开始(虽然现在很多人讨厌看春节联欢晚会,但我想这是一种传统,搞得不好可以提意见,但是好的传统应该继续传承下去,就像类的继承一样)。父亲是个不爱花冤枉钱的人,去某个地方从来不打车,要不自己走,要不就自己骑车,或者自己开车。因此在走回去的路上,我又可以观赏这隆冬的华丽夜景了。
回家后,第一件事就是把年货拿出来,不停地吃,父亲一向不许我吃零食,但是过节的时候从来不阻止。记得有一年,父亲叫我和哥哥把所有吃剩的瓜子壳,橘子皮都扔在地上,我说难道不难收拾吗?父亲则说到时候扫一下就可以了,仍在地上才有节日的气氛。到现在来想想,过节不就是要气氛吗?没了气氛,也就没了温馨,没了温馨,这节日还有什么好过的呢?
当钟上的时针和分针都指在12点的位置上的时候,就是该观看烟花的时候了。各种各样的烟花被撒如天幕,绽放出各种五颜六色,奇形怪状的烟花粒子。有的升入云霄,忽地不见了,过一眨眼的功夫,便突然呈现为一点金色的小花,像夜幕中的星星一般。有的就给子弹一样,不停地连发出去,飞到一定高度也消失了,有人说这就是传说中的“冲天炮”,我觉得与其叫“冲天炮”,还不如叫火箭“喀秋莎”算了。烟花的声音可不是一般的混乱,轰隆隆的声响里,总少不了嗖嗖地烟花升天的声音。这些声音倒也吵人,倘若靠近声源处,旁边的人说话是听不见的。
可惜最近几年迷上了编程序,烟花也懒得看了,几年没欣赏烟花了,心里也惦记起来了。最近用html5做了一个拖尾效果,想到用拖尾可以做一个烟花效果,也就尝试做了一下,没想到不做不知道,原来实现起来这么简单。上面瞎扯了一大堆,大家见谅一下,接下来就给大家介绍一下是如何实现的。
先看一下截图:
测试地址:http://www.cnblogs.com/yorhom/articles/3244140.html
用支持html5的浏览器打开就可以。
本次开发和上次一样,用到了开源引擎lufylegend,详细信息如下
lufylegend官方网站:http://lufylegend.com/lufylegend
lufylegend API文档:http://lufylegend.com/lufylegend/api
※注意:在了解了引擎lufylegend的前提下阅读本文方可没有障碍。
接下来是实现过程。
一,改进拖尾类
在上一节《『HTML5梦幻之旅』-炫丽的流星雨效果》中,我们讲解了Smearing这个类,这个类主要用于现实拖尾等效果。上一节中,我们讲到了Smearing.to()方法里的时候,谈到如果对象移动完毕时,自动将自己的mode设置为"complete"。实现这个方面的时候,我们直接将缓动的数据的onComplete进行更改,以达到效果。后来发现这样做不好,因此改进了一下:想将原数据的onComplete保存到一个变量中,再更改onComplete里的数据,更改为先调用先前保存的onComplete,然后再将mode改为"complete",这样的话,用户就可以自己设定onComplete里的内容了。Smearing.to()方法里的代码改为如下:
Smearing.prototype.to = function($duration,$vars){
var self = this;
var customFunc = $vars.onComplete || function(){};
$vars.onComplete = function(){
customFunc();
self.mode = "complete";
}
LTweenLite.to(self.originalSprite,$duration,$vars);
};
二,烟花类Fireworks
为了实现烟花效果,我们封装一个叫Fireworks的类,类的构造器如下:
function Fireworks(x,y,color){
var self = this;
base(self,LSprite,[]);
self.fireworksX = x;
self.fireworksY = y;
self.angle = 20;
self.count = 18;
self.smearingColor = color;
self._showFireworks();
}
self.angle = 20;
self.count = 18;
这两行代码看似平凡,却十分重要。由于我们的烟花是一圈一圈的,所以,我们在现实烟花喷出来的粒子的时候,要计算出每个烟花的位置。要确定位置,就要确定每个烟花的角度,以及所有烟花粒子的个数,为了实现这个,我们设置这两个属性。angle属性是当前烟花粒子要到达的位置与圆心的连线和上一个烟花粒子要到达的位置与圆心的连线的夹角。count属性是所有烟花粒子的个数。可以看到,如果angle和count想乘,积是360,也就是一圈的度数。
我们每个粒子要到达的位置图示如下:
这一点想通了就不难了,最后我们调用成员函数_showFireworks(),通过掉用这个函数实现显示烟花。具体代码如代码清单4:
Fireworks.prototype._showFireworks = function(){
var self= this;
var kaku;
for(var i=0; i<self.count; i++){
kaku = i*self.angle;
var toX = 100*Math.sin(kaku * Math.PI / 180);
var toY = 100*Math.cos(kaku * Math.PI / 180);
var smearingLayer = new LGraphics();
smearingLayer.drawArc(0,"",[0,0,5,0,2*Math.PI],true,self.smearingColor);
var spreadingSmearing = new Smearing(smearingLayer);
spreadingSmearing.x = self.fireworksX;
spreadingSmearing.y = self.fireworksY;
spreadingSmearing.to(1,{
x: toX,
y: toY,
onComplete:function(){
self.mode = "complete";
}
});
self.addChild(spreadingSmearing);
}
};
for(var i=0; i<self.count; i++){
kaku = i*self.angle;
var toX = 100*Math.sin(kaku * Math.PI / 180);
var toY = 100*Math.cos(kaku * Math.PI / 180);
var smearingLayer = new LGraphics();
smearingLayer.drawArc(0,"",[0,0,5,0,2*Math.PI],true,self.smearingColor);
var spreadingSmearing = new Smearing(smearingLayer);
spreadingSmearing.x = self.fireworksX;
spreadingSmearing.y = self.fireworksY;
spreadingSmearing.to(1,{
x: toX,
y: toY,
onComplete:function(){
self.mode = "complete";
}
});
self.addChild(spreadingSmearing);
}
烟花类就Over了,接下来是有了这些封装之后,如何实现的方法。
三,溅入空中的烟花
先把所有代码放在下面:
init(10,"mylegend",500,500,main);
var backLayer,fireworksLayer;
var back;
//烟花颜色集
var colorArray = new Array(
"yellow",
"orangered",
"red",
"pink"
);
//加入烟花最大数量
var maxFrame = 4;
//当前加入烟花数量
var frameIndex = 0;
var sound;
function main(){
LStage.setDebug(true);
//加入音乐
sound = new LSound("http://stream20.qqmusic.qq.com/34962638.mp3");
//加入底板层
backLayer = new LSprite();
addChild(backLayer);
//加入烟花层
fireworksLayer = new LSprite();
addChild(fireworksLayer);
//画一个黑色矩形作为背景
back = new LGraphics();
back.drawRect(0,"",[0,0,LStage.width,LStage.height],true,"black");
backLayer.addChild(back);
//加入时间轴事件
backLayer.addEventListener(LEvent.ENTER_FRAME,onframe)
}
function addFireworks(){
var toY = Math.floor(Math.random() * (-350 + 250) - 250);
var colorIndex = Math.floor(Math.random() * 4)
//画一个黄色矩形作为一颗升天的烟花
var fireworks = new LSprite();
fireworks.x = Math.floor(Math.random() * (480 - 20) + 20);
fireworks.y = 500;
fireworks.graphics.drawRect(0,"",[0,0,10,10],true,colorArray[colorIndex]);
//为升起的烟花添加一个拖尾
var smearing = new Smearing(fireworks,50);
//移动烟花
smearing.to(1,{
x: 0,
y: toY,//-300
onComplete:function(){
//添加扩散开的烟花
var spreading = new Fireworks(fireworks.x,fireworks.y+toY,colorArray[colorIndex]);
fireworksLayer.addChild(spreading);
}
});
fireworksLayer.addChild(smearing);
}
function onframe(){
//加入烟花
if(frameIndex < maxFrame){
frameIndex ++;
addFireworks();
}
//播放音乐
if(sound.playing == false){
sound.play();
}
//移除烟花
for(var key in fireworksLayer.childList){
if(fireworksLayer.childList[key].mode == "complete"){
//通过缓动更改烟花透明度
LTweenLite.to(fireworksLayer.childList[key],0.3,{
alpha:0,
onComplete:function(o){
//移除对象
fireworksLayer.removeChild(o);
//如果界面上没有烟花,将已经加入数量设为0
if(fireworksLayer.childList.length == 0){
frameIndex = 0;
}
}
});
}
}
}
最后运行出来,连我都感叹道:“这不是久违不见的烟花君吗?”
lufy长者也曰到:“效果很漂亮啊。”
嘿嘿,既然专家都说漂亮了,大家不赶快试试?
最后奉上源代码:http://files.cnblogs.com/yorhom/fireworks.rar
话说这烟花效果效率不高,先截了一次放20个烟花的截图:
最后我冒着卡死的风险搞了一次放1000个烟花的效果,居然还可以运行,截图如下:
如果大家要测试效率的话,用把变量maxFrame调大些就可以了。
本篇文章就到此结束了。文章如有什么地方写得不妥,欢迎提出。另外,如果有任何不解的地方,可以在博客下方留言或者新浪微博@Yorhom,当然也可以发邮件,邮箱:wangyuehao1999@gmail.com,我会尽我所能帮你解决。
支持就是最大的鼓励!
----------------------------------------------------------------
欢迎大家转载我的文章。
转载请注明:转自Yorhom's Game Box
http://blog.csdn.net/yorhomwang
欢迎继续关注我的博客