日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

用canvas绘制流星夜空

發(fā)布時(shí)間:2024/3/13 编程问答 50 豆豆
生活随笔 收集整理的這篇文章主要介紹了 用canvas绘制流星夜空 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

流星是一種唯美的天文現(xiàn)象,我一度想用所學(xué)知識(shí)將它繪制,最近閱讀MDN上的canvas教程得到啟發(fā),用一個(gè)canvas的長(zhǎng)尾效果繪制流星……

什么是長(zhǎng)尾效果?

我們知道,canvas動(dòng)畫(huà)實(shí)現(xiàn)依賴于畫(huà)布的重繪,通過(guò)不停的清空畫(huà)布,繪制畫(huà)布就能實(shí)現(xiàn)基本的動(dòng)畫(huà)效果。一般使用clearRect方法清除指定矩形區(qū)域,來(lái)實(shí)現(xiàn)重繪。長(zhǎng)尾效果是使用透明的填充色代替clearRect方法來(lái)實(shí)現(xiàn)的。

使用clearRect

吐槽:由于錄屏軟件fps跟不上canvas所以這個(gè)gif圖有點(diǎn)卡頓

使用fillRect

1.透明度為1

可以看出透明度為1時(shí),效果與清除效果一致,我們可以理解為在畫(huà)布上又蓋上了一畫(huà)布 ,遮住了之前所畫(huà)的內(nèi)容所以和清除效果是一樣的。
2.透明度為0 透明度為0的效果,則等價(jià)于沒(méi)有清除畫(huà)布的效果,此時(shí)運(yùn)動(dòng)的球體像一只尾巴不斷變長(zhǎng)的蛇,可以以此猜想,將透明度設(shè)為0~1之間,就能調(diào)整尾巴的長(zhǎng)度,達(dá)到一個(gè)帶尾巴的運(yùn)動(dòng)模糊效果。
3.長(zhǎng)尾效果 因?yàn)椴粩嗌w上透明的畫(huà)布,所以從繪制點(diǎn)到出發(fā)點(diǎn)就產(chǎn)生了一條顏色不斷變淺的路徑,給人視覺(jué)效果就是一個(gè)動(dòng)態(tài)模糊。

流星

可以將流星解構(gòu)為一個(gè)圓形和長(zhǎng)尾效果:

肉眼效果:

實(shí)際效果:

封裝頁(yè)面形狀

使用面向?qū)ο缶幊掏瓿蒫anvas繪制
月亮類(lèi)

class Moon {constructor(x, y, ctx, r = 25) {this.x = x;this.y = y;this.ctx = ctx;this.r = r;}draw() {this.ctx.fillStyle = 'rgba(255,255,255,0.6)';this.ctx.shadowBlur = this.r + 5; //光暈半徑this.ctx.shadowColor = "#fff"; // 光暈顏色this.ctx.arc(this.x, this.y, this.r, 0, Math.PI * 2);this.ctx.fill();} } 復(fù)制代碼

因?yàn)樵铝潦庆o止在頁(yè)面上的,所以只有一個(gè)draw方法,月亮光暈的實(shí)現(xiàn)是把陰影和填充設(shè)為同一顏色,然后讓陰影透明度大于填充透明度,就形成一個(gè)外發(fā)光的效果。
星星類(lèi)

class Star extends Moon {constructor(x, y, ctx, r) {super(x, y, ctx, r);}draw() {this.ctx.fillStyle = 'rgba(255,255,255,0.8)';this.ctx.beginPath();this.ctx.arc(this.x, this.y, this.r, 0, 2 * Math.PI);this.ctx.closePath();this.ctx.fill();}move() {this.x += 0.08;if (this.x > meteorCanvas.width) {this.x = 0;}this.draw();} } 復(fù)制代碼

星星與月亮的唯一區(qū)別是可以移動(dòng),所以用星星類(lèi)去繼承月亮類(lèi),實(shí)現(xiàn)面向?qū)ο蟮睦^承與多態(tài)。
用星星緩慢的向右移動(dòng)可以模擬地球自轉(zhuǎn)帶來(lái)的效果。
流星類(lèi)

