整合營銷服務商

          電腦端+手機端+微信端=數(shù)據(jù)同步管理

          免費咨詢熱線:

          使用 HTML5 Canvas 和 JavaScript 開發(fā)動畫氣泡:分步教程


          家好! 歡迎來到本教程,我們將深入了解使用 HTML 畫布和 JavaScript 在代碼中創(chuàng)建有趣的氣泡的世界。 最好的部分? 我們將只使用一點 HTML 和所有 JavaScript,而不是 CSS 來實現(xiàn)所有這一切。

          揭示概念

          今天,我們要掌握以下幾個概念:

          使用畫布上下文的 arc 方法創(chuàng)建圓。

          利用 requestAnimationFrame 函數(shù)實現(xiàn)平滑的圓形動畫。

          利用 JavaScript 類的強大功能來創(chuàng)建多個圓圈,而無需重復代碼。

          向我們的圓圈添加描邊樣式和填充樣式以獲得 3D 氣泡效果。

          你可以跟著我一起看,或者如果你想看源代碼,可以使用最終的codepen

          入門

          首先,我們需要一個 HTML5 Canvas 元素。 Canvas 是創(chuàng)建形狀、圖像和圖形的強大元素。 這就是氣泡將產(chǎn)生的地方。 讓我們來設置一下 -

          <canvas id="canvas"></canvas>

          為了使用畫布做任何有意義的事情,我們需要訪問它的上下文。 Context 提供了在畫布上渲染對象和繪制形狀的接口。

          讓我們訪問畫布及其上下文。

          const canvas = document.getElementById('canvas');
          const context = canvas.getContext('2d');

          我們將設置畫布以使用整個窗口的高度和寬度 -

          canvas.width = window.innerWidth;
          canvas.height = window.innerHeight;

          讓我們通過添加一些 css 為畫布提供一個漂亮的舒緩淺藍色背景。 這是我們要使用的唯一 CSS。 如果您愿意,也可以使用 JavaScript 來完成此操作。

          #canvas {
            background: #00b4ff;
          }

          是時候創(chuàng)造泡泡了!

          讓我們進入有趣的部分。 我們將通過單擊畫布來創(chuàng)建氣泡。 為了實現(xiàn)這一點,我們首先創(chuàng)建一個點擊事件處理程序:

          canvas.addEventListener('click', handleDrawCircle);

          由于我們需要知道在畫布上單擊的位置,因此我們將在句柄 DrawCircle 函數(shù)中跟蹤它并使用事件的坐標 -

          //We are adding x and y here because we will need it later.
          let x, y
          const handleDrawCircle = (event) => {
            x = event.pageX;
            y = event.pageY;
          
          // Draw a bubble!
            drawCircle(x, y);
          };

          用圓弧法畫圓

          為了創(chuàng)建圓圈,我們將利用畫布上下文中可用的 arc 方法。 Arc 方法接受 x 和 y - 圓心、半徑、起始角和結(jié)束角,對于我們來說,這將是 0 和 2* Math.PI,因為我們正在創(chuàng)建一個完整的圓。

          const drawCircle = (x, y) => {
            context.beginPath();
            context.arc(x, y, 50, 0, 2 * Math.PI);
            context.strokeStyle = 'white';
            context.stroke();
          };


          使用 requestAnimationFrame 方法移動圓圈

          現(xiàn)在我們有了圓圈,讓我們讓它們移動,因為……

          GIF



          請記住,當我們創(chuàng)建圓時,我們使用了 arc 方法,它接受 x 和 y 坐標 - 圓的中心。 如果我們快速移動圓的 x 和 y 坐標,就會給人一種圓在移動的印象。 讓我們試試吧!

          //Define a speed by which to increment to the x and y coordinates
          const dx = Math.random() * 3;
          const dy = Math.random() * 7;//Increment the center of the circle with this speed
          x = x + dx;
          y = y - dy;

          我們可以將其移至函數(shù)內(nèi) -

          let x, y;
          const move = () => {
            const dx = Math.random() * 3;
            const dy = Math.random() * 7;  x = x + dx;
            y = y - dy;
          };

          為了讓我們的圓圈無縫移動,我們將創(chuàng)建一個動畫函數(shù)并使用瀏覽器的 requestAnimationFrame 方法來創(chuàng)建一個移動的圓圈。

          const animate = () => {
            context.clearRect(0, 0, canvas.width, canvas.height);
            move();
              drawCircle(x,y);  requestAnimationFrame(animate);
          };//Don't forget to call animate at the bottom 
          animate();



          創(chuàng)建粒子:引入粒子類

          現(xiàn)在我們已經(jīng)創(chuàng)建了一個圓圈,是時候創(chuàng)建多個圓圈了!

          但在我們創(chuàng)建多個圓圈之前,讓我們準備一下我們的代碼。為了避免重復我們的代碼,我們將使用類并引入 Particle 類。 粒子是我們動態(tài)藝術(shù)作品和動畫的構(gòu)建塊。 每個氣泡都是一個粒子,具有自己的位置、大小、運動和顏色屬性。 讓我們定義一個 Particle 類來封裝這些屬性:

          class Particle {
            constructor(x = 0, y = 0) {}
            draw() {
              // Drawing the particle as a colored circle
              // ...
            }  move() {
              // Implementing particle movement
              // ...
            }
          }

          讓我們將一些已設置的常量移至 Particle 類 -

          class Particle {
            constructor(x = 0, y = 0) {
              this.x = x;
              this.y = y;
              this.radius = Math.random() * 50;
              this.dx = Math.random() * 3;
              this.dy = Math.random() * 7;
            }
            draw() {
              // Drawing the particle as a colored circle
              // ...
            }  move() {
              // Implementing particle movement
              // ...
            }
          }

          draw 方法將負責在畫布上渲染粒子。 我們已經(jīng)在drawCircle中實現(xiàn)了這個功能,所以讓我們將它移動到我們的類中并將變量更新為類變量

          class Particle {
            constructor(x = 0, y = 0) {
              this.x = x;
              this.y = y;
              this.radius = Math.random() * 50;
              this.dx = Math.random() * 3;
              this.dy = Math.random() * 7;
              this.color = 'white';
            }
            draw() {
              context.beginPath();
              context.arc(this.x, this.y, this.radius, 0, 2 * Math.PI);
              context.strokeStyle = this.color;
              context.stroke();    context.fillStyle = this.color;
              context.fill();
            }  move() {}
          }

          同樣,讓我們在類中移動 move 函數(shù) -

          move() {
              this.x = this.x + this.dx;
              this.y = this.y - this.dy;
          }

          現(xiàn)在,我們需要確保在事件處理程序中調(diào)用 Particle 類。

          const handleDrawCircle = (event) => {
            const x = event.pageX;
            const y = event.pageY;
            const particle = new Particle(x, y);
          };canvas.addEventListener('click', handleDrawCircle);

          由于我們需要在 animate 函數(shù)中訪問該粒子,以便調(diào)用其 move 方法,因此我們將該粒子存儲在一個名為 molecularArray 的數(shù)組中。 當創(chuàng)建大量粒子時,這個數(shù)組也會很有幫助。 這是反映這一點的更新代碼 -

          const particleArray = [];
          const handleDrawCircle = (event) => {
            const x = event.pageX;
            const y = event.pageY;  const particle = new Particle(x, y);
            particleArray.push(particle);
          };canvas.addEventListener('click', handleDrawCircle);

          記得也要更新動畫功能 -

          此時,您將在屏幕上看到這個粒子 -



          驚人的! 現(xiàn)在,到了有趣的部分! 讓我們創(chuàng)建很多圓圈并設計它們的樣式,使它們看起來像氣泡。

          為了創(chuàng)建大量氣泡,我們將使用 for 循環(huán)創(chuàng)建粒子并將它們添加到我們在此處創(chuàng)建的粒子數(shù)組中。

          const handleDrawCircle = (event) => {
            const x = event.pageX;
            const y = event.pageY;
            for (let i = 0; i < 50; i++) {
              const particle = new Particle(x, y);
              particleArray.push(particle);
            }
          };canvas.addEventListener('click', handleDrawCircle);

          在動畫函數(shù)中,我們將通過清除畫布并在新位置重新繪制粒子來不斷更新畫布。 這會給人一種圓圈在移動的錯覺。

          const animate = () => {
            context.clearRect(0, 0, canvas.width, canvas.height);
            particleArray.forEach((particle) => {
              particle?.move();
              particle?.draw();
            });  requestAnimationFrame(animate);
          };animate();


          現(xiàn)在我們有了移動的氣泡,是時候給它們添加顏色,使它們看起來像氣泡了!

          我們將通過向氣泡添加漸變填充來實現(xiàn)此目的。 這可以使用 context.createRadialGradient 方法來完成。

          const gradient = context.createRadialGradient(
            this.x,
            this.y,
            1,
            this.x + 0.5,
            this.y + 0.5,
            this.radius
          );
          gradient.addColorStop(0.3, 'rgba(255, 255, 255, 0.3)');
          gradient.addColorStop(0.95, '#e7feff');context.fillStyle = gradient;



          總結(jié)

          恭喜! 您剛剛僅使用 HTML Canvas 和 JavaScript 創(chuàng)建了一些超級有趣的東西。 您已經(jīng)學習了如何使用 arc 方法、利用 requestAnimationFrame、利用 JavaScript 類的強大功能以及使用漸變設計氣泡以實現(xiàn) 3D 氣泡效果。

          請隨意嘗試顏色、速度和大小,使您的動畫真正獨一無二。

          請隨意嘗試顏色、速度和大小,使您的動畫真正獨一無二。

          我希望您在學習本教程時能像我在創(chuàng)建它時一樣獲得樂趣。 現(xiàn)在,輪到你進行實驗了。 我很想看看你是否嘗試過這個以及你創(chuàng)造了什么。 與我分享您的代碼鏈接,我很樂意查看。


          試,程序員極力避免的事情,因為這樣只會在代碼中產(chǎn)生更多的錯誤。.

          即使是最優(yōu)秀的程序員,也會發(fā)現(xiàn)自己沒有辦法寫,沒有錯誤的代碼。這就是為什么你應該總是需要調(diào)試代碼。

          調(diào)試JavaScript代碼最佳方法之一是console.log()。除此之外還有更好的辦法。

          這就是本文的重點講述與控制臺交互的方法。在復雜的ide中輸入consol可以提供自動完成提示功能。

          除了console.log(),這里還有其他更好的選擇。使用這些選項可以讓調(diào)試過程變得更加容易和更快。


          console.warn()和console.error()

          當存在可以停止應用程序工作的錯誤時,使用console.log來調(diào)試它是行不通的。

          這會是你的控制臺消息變得異常混亂,讓你找不到你想要找的消息。

          使用console.warn() 和 console.error() 是克服這個問題的好方法。

          console.warn("This is a warning");


          console.error("This is an error")

          時間operations

          想看看這段代碼運行需要多長時間?

          使用console.time()

          首先,創(chuàng)建一個計時器并為其指定一個唯一的名稱。

          console.time("Loop timer")


          然后,運行該代碼段。

          for(i = 0; i < 10000; i++){
              // Some code here
          }

          然后調(diào)用 timeEnd().

          console.timeEnd("Loop timer")

          這是所有的代碼。

          console.time("Loop timer")
          for(i = 0; i < 10000; i++){
              // Some code here
          }
          console.timeEnd("Loop timer")


          這對于需要一些時間密集型應用程序非常有用,例如神經(jīng)網(wǎng)絡或 HTML Canvas 讀取。

          最終代碼的運行

          想看看函數(shù)是如何被調(diào)用的嗎?

          function trace(){
              console.trace()
          }
          function randomFunction(){
              trace();
          }

          在這里,有一個名為randomFunction 調(diào)用trace,它又調(diào)用console.trace()

          所以當你調(diào)用randomFunction, 你會得到類似如下的輸出。


          上圖顯示的那個匿名的方法調(diào)用了 randomFunction, 然后調(diào)用 trace().

          控制臺消息分組

          對控制臺消息進行分組,可以使控制臺更易于閱讀。

          console.log("Test1!");
          
          console.group("My message group");
          
          console.log("Test2!");
          console.log("Test2!");
          console.log("Test2!");
          
          console.groupEnd()

          所有的 Test2 歸于 ‘My message group’組之下.


          清除控制臺消息

          如果你遵循本教程,那么你的控制臺將會非常滿。讓我們把它清除掉。

          console.clear();

          下面就是結(jié)果。


          沒有什么特別的,我只是又清除了一遍,讓我們繼續(xù)。

          表格

          讓我們添加表格,以更好的可視化數(shù)據(jù),想象一下我們有兩個對象。

          var person1 = {name: "Weirdo", age : "-23", hobby: "singing"}
          var person2 = {name: "SomeName", age : "Infinity", hobby: "programming"}

          簡單的使用console.log 只會讓數(shù)據(jù)看起來很混亂。


          使用表格就會更好一點。

          console.table({person1, person2})


          從未見過JavaScript控制臺可以如此的干凈,對吧?

          在控制臺中使用CSS ?

          是的,你沒看錯,你可以將css添加到控制臺。

          console.log("%c I love JavaScript!", 
            "color: red; background-color: lightblue; border: solid");

          注意這個%c 標識. 這就是發(fā)揮魔法的地方。.


          感謝你的閱讀,謝謝!

          lt;meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>

          <html>

          <body>

          <canvas id='canvas'></canvas>

          <div id="write"></div>

          </body>

          </html>

          <script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>

          <script>

          //畫布

          var c=document.getElementById('canvas');

          var ctx=c.getContext('2d');

          //畫布尺寸

          var h=650;

          var w=800;

          c.width=w;

          c.height=h;

          //背景數(shù)量

          var num=100;

          //大紅尺寸

          var gh=h/num;

          var gw=w/num;

          //小綠尺寸

          var gamex=40;

          var gamey=30;

          //背景布置

          function bk(){

          for(var x=0;x<num;x++){

          for(var y=0;y<num;y++){

          ctx.fillStyle="green";

          ctx.fillRect(10*(x-1)+x,10*(y-1)+y,gw,gh);

          }

          }

          }

          //定義小綠數(shù)量

          var sts=new Array();

          //定義小紅數(shù)量

          var drs=new Array();

          //小紅小綠范圍內(nèi)相遇刪除對方

          function dels(){

          if(sts.length>0){

          for(var i=0;i<sts.length;i++){

          //范圍大小

          var a=sts[i]['x']+20;

          var b=sts[i]['x']-20;

          var aa=sts[i]['y']+20;

          var bb=sts[i]['y']-20;

          $('#write').text(a+'---'+b);

          for(var s=0;s<drs.length;s++){

          //判斷是否在范圍內(nèi)

          if((drs[s]['x']<a && drs[s]['x']>b) && (drs[s]['y']<aa && drs[s]['y']>bb)){

          //sts.splice(i,1);//刪除小綠

          drs.splice(s,1);//刪除小紅

          }

          }

          }

          }

          }

          //小紅數(shù)量循環(huán)

          function drss(){

          var dr=new Array();

          dr['x']=Math.floor((Math.random()*w)+1);

          dr['y']=0;

          //dr['y']=Math.floor((Math.random()*h)+1);

          drs.push(dr);

          if(drs.length>0){

          for(var i=0;i<drs.length;i++){

          if(drs[i]['y']>h){

          drs.splice(i,1);

          }else{

          drs[i]['y']+=1;

          }

          ctx.fillStyle="orange";

          ctx.fillRect(drs[i]['x'],drs[i]['y'],gw,gh);

          }

          }

          }

          //小綠數(shù)量循環(huán)

          function st(){

          ctx.fillStyle="black";

          var st=new Array();

          st['x']=10*(gamex-1)+gamex+10;

          st['y']=10*(gamey-1)+gamey-10;

          sts.push(st);

          ctx.fillRect(10*(gamex-1)+gamex+10,10*(gamey-1)+gamey-10,gw,gh);

          }

          //小綠移動

          function stsup(){

          if(sts.length>0){

          for(var i=0;i<sts.length;i++){

          if(sts[i]['y']<0){

          sts.splice(i,1);

          }else{

          sts[i]['y']-=1;

          }

          ctx.fillStyle="red";

          ctx.fillRect(sts[i]['x'],sts[i]['y'],gw,gh);

          }

          }

          }

          //大紅位置移動

          function game(gamex,gamey){

          ctx.fillStyle="red";

          //ctx.fillRect(10*(gamex-1)+gamex,10*(gamey-1)+gamey,gw,gh);

          ctx.fillRect(10*(gamex-1)+gamex,10*(gamey-1)+gamey,20,20);

          }

          bk();

          game(gamex,gamey);

          //時間戳

          setInterval(function(){

          //按鍵判斷

          document.onkeydown=function(event){

          var e = event || window.event || arguments.callee.caller.arguments[0];

          if(e.keyCode=='37'){

          gamex=gamex-1;

          }

          else if(e.keyCode=='38'){

          gamey=gamey-1;

          }

          else if(e.keyCode=='39'){

          gamex=gamex+1;

          }

          else if(e.keyCode=='40'){

          gamey=gamey+1;

          }

          if(e.keyCode=='32'){

          st();

          }

          }

          //清空畫布

          c.width=w;

          c.height=h;

          bk();

          game(gamex,gamey);

          drss();

          stsup();

          dels();

          },10);

          </script>


          主站蜘蛛池模板: 久久久久人妻一区精品| 色久综合网精品一区二区| 成人一区专区在线观看| 无码人妻AⅤ一区二区三区水密桃| 国产裸体舞一区二区三区| 国产在线一区观看| 久久婷婷色一区二区三区| 色狠狠色噜噜Av天堂一区| 蜜桃无码AV一区二区| 一区二区三区在线| 久久精品岛国av一区二区无码| 免费高清av一区二区三区| 亚洲天堂一区在线| 一区二区三区精品视频| 久久国产精品无码一区二区三区| 丰满人妻一区二区三区视频| 国模精品视频一区二区三区| 国产成人精品一区二区三区无码| 少妇无码一区二区二三区| 最新中文字幕一区| 一区二区视频在线免费观看| 99热门精品一区二区三区无码| 日本高清无卡码一区二区久久| 在线|一区二区三区四区| 精品人妻一区二区三区四区| 精品中文字幕一区二区三区四区| 亚洲一区二区三区香蕉| 国产一区二区三区在线免费| 伊人色综合一区二区三区影院视频| 久夜色精品国产一区二区三区| 成人免费观看一区二区| 国产一区二区三区内射高清| eeuss鲁片一区二区三区| 国产AV午夜精品一区二区三| 精品亚洲AV无码一区二区 | 无码精品人妻一区二区三区漫画| 日韩人妻无码一区二区三区 | 全国精品一区二区在线观看| 美日韩一区二区三区| 中文字幕一区视频| 久久综合精品国产一区二区三区|