摘要:多代碼,慎讀預(yù)覽完整項(xiàng)目預(yù)覽預(yù)覽地址屬性設(shè)計(jì)煙花狀態(tài)煙花應(yīng)有三個(gè)狀態(tài)升空等待炸裂炸裂后煙花發(fā)射點(diǎn),爆炸點(diǎn),升空后等待炸裂時(shí)間,炸裂后微粒個(gè)數(shù),煙花半徑煙花炸裂后微粒自身位置,自身大小,自身速度,最大煙花半徑。
多代碼,慎讀!!!
預(yù)覽完整項(xiàng)目預(yù)覽----預(yù)覽地址;
屬性設(shè)計(jì)煙花狀態(tài):煙花應(yīng)有三個(gè)狀態(tài):
升空
等待炸裂
炸裂后
煙花:發(fā)射點(diǎn)(x, y),爆炸點(diǎn)(xEnd, yEnd),升空后等待炸裂時(shí)間(wait),炸裂后微粒個(gè)數(shù)(count),煙花半徑(radius)
煙花炸裂后微粒:自身位置(x, y),自身大小(size),自身速度(rate),最大煙花半徑(radius)。
config:為全局變量,以及控制參數(shù),包括畫布寬高,設(shè)定煙花屬性等。
設(shè)定全局變量const config = { width: 360, height: 600, canvases: ["bg", "firework"], skyColor: "210, 60%, 5%, 0.2)", fireworkTime:{min:30,max:60}, //煙花參數(shù)本身有默認(rèn)值 傳入undefined則使用默認(rèn)參數(shù) fireworkOpt:{ x: undefined, y: undefined, xEnd: undefined, yEnd: undefined, count: 300, //炸裂后粒子數(shù) wait: undefined, //消失后 => 炸裂 等待時(shí)間 } }構(gòu)建微粒類
class Particle{ //默認(rèn)值寫法 constructor({x, y, size = 1, radius = 1.2} = {}){ this.x = x; this.y = y; this.size = size; this.rate = Math.random(); //每個(gè)微粒移動(dòng)的速度都是隨機(jī)不同的 this.angle = Math.PI * 2 * Math.random(); //每個(gè)微粒的偏移角度 //每次微粒移動(dòng)速度分解為橫縱坐標(biāo)的移動(dòng)。 this.vx = radius * Math.cos(this.angle) * this.rate; this.vy = radius * Math.sin(this.angle) * this.rate; } go(){ this.x += this.vx; this.y += this.vy; this.vy += 0.02; //重力影響 y越大實(shí)際越偏下 //空氣阻力 this.vx *= 0.98; this.vy *= 0.98; } //畫出微粒的位置 render(ctx){ this.go(); ctx.beginPath(); ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2, false); ctx.fill(); } }構(gòu)建煙花類
class Firework{ constructor({x, y = config.height, xEnd, yEnd, count = 300, wait} = {}){ //煙花自身屬性 this.x = x || config.width / 8 + Math.random() * config.width * 3 / 4; this.y = y; this.xEnd = xEnd || this.x; this.yEnd = yEnd || config.width / 8 + Math.random() * config.width * 3 / 8; this.size = 2; this.velocity = -3; this.opacity = 0.8; this.color = `hsla(${360 * Math.random() | 0},80%,60%,1)`; this.wait = wait || 30 + Math.random() * 30; //微粒個(gè)數(shù)等 this.count = count; this.particles = []; this.createParticles(); this.status = 1; } //創(chuàng)建微粒 createParticles(){ for(let i = 0;i < this.count; ++i){ this.particles.push(new Particle({x:this.xEnd, y:this.yEnd})); } } //升空 rise(){ this.y += this.velocity * 1; this.velocity += 0.005; //升空時(shí)產(chǎn)生的阻力 //煙花升空到目標(biāo)位置開始漸隱 if(this.y - this.yEnd <= 50){ this.opacity = (this.y - this.yEnd) / 50; } //如果到了目標(biāo)位置 就開始第二個(gè)狀態(tài) if(this.y <= this.yEnd){ this.status = 2; } } //渲染煙花 煙花所有動(dòng)作完成之后返回false render(ctx){ switch(this.status){ case 1: //升空 ctx.save(); ctx.beginPath(); ctx.globalCompositeOperation = "lighter"; ctx.globalAlpha = this.opacity; ctx.translate(this.x, this.y); ctx.scale(0.8, 2.3); ctx.translate(-this.x, -this.y); ctx.fillStyle = this.color; ctx.arc(this.x + Math.sin(Math.PI * 2 * Math.random()) / 1.2, this.y, this.size, 0, Math.PI * 2, false); ctx.fill(); ctx.restore(); this.rise(); return true; break; case 2: //煙花消失階段,等待炸裂 if(--this.wait <= 0){ this.opacity = 1; this.status = 3; } return true; break; case 3: //炸裂之后 渲染煙花微粒 ctx.save(); ctx.globalCompositeOperation = "lighter"; ctx.globalAlpha = this.opacity; ctx.fillStyle = this.color; for(let i = 0;i < this.particles.length;++i){ this.particles[i].render(ctx); } ctx.restore(); this.opacity -= 0.01; return this.opacity > 0; break; default: return false; } } }放煙花
const canvas = { init: function(){ //一些屬性的設(shè)定 可以不用管 this.setProperty(); this.renderBg(); //循環(huán)體 **主要 this.loop(); }, setProperty: function(){ this.fireworks = []; this.width = config.width; this.height = config.height; this.fireworkTime = (config.fireworkTime.min + (config.fireworkTime.max - config.fireworkTime.min) * Math.random()) | 0; this.bgCtx = document.querySelector("#bg").getContext("2d"); this.fireworkCtx = document.querySelector("#firework").getContext("2d"); }, renderBg(){ this.bgCtx.fillStyle = "hsla(210, 60%, 5%, 0.9)" this.bgCtx.fillRect(0, 0, this.width, this.height); }, loop(){ requestAnimationFrame(this.loop.bind(this)); this.fireworkCtx.clearRect(0, 0, this.width, this.height); //隨機(jī)創(chuàng)建煙花 if(--this.fireworkTime <= 0){ this.fireworks.push(new Firework(config.fireworkOpt)); //每次到點(diǎn)之后重新設(shè)置煙花產(chǎn)生時(shí)間 (|0轉(zhuǎn)化為整數(shù)) this.fireworkTime = (config.fireworkTime.min + (config.fireworkTime.max - config.fireworkTime.min) * Math.random()) | 0; } for(let i = this.fireworks.length - 1; i >= 0; --i){ //渲染煙花 (若返回值為false則移除煙花) !this.fireworks[i].render(this.fireworkCtx) && this.fireworks.splice(i,1); } } } canvas.init();完善
此時(shí)煙花是這樣的,感覺少了點(diǎn)小尾巴。
現(xiàn)在我們每一幀都是清除了畫布,如果要加上小尾巴其實(shí)也很簡單,每一幀都不要清除畫布,而是覆蓋一層新的有透明度的天空上去。
//canvas.loop方法 // this.fireworkCtx.clearRect(0, 0, this.width, this.height); this.fireworkCtx.fillStyle = config.skyColor; this.fireworkCtx.fillRect(0,0,this.width,this.height);
這時(shí)就變成這樣了。
但是,還是缺少了在爆炸瞬間 天空變亮的場(chǎng)景。
那么在畫煙花的時(shí)候,先會(huì)獲取一下煙花的顏色以及透明度。
// *****Firework constructor // this.color = `hsla(${360 * Math.random() | 0},80%,60%,1)`; this.hue = 360 * Math.random() | 0; this.color = `hsla(${this.hue},80%,60%,1)`;
// *****Firework 新增實(shí)例方法 getSkyColor(){ const skyColor = { //只有炸裂階段才返回亮度 lightness: this.status == 3 ? this.opacity : 0 , hue: this.hue }; return skyColor; }
// *****config 修改config的skyColor // skyColor: "hsla(210, 60%, 5%, 0.2)", skyColor: "hsla({hue}, 60%, {lightness}%, 0.2)",
// canvas.loop方法 //this.fireworkCtx.fillStyle = config.skyColor; //每次替換色調(diào)與亮度值。 this.fireworkCtx.fillStyle = config.skyColor.replace("{lightness}", 5 + this.skyColor.lightness * 15).replace("{hue}" , this.skyColor.hue); this.skyColor = { //新增 lightness: 0, hue: 210 }; for(let i = this.fireworks.length - 1; i >= 0; --i){ //新增 天空顏色為最亮的煙花的顏色 this.skyColor = this.skyColor.lightness >= this.fireworks[i].getSkyColor().lightness ? this.skyColor : this.fireworks[i].getSkyColor(); !this.fireworks[i].render(this.fireworkCtx) && this.fireworks.splice(i,1); }
到現(xiàn)在就算是大功告成了。
完整項(xiàng)目github項(xiàng)目地址
如果覺得還不錯(cuò),請(qǐng)star一個(gè)吧。
煙花制作參考鏈接參考了codepen.io上的很多作品。
主要參考 --- fireworks seen in the countryside
fireworks seen in the countryside
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/107572.html
摘要:預(yù)覽完整項(xiàng)目預(yù)覽預(yù)覽地址粒子效果原理在中,可以通過方法來獲取像素?cái)?shù)據(jù)。下例是通過改變像素的數(shù)據(jù)而重新寫出來的文字。不過可能會(huì)造成文字部分地方缺失。煙花效果可以看一下我的上一篇,程序員的小浪漫煙火完整項(xiàng)目項(xiàng)目地址如果覺得還不錯(cuò),請(qǐng)一個(gè)吧。 預(yù)覽 showImg(https://segmentfault.com/img/remote/1460000013379709?w=476&h=361...
摘要:問題安全性和耗能存爭(zhēng)議云計(jì)算已經(jīng)成為全球未來信息產(chǎn)業(yè)發(fā)展的戰(zhàn)略方向,隨著各國都認(rèn)真研究云計(jì)算將為社會(huì)和經(jīng)濟(jì)發(fā)展模式帶來的變革,部署國家戰(zhàn)略,中國也正在推動(dòng)云從概念走向應(yīng)用。 身邊就是一片云 ■ 體驗(yàn) 白領(lǐng)蕭瀟(化名)對(duì)任何科技新知都難以表現(xiàn)出興趣,云?聽說過,是什么?很快她就投入到了對(duì)附近商場(chǎng)打折活動(dòng)的熱切關(guān)注中。其實(shí),像蕭瀟一樣,我們往往享受到了云的便利,卻又對(duì)它視而不見。每一天,...
摘要:問題安全性和耗能存爭(zhēng)議云計(jì)算已經(jīng)成為全球未來信息產(chǎn)業(yè)發(fā)展的戰(zhàn)略方向,隨著各國都認(rèn)真研究云計(jì)算將為社會(huì)和經(jīng)濟(jì)發(fā)展模式帶來的變革,部署國家戰(zhàn)略,中國也正在推動(dòng)云從概念走向應(yīng)用。 身邊就是一片云 ? 體驗(yàn)? 白領(lǐng)蕭瀟(化名)對(duì)任何科技新知都難以表現(xiàn)出興趣,云?聽說過,是什么?很快她就投入到了對(duì)附近商場(chǎng)打折活動(dòng)的熱切關(guān)注中。其實(shí),像蕭瀟一樣,我們往往享受到了云的便利,卻又對(duì)它視而不見。每一...
摘要:預(yù)計(jì)年全國云計(jì)算產(chǎn)業(yè)鏈規(guī)模可能達(dá)到億至一萬億元人民幣,有望占到年戰(zhàn)略性新興產(chǎn)業(yè)以上的產(chǎn)值規(guī)模。但也有分析人士認(rèn)為,云計(jì)算可以節(jié)省大量企業(yè)的硬件成本和軟件成本,而云計(jì)算服務(wù)器所耗費(fèi)的能源應(yīng)該不會(huì)多于大量企業(yè)節(jié)省的能源。 云在哪里?其實(shí),云計(jì)算技術(shù)在網(wǎng)絡(luò)服務(wù)中已經(jīng)隨處可見,例如云桌面、云辦公、云視頻、云游戲、云搜索、云識(shí)別、云U盤等。用戶不必了解其背后的運(yùn)行原理,也無需自備一些硬件和軟件,就可以...
閱讀 2752·2021-11-16 11:45
閱讀 1660·2021-09-26 10:19
閱讀 2055·2021-09-13 10:28
閱讀 2809·2021-09-08 10:46
閱讀 1537·2021-09-07 10:13
閱讀 1533·2019-08-30 13:50
閱讀 1378·2019-08-30 11:17
閱讀 1460·2019-08-29 13:18