class Meteor extends Star {constructor(x, y, ctx, r,angle) {super(x, y, ctx, r);this.angle = angle;}draw() {this.ctx.fillStyle = '#ffffff';this.ctx.rotate(this.angle);this.ctx.translate(100, -meteorCanvas.height / 1.5);this.ctx.beginPath();this.ctx.arc(this.x, this.y, this.r, 0, 2 * Math.PI);this.ctx.closePath();this.ctx.fill();this.ctx.translate(-100, meteorCanvas.height / 1.5);this.ctx.rotate(-this.angle);}move() {this.x += 4;this.y += 1;if (this.x > meteorCanvas.width) {this.x = Math.random() * 5this.y = -2 * meteorCanvas.height + Math.random() * meteorCanvas.height * 3;}this.draw();} } 復(fù)制代碼

同理用流星類(lèi)去繼承星星類(lèi)。
注意的是,流星類(lèi)與星星類(lèi)運(yùn)動(dòng)的不同之處是流星劃過(guò)天空有一個(gè)夾角,所以在繪制時(shí)將畫(huà)布旋轉(zhuǎn)了角度之后,需要回歸原位。
為了讓流星出現(xiàn)的位置不會(huì)太密集,我將流星在y軸出現(xiàn)的位置設(shè)置在-2倍畫(huà)布高度到1倍畫(huà)布高度之間,并在draw方法中將畫(huà)布往上挪了畫(huà)布高度的2/3(同理要將畫(huà)布?xì)w位)。

繪制canvas

流星需要使用長(zhǎng)尾效果渲染,星星需要clearRect重繪,月亮就只需要繪制一次。為了三種形狀互不干擾,我分別使用了不同畫(huà)布去渲染它們。
優(yōu)點(diǎn):互不干擾,繪制邏輯清晰,優(yōu)化渲染。

源碼

const meteorCanvas = document.getElementById('meteor');const starCanvas = document.getElementById('star');const moonCanvas = document.getElementById('moon');const meteors = [], stars = [];meteorCanvas.width = document.body.clientWidth;meteorCanvas.height = document.body.clientHeight;starCanvas.width = document.body.clientWidth;starCanvas.height = document.body.clientHeight / 3;moonCanvas.width = document.body.clientWidth;moonCanvas.height = document.body.clientHeight / 3;const meteorCtx = meteorCanvas.getContext('2d');const starCtx = starCanvas.getContext('2d');const moonCtx = moonCanvas.getContext('2d');init();animate();function init() {for (var i = 0; i < 4; i++) {meteors[i] = new Meteor(Math.random() * meteorCanvas.width,-2 * meteorCanvas.height + Math.random() * meteorCanvas.height * 3,meteorCtx, Math.floor(Math.random() * 2) + 1.5, Math.PI / 7);meteors[i].draw();}for (var i = 0; i < 60; i++) {stars[i] = new Star(Math.random() * starCanvas.width, Math.random() * starCanvas.height,starCtx, Math.random());stars[i].draw();}moon = new Moon(moonCanvas.width - 50, 50, moonCtx)moon.draw();}function animate() {starCtx.clearRect(0, 0, starCanvas.width, starCanvas.height);meteorCtx.fillStyle = `rgba(0, 0, 0, 0.1)`;meteorCtx.fillRect(0, 0, meteorCanvas.width, meteorCanvas.height);for (let meteor of meteors)meteor.move();for (let star of stars)star.move();requestAnimationFrame(animate);}function recover() {for (let meteor of meteors)meteor = null;for (let star of stars)star = null;moon = null;}window.onresize = function () {meteorCanvas.width = document.body.clientWidth;meteorCanvas.height = document.body.clientHeight;starCanvas.width = document.body.clientWidth;starCanvas.height = document.body.clientHeight / 3;moonCanvas.width = document.body.clientWidth;moonCanvas.height = document.body.clientHeight / 3;recover();init();} 復(fù)制代碼

結(jié)語(yǔ)

陪你去看流星雨落在這地球上
讓你的淚落在我肩膀
要你相信我的愛(ài)只肯為你勇敢……

文章隨著《流星雨》的歌聲,也走向了尾聲。人生如流星劃過(guò),轉(zhuǎn)瞬即逝,然而,流星易逝,真情永恒……

總結(jié)

以上是生活随笔為你收集整理的用canvas绘制流星夜空的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。