要過(guò)年了,過(guò)年想到的就是放煙火啦。。。。于是就用canvas寫了個(gè)放煙火的效果,鼠標(biāo)點(diǎn)擊也會(huì)產(chǎn)生煙火,不過(guò)不要產(chǎn)生太多煙火哦,一個(gè)煙火散出的粒子是30到200個(gè)之間,當(dāng)頁(yè)面上的粒子數(shù)量達(dá)到一定的時(shí)候,頁(yè)面就會(huì)很卡咯,我也沒特意去優(yōu)化神馬的。以后有空再說(shuō)吧。
原理很簡(jiǎn)單。。。就寫一個(gè)煙火類以及碎屑類,實(shí)例化后讓它飛起來(lái),然后到達(dá)某個(gè)點(diǎn)后,把這個(gè)煙火對(duì)象的dead屬性置為true,然后再實(shí)例化出一定數(shù)量的碎屑對(duì)象,并且給與碎屑對(duì)象隨機(jī)一個(gè)要到達(dá)的目標(biāo)點(diǎn),然后讓所有碎屑對(duì)象飛過(guò)去就行了。
XML/HTML Code復(fù)制內(nèi)容到剪貼板
- var Boom = function(x,r,c,boomArea,shape){ //煙火對(duì)象
- this.booms = [];
- this.x = x;
- this.y = (canvas.height+r);
- this.r = r;
- this.c = c;
- this.shape = shape || false;
- this.boomArea = boomArea;
- this.theta = 0;
- this.dead = false;
- this.ba = parseInt(getRandom(80 , 200));
- }
- Boom.prototype = {
- _paint:function(){
- ctx.save();
- ctx.beginPath();
- ctx.arc(this.x,this.y,this.r,0,2*Math.PI);
- ctx.fillStyle = this.c;
- ctx.fill();
- ctx.restore();
- },
- _move:function(){
- var dx = this.boomArea.x - this.x , dy = this.boomArea.y - this.y;
- thisthis.x = this.x+dx*0.01;
- thisthis.y = this.y+dy*0.01;
-
- if(Math.abs(dx)<=this.ba && Math.abs(dy)<=this.ba){
- if(this.shape){
- this._shapBoom();
- }
- else this._boom();
- this.dead = true;
- }
- else {
- this._paint();
- }
- },
- _drawLight:function(){
- ctx.save();
- ctx.fillStyle = "rgba(255,228,150,0.3)";
- ctx.beginPath();
- ctx.arc(this.x , this.y , this.r+3*Math.random()+1 , 0 , 2*Math.PI);
- ctx.fill();
- ctx.restore();
- },
- _boom:function(){ //普通爆炸
- var fragNum = getRandom(30 , 200);
- var style = getRandom(0,10)>=5? 1 : 2;
- var color;
- if(style===1){
- color = {
- a:parseInt(getRandom(128,255)),
- b:parseInt(getRandom(128,255)),
- c:parseInt(getRandom(128,255))
- }
- }
-
- var fanwei = parseInt(getRandom(300, 400));
- for(var i=0;i<fragNum;i++){
- if(style===2){
- color = {
- a:parseInt(getRandom(128,255)),
- b:parseInt(getRandom(128,255)),
- c:parseInt(getRandom(128,255))
- }
- }
- var a = getRandom(-Math.PI, Math.PI);
- var x = getRandom(0, fanwei) * Math.cos(a) + this.x;
- var y = getRandom(0, fanwei) * Math.sin(a) + this.y;
- var radius = getRandom(0 , 2)
- var frag = new Frag(this.x , this.y , radius , color , x , y );
- this.booms.push(frag);
- }
- },
- _shapBoom:function(){ //有形狀的爆炸
- var that = this;
- putValue(ocas , octx , this.shape , 5, function(dots){
- var dx = canvas.width/2-that.x;
- var dy = canvas.height/2-that.y;
- for(var i=0;i<dots.length;i++){
- color = {a:dots[i].a,b:dots[i].b,c:dots[i].c}
- var x = dots[i].x;
- var y = dots[i].y;
- var radius = 1;
- var frag = new Frag(that.x , that.y , radius , color , x-dx , y-dy);
- that.booms.push(frag);
- }
- })
- }
- }
XML/HTML Code復(fù)制內(nèi)容到剪貼板
- var Frag = function(centerX , centerY , radius , color ,tx , ty){ //煙火碎屑對(duì)象
- this.tx = tx;
- this.ty = ty;
- this.x = centerX;
- this.y = centerY;
- this.dead = false;
- this.centerX = centerX;
- this.centerY = centerY;
- this.radius = radius;
- this.color = color;
- }
-
- Frag.prototype = {
- paint:function(){
- ctx.save();
- ctx.beginPath();
- ctx.arc(this.x , this.y , this.radius , 0 , 2*Math.PI);
- ctx.fillStyle = "rgba("+this.color.a+","+this.color.b+","+this.color.c+",1)";
- ctx.fill()
- ctx.restore();
- },
- moveTo:function(index){
- thisthis.ty = this.ty+0.3;
- var dx = this.tx - this.x , dy = this.ty - this.y;
- this.x = Math.abs(dx)<0.1 ? this.tx : (this.x+dx*0.1);
- this.y = Math.abs(dy)<0.1 ? this.ty : (this.y+dy*0.1);
- if(dx===0 && Math.abs(dy)<=80){
- this.dead = true;
- }
- this.paint();
- }
- }
XML/HTML Code復(fù)制內(nèi)容到剪貼板
- ctx.save();
- ctx.fillStyle = "rgba(0,5,24,0.1)";
- ctx.fillRect(0,0,canvas.width,canvas.height);
- ctx.restore();
讓煙火形成自己想要的形狀,比如字體,圖片之類的,也很簡(jiǎn)單,就是可以通過(guò)離屏canvas以及canvas的getImageData這個(gè)方法就可以做出來(lái)。離屏canvas,顧名思義就是離開屏幕的,也就是不可見的canvas,直接在js里面用document.createElement("canvas")就可以生成一個(gè)canvas dom對(duì)象了,只要不把這個(gè)dom對(duì)象賦給body,這個(gè)canvas對(duì)象就相當(dāng)于一個(gè)離屏對(duì)象了,我們就可以獲取到這個(gè)離屏canvas的context對(duì)象,然后再用戶看不到的地方做任何我們想做的事情了。
讓煙火形成自己想要的形狀就是先把文字或者圖片畫在離屏canvas上,然后用getImageData獲取畫布上的像素?cái)?shù)組,然后遍歷數(shù)組,獲取有顏色的像素,也就是我們想要的內(nèi)容,保存起來(lái)后,再放到主canvas對(duì)象中顯示出來(lái)。
getImageData的像素處理我之前的博客上有講過(guò),如果不會(huì)用的,請(qǐng)戳:隨便談?wù)動(dòng)胏anvas來(lái)實(shí)現(xiàn)文字圖片粒子化
源碼地址:https://github.com/whxaxes/canvas-test/tree/gh-pages/src/Funny-demo/shotFire