建造磚塊區域
這是Gamedev Canvas 教程的第 6 步(共 10 步)。您可以在 Gamedev-Canvas-workshop/lesson6.html 找到完成本課程後代碼的原始碼。
在修改了遊戲玩法機制後,我們現在能夠輸掉了——這很棒,因為這意味著遊戲終於感覺更像一個遊戲了。但是,如果玩來玩去只是讓球在牆壁和擋板之間彈來彈去,那很快就會變得很無聊。Breakout 遊戲真正需要的是一些可以被球擊碎的磚塊,這正是我們現在要建立的!
設定磚塊變數
本課程的總體目標是渲染幾行關於磚塊的程式碼,使用一個巢狀迴圈來處理一個二維陣列。但首先,我們需要設定一些變數來定義磚塊的資訊,例如它們的寬度和高度、行數和列數等。在您之前宣告的程式變數下方新增以下行。
const brickRowCount = 3;
const brickColumnCount = 5;
const brickWidth = 75;
const brickHeight = 20;
const brickPadding = 10;
const brickOffsetTop = 30;
const brickOffsetLeft = 30;
這裡我們定義了磚塊的行數和列數、它們的寬度和高度、磚塊之間的填充(這樣它們就不會互相接觸)以及頂部和左側的偏移量(這樣它們就不會從 Canvas 的邊緣開始繪製)。
我們將所有磚塊儲存在一個二維陣列中。它將包含磚塊列(c),而磚塊列又將包含磚塊行(r),而磚塊行又將各自包含一個物件,該物件包含繪製每個磚塊在螢幕上的 x 和 y 位置。將以下程式碼新增到您的變數下方。
const bricks = [];
for (let c = 0; c < brickColumnCount; c++) {
bricks[c] = [];
for (let r = 0; r < brickRowCount; r++) {
bricks[c][r] = { x: 0, y: 0 };
}
}
上面的程式碼將迴圈遍歷行和列並建立新的磚塊。請注意,磚塊物件也將用於稍後的碰撞檢測。
磚塊繪製邏輯
現在讓我們建立一個函式來遍歷陣列中的所有磚塊並將它們繪製在螢幕上。我們的程式碼可能如下所示。
function drawBricks() {
for (let c = 0; c < brickColumnCount; c++) {
for (let r = 0; r < brickRowCount; r++) {
bricks[c][r].x = 0;
bricks[c][r].y = 0;
ctx.beginPath();
ctx.rect(0, 0, brickWidth, brickHeight);
ctx.fillStyle = "#0095DD";
ctx.fill();
ctx.closePath();
}
}
}
同樣,我們正在迴圈遍歷行和列來設定每個磚塊的 x 和 y 位置,並且在每次迴圈迭代中,我們還在 Canvas 上繪製一個磚塊——大小為 brickWidth x brickHeight。問題是我們把它們都繪製在了一個地方,座標是 (0,0)。我們需要做的是包含一些計算,這些計算將計算出每次迴圈迭代中每個磚塊的 x 和 y 位置。
const brickX = c * (brickWidth + brickPadding) + brickOffsetLeft;
const brickY = r * (brickHeight + brickPadding) + brickOffsetTop;
每個 brickX 位置的計算方法是 brickWidth + brickPadding,乘以列號 c,再加上 brickOffsetLeft;brickY 的邏輯是相同的,只是它使用了行號 r、brickHeight 和 brickOffsetTop 的值。現在,每一塊磚都可以放置在正確的行和列位置,磚塊之間有填充,並從畫布的左側和頂部邊緣偏移繪製。
完成 drawBricks() 函式後,將 brickX 和 brickY 值作為座標而不是每次都使用 (0,0),最終版本將如下所示——將此新增到您程式碼中的 drawPaddle() 函式下方。
function drawBricks() {
for (let c = 0; c < brickColumnCount; c++) {
for (let r = 0; r < brickRowCount; r++) {
const brickX = c * (brickWidth + brickPadding) + brickOffsetLeft;
const brickY = r * (brickHeight + brickPadding) + brickOffsetTop;
bricks[c][r].x = brickX;
bricks[c][r].y = brickY;
ctx.beginPath();
ctx.rect(brickX, brickY, brickWidth, brickHeight);
ctx.fillStyle = "#0095DD";
ctx.fill();
ctx.closePath();
}
}
}
實際繪製磚塊
在本課中要做的最後一件事是在 draw() 函式中新增對 drawBricks() 的呼叫,最好是在開頭,放在清除 Canvas 和繪製球之間。將以下程式碼新增到 drawBall() 呼叫上方。
drawBricks();
Compare your code
此時,遊戲又變得更有趣了一些。
注意:嘗試更改每行或每列的磚塊數量,或者它們的位
後續步驟
所以現在我們有磚塊了!但是球根本沒有與它們互動——我們將在繼續第七章“碰撞檢測”時改變這一點。