一個半徑爲3的實心圓以畫布的中心(canvas.width/2,canvas.height/2)爲起點,沿着一條曲線進行移動。編寫以下的HTML代碼。html
<!DOCTYPE html> <html> <head> <title>粒子的運動</title> </head> <body> <script> var canvas = document.createElement('canvas'); var ctx = canvas.getContext('2d'); document.body.appendChild(canvas); canvas.width = window.innerWidth; canvas.height = window.innerHeight; ctx.beginPath(); ctx.fillStyle = 'rgba(0, 0, 0, 1)'; ctx.fillRect(0, 0, canvas.width, canvas.height); var angle = 90; var pos = [canvas.width/2,canvas.height/2]; var speed = 6; var curve = 2.5; var index = 1; var color = 'rgba(69,204,255,.95)'; function draw () { var radians = angle*Math.PI/180; pos[0] += Math.cos(radians)* speed+Math.cos(index); pos[1] += Math.sin(radians)* speed+Math.sin(index); angle += curve; ctx.fillStyle = color; ctx.beginPath(); ctx.arc(pos[0],pos[1],3,0,2*Math.PI); ctx.fill(); fade(); window.requestAnimationFrame(draw); } function fade () { ctx.beginPath(); ctx.fillStyle = 'rgba(0, 0, 0, .03)'; ctx.fillRect(0, 0, canvas.width, canvas.height); } window.requestAnimationFrame(draw); </script> </body> </html>
在瀏覽器中打開包含這段HTML代碼的html文件,能夠在瀏覽器窗口中呈現出如圖1所示的動畫效果。canvas
圖1 一個實心圓的運動數組
將圖1中的半徑爲3的實心圓做爲一個基本粒子,抽象一個粒子對象Particle,該對象有表示粒子運動的起始位置的angle、粒子運動的當前位置pos(初始值爲畫布中心[canvas.width/2,canvas.height/2])、粒子運動速度speed、粒子運動角度變化量curve、粒子顏色color和例子編號index等屬性;爲該粒子對象定義move和draw兩個方法,分別完成粒子的位置變化和粒子繪製操做。瀏覽器
爲設定方便起見,給在畫布中心爆裂的粒子預設置3個參數,用變量config來表示。config.num、config.speed和config.curve分別表示3個參數份量。其中,config.num表示畫布中爆裂出的粒子個數,由它計算出粒子運動的起始位置angle;config.speed和config.curve則分別對應粒子運動速度speed和粒子運動角度變化量curve。app
編寫的HTML文件以下。dom
<!DOCTYPE html> <html> <head> <title>爆裂的粒子</title> </head> <body> <script> var canvas = document.createElement('canvas'); var ctx = canvas.getContext('2d'); canvas.width = window.innerWidth; canvas.height = window.innerHeight; document.body.appendChild(canvas); var particles = []; var colors = [ 'rgba(69,204,255,.95)', 'rgba(73,232,62,.95)', 'rgba(255,212,50,.95)', 'rgba(232,75,48,.95)', 'rgba(178,67,255,.95)' ]; var config = {}; config.num=150; config.speed=1; config.curve=0.5; ctx.beginPath(); ctx.fillStyle = 'rgba(0, 0, 0, 1)'; ctx.fillRect(0, 0, canvas.width, canvas.height); ctx.fill(); particles.length = 0; createParticles(); window.requestAnimationFrame(draw); function createParticles() { var n = config.num; for (var i=0; i<n; i++) { var angle = (360/n)*(i+1); particles.push(new Particle(angle,i)); } } function draw () { for (var i=0; i<particles.length; i++) { var p = particles[i]; p.move(); p.draw(); } fade(); window.requestAnimationFrame(draw); } function Particle (angle,index) { this.angle = angle; this.speed = config.speed; this.curve = config.curve; this.color = colors[index%5]; this.index = index; this.pos = [canvas.width/2, canvas.height/2]; } Particle.prototype.move = function() { this.angle += this.curve; var radians = this.angle*Math.PI/180; this.pos[0] += Math.cos(radians)*this.speed+Math.cos(this.index); this.pos[1] += Math.sin(radians)*this.speed+Math.sin(this.index); } Particle.prototype.draw = function () { ctx.fillStyle = this.color; ctx.beginPath(); ctx.arc(this.pos[0],this.pos[1],3,0,2*Math.PI); ctx.fill(); } function fade () { ctx.beginPath(); ctx.fillStyle = 'rgba(0, 0, 0, .03)'; ctx.fillRect(0, 0, canvas.width, canvas.height); ctx.fill(); } </script> </body> </html>
在瀏覽器中打開包含這段HTML代碼的html文件,能夠在瀏覽器窗口中呈現出如圖2所示的動畫效果,150個粒子包在畫布中心爆裂開後,四散運動起來。ide
圖2 爆裂的粒子(num=150,speed = 1,curve = 0.5)函數
爲3個參數設定不一樣的值,能夠呈現出不一樣的動畫效果。給出4組不一樣值的設定,呈現的動畫效果分別如圖三、圖四、圖5和圖6所示。爲避免圖形文件過大,下列的動畫過程均只錄制一個片斷。完整的動畫演示過程請讀者本身打開HTML文件運行程序觀看。動畫
圖3 爆裂的粒子(num=300,speed = 6,curve =1.5)this
圖4 爆裂的粒子(num=300,speed = 2,curve = 1)
圖5 爆裂的粒子(num=300,speed = 100,curve =180)
圖6 爆裂的粒子(num=100,speed = 120,curve =10)
由圖2~圖6可知,不一樣的參數設定,爆裂開來的粒子運動所呈現的動畫效果不一樣。爲此,咱們提供文本框輸入預設數值的方式對3個參數的值進行設定,設定完成後,單擊「Burst!」按鈕,按設定的參數進行動畫效果的呈現。
編寫的HTML代碼以下。
<!DOCTYPE html> <html> <head> <title>爆裂的粒子(可設置參數)</title> <style> form { position:absolute; top:0; left:0; z-index:100; background-color:rgba(200,200,200,.8); padding:8px; font-size:90%; } form input[type=text] { width:30px; border:1px solid #000; text-align:center; } form button { margin:4px auto; border:1px solid #000; display:block; } </style> </head> <body> <form id="settings" onsubmit="return false"> Particles<br/> <input type="text" id="inNum" value="150"/><br/> Speed<br/> <input type="text" id="inSpeed" value="2"/><br/> Curve<br/> <input type="text" id="inCurve" value="1"/><br/> <button id="btnClear">Clear</button> <button id="btnSet">Burst!</button><br/> </form> <script> var canvas = document.createElement('canvas'); var ctx = canvas.getContext('2d'); canvas.width = window.innerWidth; canvas.height = window.innerHeight; document.body.appendChild(canvas); var particles = []; var config = {}; var settings = document.getElementById('settings'); start(); window.requestAnimationFrame(draw); function createParticles() { var n = config.num; for (var i=0; i<n; i++) { var angle = (360/n)*(i+1); particles.push(new Particle(angle,i)); } } function draw () { for (var i=0; i<particles.length; i++) { var p = particles[i]; p.move(); p.draw(); } fade(); window.requestAnimationFrame(draw); } function Particle (angle,index) { this.angle = angle; this.speed = config.speed; this.curve = config.curve; this.color = randColor(90,255) this.index = index; this.pos = [canvas.width/2, canvas.height/2]; } Particle.prototype.move = function() { this.angle += this.curve; var radians = this.angle*Math.PI/180; this.pos[0] += Math.cos(radians)*this.speed+Math.cos(this.index); this.pos[1] += Math.sin(radians)*this.speed+Math.sin(this.index); } Particle.prototype.draw = function () { ctx.fillStyle = this.color; ctx.beginPath(); ctx.arc(this.pos[0],this.pos[1],3,0,2*Math.PI); ctx.fill(); } function randColor(min, max) { var r = Math.floor(Math.random()*(max-min)+min); var g = Math.floor(Math.random()*(max-min)+min); var b = Math.floor(Math.random()*(max-min)+min); return 'rgba('+r+','+g+','+b+',0.95)'; } function fade () { ctx.beginPath(); ctx.fillStyle = 'rgba(0, 0, 0, .03)'; ctx.fillRect(0, 0, canvas.width, canvas.height); ctx.fill(); } function clear () { ctx.beginPath(); ctx.fillStyle = 'rgba(0, 0, 0, 1)'; ctx.fillRect(0, 0, canvas.width, canvas.height); ctx.fill(); particles.length = 0; } function start() { config.num = parseFloat(settings.inNum.value); config.speed = parseFloat(settings.inSpeed.value); config.curve = parseFloat(settings.inCurve.value); createParticles(); } settings.btnSet.addEventListener("click", start); settings.btnClear.addEventListener("click", clear); </script> </body> </html>
在瀏覽器中打開包含這段HTML代碼的html文件,能夠在瀏覽器窗口中呈現出如圖7所示的動畫效果。
圖7 爆裂的粒子(單擊一次Burst!按鈕)
在頁面中,單擊「Clear」按鈕,會清屏,同時置粒子數組的長度爲0,至關於頁面中再也不有運動的粒子。
單擊「Burst!」按鈕,會讀取設置的參數值,同時調用createParticles();向粒子數組中添加從畫布中心爆裂開的粒子。注意:是添加,若數組中原來有運動的粒子,則原來運動的粒子會繼續運動。這樣,屢次單擊「Burst!」按鈕,會呈現出更多有變化的動畫效果。
例如,連續單擊三次「Burst!」按鈕,在瀏覽器窗口呈現出如圖8所示的動畫效果。
圖8 爆裂的粒子(單擊三次Burst!按鈕)
從圖2和圖7的動畫過程能夠看出,一個粒子包在畫布中心爆裂開來後,粒子四散運動,逐漸超出畫布範圍,最終畫布一片空白。雖然咱們能夠像圖8的效果那樣,經過不斷單擊「Burst!」按鈕在畫布中心爆裂開新的粒子包,但這須要人爲控制。固然,也能夠不斷調用createParticles()函數,在畫布中心爆裂新的粒子包,但函數調用的時機須要仔細考慮。
一個可行的辦法是:每當一個粒子運動超出了畫布範圍,能夠認爲該粒子消亡了,從particles數組中刪除該粒子對象。當粒子數組particles中剩餘的粒子數不足config.num的一半時,自動調用createParticles()函數在畫布中心爆裂一個新的粒子包,向粒子數組中添加爆裂的粒子。
編寫的HTML文件以下。
<!DOCTYPE html> <html> <head> <title>爆裂的粒子</title> </head> <body> <script> var canvas = document.createElement('canvas'); var ctx = canvas.getContext('2d'); canvas.width = window.innerWidth; canvas.height = window.innerHeight; document.body.appendChild(canvas); var particles = []; var colors = [ 'rgba(69,204,255,.95)', 'rgba(73,232,62,.95)', 'rgba(255,212,50,.95)', 'rgba(232,75,48,.95)', 'rgba(178,67,255,.95)' ]; var config = {}; config.num=150; config.speed=1; config.curve=0.5; ctx.beginPath(); ctx.fillStyle = 'rgba(0, 0, 0, 1)'; ctx.fillRect(0, 0, canvas.width, canvas.height); ctx.fill(); particles.length = 0; createParticles(); window.requestAnimationFrame(draw); function createParticles() { var n = config.num; for (var i=0; i<n; i++) { var angle = (360/n)*(i+1); particles.push(new Particle(angle,i)); } } function draw () { for (var i=particles.length-1;i>=0; i--) { var p = particles[i]; p.move(); p.draw(); if (p.pos[0]<0 || p.pos[0]>canvas.width || p.pos[1]<0 || p.pos[1]>canvas.height) particles.splice(i, 1); } fade(); if (particles.length<=config.num/2) createParticles(); window.requestAnimationFrame(draw); } function Particle (angle,index) { this.angle = angle; this.speed = config.speed; this.curve = config.curve; this.color = colors[index%5]; this.index = index; this.pos = [canvas.width/2, canvas.height/2]; } Particle.prototype.move = function() { this.angle += this.curve; var radians = this.angle*Math.PI/180; this.pos[0] += Math.cos(radians)*this.speed+Math.cos(this.index); this.pos[1] += Math.sin(radians)*this.speed+Math.sin(this.index); } Particle.prototype.draw = function () { ctx.fillStyle = this.color; ctx.beginPath(); ctx.arc(this.pos[0],this.pos[1],3,0,2*Math.PI); ctx.fill(); } function fade () { ctx.beginPath(); ctx.fillStyle = 'rgba(0, 0, 0, .03)'; ctx.fillRect(0, 0, canvas.width, canvas.height); ctx.fill(); } </script> </body> </html>
在瀏覽器中打開包含這段HTML代碼的html文件,能夠在瀏覽器窗口中呈現出如圖9所示的動畫效果。
圖9 不斷爆裂的粒子包
須要說明的是,對於不一樣的num、speed和curve三個參數的設置,上面的程序大多數狀況下運行狀況良好。但對於如圖6動畫效果所設置的3個參數(num=100,speed = 120,curve =10),呈現的動畫效果如圖10所示。
圖10 不斷爆裂的粒子包(num=100,speed = 120,curve =10)
從圖10看出,畫面基本靜止,這主要因爲按給定的參數,粒子移動一次就會超出畫布範圍,於是不斷刪除粒子、添加粒子,每一個粒子的移動基本是一次性的,即移動一次就超出畫布範圍消亡了。而圖6之因此能夠呈現出動畫效果是由於移出畫布的粒子有可能會本身運動回來。