在我們的彈球演示中新增功能
在本評估中,您需要使用上一篇文章中的彈跳球演示作為起點,並新增一些新的、有趣的特性。
| 先決條件 | 在嘗試本評估之前,您應該已經完成了本模組中的所有文章。 |
|---|---|
| 目標 | 測試對 JavaScript 物件和麵向物件結構的理解 |
起點
要開始本評估,請在本地計算機上的新目錄中建立以下檔案的本地副本:index-finished.html,style.css,以及main-finished.js,它們來自我們上一篇文章。
或者,您可以使用線上編輯器,例如CodePen,JSFiddle,或Glitch。您可以將 HTML、CSS 和 JavaScript 貼上到其中一個線上編輯器中。如果使用的線上編輯器沒有單獨的 JavaScript 面板,請隨意將其內嵌到 HTML 頁面中的 <script> 元素中。
注意:如果您卡住了,您可以透過我們的溝通渠道之一與我們聯絡。
提示和技巧
在您開始之前,有幾點需要提醒您。
- 本評估相當具有挑戰性。在開始編碼之前,請仔細閱讀整個評估內容,並逐個步驟緩慢而謹慎地進行。
- 最好在每個階段執行後儲存演示的單獨副本,這樣如果之後遇到問題,您就可以參考它。
專案簡述
我們的彈跳球演示很有趣,但現在我們要透過新增一個使用者控制的邪惡圓圈來使其更具互動性,如果邪惡圓圈碰到球,就會吞噬它們。我們還想透過建立一個通用的 Shape() 物件,讓我們的球和邪惡圓圈能夠從它繼承,來測試您的物件構建技能。最後,我們要新增一個分數計數器來跟蹤剩餘的球的數量。
以下螢幕截圖展示了完成後的程式的外觀。
為了讓您更好地瞭解,請檢視完成的示例(不要偷看原始碼!)
完成步驟
以下部分描述了您需要做的事情。
建立 Shape 類
首先,建立一個新的 Shape 類。它只有一個建構函式。Shape 建構函式應該與最初 Ball() 建構函式的方式相同,定義 x、y、velX 和 velY 屬性,但不要定義 color 和 size 屬性。
Ball 類應該使用 extends 從 Shape 派生。Ball 的建構函式應該
- 接收與之前相同的引數:
x、y、velX、velY、size和color - 使用
super()呼叫Shape建構函式,並將x、y、velX和velY引數傳遞給它 - 從傳入的引數中初始化它自己的
color和size屬性。
Ball 建構函式應該定義一個名為 exists 的新屬性,用於跟蹤球是否存在於程式中(還沒有被邪惡圓圈吞噬)。它應該是一個布林值 (true/false),在建構函式中初始化為 true。
Ball 類的 collisionDetect() 方法需要一個小小的更新。只有當 exists 屬性為 true 時,才需要考慮球進行碰撞檢測。因此,將現有的 collisionDetect() 程式碼替換為以下程式碼
collisionDetect() {
for (const ball of balls) {
if (!(this === ball) && ball.exists) {
const dx = this.x - ball.x;
const dy = this.y - ball.y;
const distance = Math.sqrt(dx * dx + dy * dy);
if (distance < this.size + ball.size) {
ball.color = this.color = randomRGB();
}
}
}
}
如上所述,唯一增加的是檢查球是否存在——透過在 if 條件語句中使用 ball.exists。
球的 draw() 和 update() 方法定義應該能夠保持與之前完全相同。
此時,嘗試重新載入程式碼——它應該與之前一樣工作,使用我們重新設計的物件。
定義 EvilCircle
現在是時候讓壞傢伙登場了——EvilCircle()!我們的遊戲中只會有一個邪惡圓圈,但我們仍然要使用從 Shape() 繼承的建構函式來定義它,以便您練習一下。您可能想稍後在應用程式中新增另一個圓圈,它可以由另一個玩家控制,或者讓多個由計算機控制的邪惡圓圈出現。您可能不會用一個邪惡圓圈來征服世界,但對於本評估來說已經足夠了。
建立一個 EvilCircle 類的定義。它應該使用 extends 從 Shape 繼承。
EvilCircle 建構函式
EvilCircle 的建構函式應該
- 只接收
x和y引數 - 將
x和y引數傳遞給Shape超類,以及硬編碼為 20 的velX和velY值。您應該使用類似super(x, y, 20, 20);的程式碼來實現這一點 - 將
color設定為white,將size設定為10。
最後,建構函式應該設定使使用者能夠在螢幕上移動邪惡圓圈的程式碼
window.addEventListener("keydown", (e) => {
switch (e.key) {
case "a":
this.x -= this.velX;
break;
case "d":
this.x += this.velX;
break;
case "w":
this.y -= this.velY;
break;
case "s":
this.y += this.velY;
break;
}
});
這將向 window 物件新增一個 keydown 事件監聽器,以便當按下某個鍵時,會查詢事件物件的 key 屬性,以檢視按下了哪個鍵。如果它是四個指定鍵之一,那麼邪惡圓圈就會向左/右/上/下移動。
為 EvilCircle 定義方法
EvilCircle 類應該有三個方法,如下所述。
draw()
該方法與 Ball 的 draw() 方法具有相同的目的:在畫布上繪製物件例項。EvilCircle 的 draw() 方法的工作方式非常類似,因此您可以從複製 Ball 的 draw() 方法開始。然後,您應該進行以下更改
- 我們希望邪惡圓圈不填充,而只是有一個外圍線(描邊)。您可以透過更新
fillStyle和fill()為strokeStyle和stroke()來實現這一點。 - 我們還希望使描邊稍微更厚一些,這樣您就可以更輕鬆地看到邪惡圓圈。這可以透過在
beginPath()呼叫之後(3 即可)設定lineWidth的值來實現。
checkBounds()
該方法將執行與 Ball 的 update() 方法的第一部分相同的操作——檢視邪惡圓圈是否會移出螢幕邊緣,並阻止它這樣做。同樣,您只需複製 Ball 的 update() 方法即可,但您應該做一些更改
- 刪除最後兩行——我們不想在每一幀上自動更新邪惡圓圈的位置,因為我們會以其他方式移動它,如您將在下面看到的那樣。
- 在
if ()語句中,如果測試結果為真,我們不想更新velX/velY;而是要更改x/y的值,以便邪惡圓圈稍微彈回螢幕上。新增或減去(視情況而定)邪惡圓圈的size屬性是合理的。
collisionDetect()
該方法的工作方式與 Ball 的 collisionDetect() 方法非常類似,因此您可以使用它的副本作為該新方法的基礎。但是,有一些區別
- 在外部
if語句中,您不再需要檢查正在迭代的當前球是否與進行檢查的球相同——因為它不再是球,而是邪惡圓圈!相反,您需要做一項測試,以檢視正在檢查的球是否存在(您可以使用哪個屬性來實現這一點?)。如果它不存在,說明它已經被邪惡圓圈吞噬了,因此無需再次檢查它。 - 在內部
if語句中,您不再希望當檢測到碰撞時使物件改變顏色——而是,您希望將與邪惡圓圈碰撞的所有球設定為不再存在(同樣,您認為該怎麼做?)。
將邪惡圓圈引入程式
現在我們已經定義了邪惡圓圈,我們需要讓它出現在我們的場景中。為此,您需要對 loop() 函式進行一些更改。
- 首先,建立一個新的邪惡圓圈物件例項(指定必要的引數)。您只需要執行一次,而不需要在迴圈的每次迭代中都執行。
- 在您遍歷每個球併為每個球呼叫
draw()、update()和collisionDetect()函式的地方,請確保只有在當前球存在的情況下才呼叫這些函式。 - 在迴圈的每次迭代中,呼叫邪惡圓圈例項的
draw()、checkBounds()和collisionDetect()方法。