『HTML5夢幻之旅』-繽紛多姿的煙花效果

天花無數月中開,五采祥雲繞絳臺。墮地忽驚星彩散,飛空旋作雨聲來。怒撞玉斗翻晴雪,勇踏金輪起疾雷。更漏已深人漸散,鬧竿挑得彩燈回。

——明·瞿佑·《煙火戲》

記得每年過春節的那段時間,除了欣賞隆冬的景色,剩下的就是欣賞天空中美麗的煙花了。

成都的冬天,天空中總是灰濛濛的,像是織了一層薄薄的輕紗,把陽光擋走了一部分。路邊的楓樹上,沒有了夏日整天“知了”,“知了”的小傢伙,是否有鳥兒,我卻也忘了。樹上的楓葉寥寥無幾,可能是在某一時候,悄無聲息地飄落了;有時路過一棵年歲已高的樹,也不知是地球引力還是什麼的原因,一片葉子會自然地落下來,不留神的話就會掉到你頭頂上,頂着它走幾里路了,還沒發現。

大冷的天,躲在屋裏,有時大風掛起,看着不停散落的楓葉,都開始害怕他們會凍成冰。有時敲代碼不知不覺就到了傍晚,天更灰了,回身看看窗外的楓樹,只見一片片的紅雲飄逸在眼前,隨着風起而凋零。

除夕夜裏,一般是在親戚家過的,吃完了飯,一家人便一邊欣賞提前放飛的煙花,一邊聊天。屋裏暖暖的,想到還在外面勞作的人們,不覺得會爲他們打個寒戰。

有時我和父母還有哥哥會提前回家,告別了衆親戚,便往屋裏趕,希望還能趕上春節聯歡晚會的開始(雖然現在很多人討厭看春節聯歡晚會,但我想這是一種傳統,搞得不好可以提意見,但是好的傳統應該繼續傳承下去,就像類的繼承一樣)。父親是個不愛花冤枉錢的人,去某個地方從來不打車,要不自己走,要不就自己騎車,或者自己開車。因此在走回去的路上,我又可以觀賞這隆冬的華麗夜景了。

回家後,第一件事就是把年貨拿出來,不停地吃,父親一向不許我吃零食,但是過節的時候從來不阻止。記得有一年,父親叫我和哥哥把所有吃剩的瓜子殼,橘子皮都扔在地上,我說難道不難收拾嗎?父親則說到時候掃一下就可以了,仍在地上纔有節日的氣氛。到現在來想想,過節不就是要氣氛嗎?沒了氣氛,也就沒了溫馨,沒了溫馨,這節日還有什麼好過的呢?

當鐘上的時針和分針都指在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);
};

代碼清單1

二,煙花類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();
}

代碼清單2
這段代碼其實不難理解,首先和拖尾類一樣,繼承自LSprite,然後把前三個參數保存進自身屬性裏面,中間有一段代碼,如下:

self.angle = 20;
self.count = 18;

代碼清單3

這兩行代碼看似平凡,卻十分重要。由於我們的煙花是一圈一圈的,所以,我們在現實煙花噴出來的粒子的時候,要計算出每個煙花的位置。要確定位置,就要確定每個煙花的角度,以及所有煙花粒子的個數,爲了實現這個,我們設置這兩個屬性。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);
	}
};

代碼清單4
前兩行代碼跳過,因爲js程序員都應該知道。然後我們跳到最重要的循環環節,整理後代碼如下:

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);
}

代碼清單5
首先我們爲了達到粒子環形圍繞效果,我們通過循環,取出每個點的角度,並且通過Math.sin()和Math.cos()兩個函數確定該粒子的位置。然後我們畫出一個圓形,顏色是我們實例化時給的color參數的值,上面我們已經把它保存起來了,所以這裏直接用。畫好之後,我們給這個粒子建立拖尾效果。該粒子拖尾的位置是我們保存好的x,y參數。接着通過to方法讓改拖尾移動到我們指定的位置。當移動到位後,我們就通過onComplete加入完成時的函數,將該煙花類的mode設置爲"complete",因爲我們在上面更改了to方法,所以可以自定義onComplete裏的東西了。

煙花類就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;
					}
				}
			});
		}
	}
}

代碼清單6
代碼都加了註釋,我只講一下設計方案:因爲我們的煙花是五顏六色的,所以我們將要有的顏色全部放入colorArray中,然後我們在main中初始化層,並加入背景,音樂,時間軸事件。在時間軸事件觸發的onframe函數中,我們通過addFireworks來加煙花。在addFireworks中,我們首先取出一個煙花的顏色,並以這種顏色畫出相應的煙花,然後通過拖尾效果中的to方法送這個煙花上天,然後在上天動作完成的時候,我們加入散開的粒子效果,如果我們反覆調用addFireworks就會反覆出現煙花。由於我們的界面上不能出現太多的煙花,因爲一方面會顯得擁擠看不清楚效果,另一方面就是會導致界面很卡。爲了解決這個問題,我們通過,maxFrame和frameIndex兩個變量來控制。當onframe每觸發一次,我們就將frameIndex加一,然後判斷是否小於maxFrame,如果是,就調用addFireworks(),因爲我們在上面定義的maxFrame爲4,所以最多加4個煙花到界面上。但是如果我們不把frameIndex重新設置爲0的話,且不移除煙花的話,那4個煙花就會一直在屏幕上,一不會消失,而不會重新加入。爲了實現這些,我們加入循環,在循環裏通過判斷mode是否爲"complete"來移除對象,通過判斷fireworksLayer裏的對象是否被移除完了來判斷是否把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

歡迎繼續關注我的博客

發佈了67 篇原創文章 · 獲贊 45 · 訪問量 93萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章