--- title: 物件建構實作 slug: Learn/JavaScript/Objects/Object_building_practice tags: - Canvas - JavaScript translation_of: Learn/JavaScript/Objects/Object_building_practice ---
{{LearnSidebar}}
{{PreviousMenuNext("Learn/JavaScript/Objects/JSON", "Learn/JavaScript/Objects/Adding_bouncing_balls_features", "Learn/JavaScript/Objects")}}

我們解說完必要的 JavaScript 物件理論以及語法細節,想先幫你把根紮好。接著就透過實作範例,讓你實際建立自己有趣又多彩的 JavaScript 物件。

必備條件: 基礎的計算機素養、了解 HTML 與 CSS 的基本概念、熟悉 JavaScript (參閱〈First steps〉與〈Building blocks〉) 與 OOJS 基本概念 (參閱〈Introduction to objects〉)。
要點: 親手實作物件與物件導向 (OO) 技術。

弄一些彈跳彩球

本文將帶領你實作經典的「彈跳球」展示網頁,讓你了解物件在 JavaScript 中的用處。這些小球會在畫面上四處彈跳,而且互相碰撞時變換顏色。範例成品如下:

此範例將透過 Canvas API 在畫面上繪製球體,requestAnimationFrame API 則是繪製整個動畫;而且你不需先了解此兩個 API。但我們希望在看完本文之後,能引起大家深入探究此兩個 API 的興趣。整個過程會利用某些花俏的物件,並讓你看到幾項有趣技術,像是球體從牆上回彈,並檢查球體是否互相碰撞 (也就是碰撞偵測)。

著手開始

先複製 index.htmlstyle.cssmain.js 檔案到你的本機磁碟中。這些檔案分別具備下列:

  1. 極簡的 HTML 文件,具備 1 個 {{HTMLElement("h1")}} 元素、1 個 {{HTMLElement("canvas")}} 元素可繪製彩球,以及其他元素可將 CSS 與 JavaScript 套用到 HTML 之上。
  2. 一些極簡單的樣式,主要可作為 <h1> 的樣式風格與定位之用,並省去網頁邊緣的捲動棒或空白 (看起來更簡約)。
  3. 某些 JavaScript 可用以設定 <canvas> 元素,另有通用函式可供我們往後使用。

指令碼第一部分就像:

var canvas = document.querySelector('canvas');

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

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

此指令碼將為 <canvas> 元素提供參照,接著於其上呼叫 getContext() 函式,藉以提供能開始繪圖的內文 (Context)。所產生的變數 (ctx) 也就是物件,將直接呈現 canvas 的繪圖區域,讓我們繪製 2D 圖像。

接著設定 widthheight 共 2 個變數,也就是 canvas 元素的寬度與高度 (透過 canvas.widthcanvas.height 屬性呈現) 即等於瀏覽器可視區的寬度與高度 (也就是網頁顯示的區域 — 可經由 {{domxref("Window.innerWidth")}} 與 {{domxref("Window.innerHeight")}} 屬性得知)。

你會看到我們在這裡串連了多個指定式,以快速設定所有變數,而且運作無虞。

剛開始的指令碼後半部如下:

function random(min, max) {
  var num = Math.floor(Math.random()*(max-min)) + min;
  return num;
}

此函式共有 2 組參數 (argument),並會回傳此範圍之內的任意值。

在程式中設定球體的模型

我們的程式會讓一堆彩球在畫面中彈來彈去。因為這些球體的行動方式均相同,所以透過物件呈現這些彩球也合情合理。先在程式碼底部加入下列建構子:

function Ball() {
  this.x = random(0,width);
  this.y = random(0,height);
  this.velX = random(-7,7);
  this.velY = random(-7,7);
  this.color = 'rgb(' + random(0,255) + ',' + random(0,255) + ',' + random(0,255) +')';
  this.size = random(10,20);
}

這裡我們要定義某些屬性,以利彩球能在程式中動作:

屬性講完了,那函式呢?程式中的彩球要實際運作才行。

繪製球體

先將下列 draw() 函式加到 Ball() 的 prototype 之中:

Ball.prototype.draw = function() {
  ctx.beginPath();
  ctx.fillStyle = this.color;
  ctx.arc(this.x, this.y, this.size, 0, 2 * Math.PI);
  ctx.fill();
}

透過此函式,再呼叫我們之前定義在 2D canvas 內文(ctx)中的物件成員,就能讓球體自己在螢幕上畫出自己。此內文就像是白紙一樣,接著就用筆在紙上畫出點東西:

