天花無數月中開,五采祥雲繞絳臺。墮地忽驚星彩散,飛空旋作雨聲來。怒撞玉斗翻晴雪,勇踏金輪起疾雷。更漏已深人漸散,鬧竿挑得彩燈回。
——明·瞿佑·《煙火戲》
記得每年過春節的那段時間,除了欣賞隆冬的景色,剩下的就是欣賞天空中美麗的煙花了。
成都的冬天,天空中總是灰濛濛的,像是織了一層薄薄的輕紗,把陽光擋走了一部分。路邊的楓樹上,沒有了夏日整天“知了”,“知了”的小傢伙,是否有鳥兒,我卻也忘了。樹上的楓葉寥寥無幾,可能是在某一時候,悄無聲息地飄落了;有時路過一棵年歲已高的樹,也不知是地球引力還是什麼的原因,一片葉子會自然地落下來,不留神的話就會掉到你頭頂上,頂着它走幾里路了,還沒發現。
大冷的天,躲在屋裏,有時大風掛起,看着不停散落的楓葉,都開始害怕他們會凍成冰。有時敲代碼不知不覺就到了傍晚,天更灰了,回身看看窗外的楓樹,只見一片片的紅雲飄逸在眼前,隨着風起而凋零。
除夕夜裏,一般是在親戚家過的,吃完了飯,一家人便一邊欣賞提前放飛的煙花,一邊聊天。屋裏暖暖的,想到還在外面勞作的人們,不覺得會爲他們打個寒戰。
有時我和父母還有哥哥會提前回家,告別了衆親戚,便往屋裏趕,希望還能趕上春節聯歡晚會的開始(雖然現在很多人討厭看春節聯歡晚會,但我想這是一種傳統,搞得不好可以提意見,但是好的傳統應該繼續傳承下去,就像類的繼承一樣)。父親是個不愛花冤枉錢的人,去某個地方從來不打車,要不自己走,要不就自己騎車,或者自己開車。因此在走回去的路上,我又可以觀賞這隆冬的華麗夜景了。
回家後,第一件事就是把年貨拿出來,不停地吃,父親一向不許我吃零食,但是過節的時候從來不阻止。記得有一年,父親叫我和哥哥把所有吃剩的瓜子殼,橘子皮都扔在地上,我說難道不難收拾嗎?父親則說到時候掃一下就可以了,仍在地上纔有節日的氣氛。到現在來想想,過節不就是要氣氛嗎?沒了氣氛,也就沒了溫馨,沒了溫馨,這節日還有什麼好過的呢?
當鐘上的時針和分針都指在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,當然也可以發郵件,郵箱:[email protected],我會盡我所能幫你解決。
支持就是最大的鼓勵!
----------------------------------------------------------------
歡迎大家轉載我的文章。
轉載請註明:轉自Yorhom's Game Box
http://blog.csdn.net/yorhomwang
歡迎繼續關注我的博客