你已經可以開始測試自己的物件了。

  1. 儲存目前的程式碼,在瀏覽器中載入此 HTML 檔案。
  2. 開啟瀏覽器的 JavaScript 主控台,並在主控台開啟時重新整理網頁,讓 canvas 尺寸變更為左側較小型的可視區域。
  3. 鍵入下列程式碼以建立新的球體實例:
    var testBall = new Ball();
  4. 再呼叫其成員:
    testBall.x
    testBall.size
    testBall.color
    testBall.draw()
  5. 輸入最後一行之後,應該就能看到 canvas 上出現自己產生的球體。

更新球體的資料

現在可以繪製彩球了。但在讓球彈跳之前,我們必須先更新幾個函式。將下列程式碼加到 JavaScript 檔案底端,把 update() 函式加到 Ball()prototype 之中:

Ball.prototype.update = function() {
  if((this.x + this.size) >= width) {
    this.velX = -(this.velX);
  }

  if((this.x - this.size) <= 0) {
    this.velX = -(this.velX);
  }

  if((this.y + this.size) >= height) {
    this.velY = -(this.velY);
  }

  if((this.y - this.size) <= 0) {
    this.velY = -(this.velY);
  }

  this.x += this.velX;
  this.y += this.velY;
}

函式的前 4 個部分負責檢查球體是否碰到 canvas 邊緣。如果球體抵達邊緣,我們就反轉相對加速度的方向,讓球反方向行進。以球體向上 (正向 velX) 時為例,接著就會改變水平速度,球體也就反向運動。

在這 4 個情境中,我們:

在各情境中,因為 x/y 座標為球體的中心,所以我們把球體的 size 納入計算,但我們不要球體在回彈之前在半路上就跳出畫面之外。

最後 2 行則是將 velX 與 velY 值分別加入 x\y 座標之中;每次只要呼叫此函式,球體就會依照應有的效果移動。

到這裡沒有問題的話,就開始弄動畫吧!

球體動起來

接著來玩玩吧。我們要加更多球到 canvas 中並開始動畫效果。

  1. 首先要弄個地方儲存所有的彩球。將下方陣列加到現有程式碼底部即可:
    var balls = [];

    所有可提供動畫效果的程式,一般都會採用動畫迴圈,可用以更新程式中的資訊,並接著在動畫的各個畫格上繪製產生的結果。這也是大部分遊戲或類似程式的基礎。

  2. 再將下列程式碼加到現有程式碼底部:
    function loop() {
      ctx.fillStyle = 'rgba(0,0,0,0.25)';
      ctx.fillRect(0,0,width,height);
    
      while(balls.length < 25) {
        var ball = new Ball();
        balls.push(ball);
      }
    
      for(i = 0; i < balls.length; i++) {
        balls[i].draw();
        balls[i].update();
      }
    
      requestAnimationFrame(loop);
    }

    我們的 loop() 函式可進行:

  3. 最後將下列程式碼加入最底端,呼叫函式 1 次讓動畫開始運作。
    loop();

基本就是這樣了。試著儲存並重新整理檔案,讓你的彩球開始跳動吧!

另增碰撞偵測

現在弄點有趣的東西,就把碰撞偵測 (Collision detection) 加進程式裡,讓彩球知道自己碰到其他球了。

  1. 首先將下列函式定義加進你自己定義 update() 函式中 (例如 Ball.prototype.update 區塊):
    Ball.prototype.collisionDetect = function() {
      for(j = 0; j < balls.length; j++) {
        if( (!(this.x === balls[j].x && this.y === balls[j].y && this.velX === balls[j].velX && this.velY === balls[j].velY)) ) {
          var dx = this.x - balls[j].x;
          var dy = this.y - balls[j].y;
          var distance = Math.sqrt(dx * dx + dy * dy);
    
          if (distance < this.size + balls[j].size) {
            balls[j].color = this.color = 'rgb(' + random(0,255) + ',' + random(0,255) + ',' + random(0,255) +')';
          }
        }
      }
    }

    這函式有點複雜,所以現在不瞭解如何運作的也別擔心。解釋如下:

  2. 你也可以在動畫的每一畫格中呼叫此一函式。在 balls[i].update(); 這一行下方新增下列程式碼即可:
    balls[i].collisionDetect();
  3. 儲存並重新整理之後,就能看到球體在碰撞時變更其色彩了!

注意:如果你無法讓此範例順利運作,可比較我們的最後版本 (另可參閱實際執行情形)。

摘要

希望你喜歡撰寫出隨機彩球碰撞範例,其內並包含我們前面說過的多樣物件與 OO 技術!本文應該已提供你有用的物件實作與絕佳的實際文本。

物件實體就到這裡。接著就是你要磨練自己的物件技術了!

另可參閱

{{PreviousMenuNext("Learn/JavaScript/Objects/JSON", "Learn/JavaScript/Objects/Adding_bouncing_balls_features", "Learn/JavaScript/Objects")}}