ロゴシュミグラム

ブロックの関数の作成

ブロックの位置の決め方

blocks に二次元配列を作成してその中にブロックを生成していきます。またブロックの個数を入れておく blocksCount も用意しておきます。

blocks.js

let blocks;
let blocksCount;

blocks を図で表すと次のようになります。

ブロック崩しのブロック番号

例えば一番右上のブロックを取得したい場合には blocks[0][3] のようにします。

次にこの blocks を座標で表すと次のようになります。(一つ当たりのブロックの横幅が20px、縦幅が10pxだとします)

ブロック崩しのブロック座標

たとえば blocks[2][3] のブロックの左上のx座標は2×30px=60px、y座標は2×10px=20pxとなります。

このブロックを描く場合は、blocksCtx.fillRect(60, 20, 20, 10) とすることで描くことができます。

ブロックのプロパティ

ブロックは次のようなプロパティを持ちます。

ブロックの例

{
// 縁の色
borderColor: 'midnightblue',
// 中身の色
fillColor: 'deepskyblue',
// このブロックが存在するblocksの行番号
rowIndex:1,
// このブロックが存在するblocksの列番号
columnIndex:2,
// このブロックの左上のx座標
x:40,
// このブロックの左上のy座標
y:10,
// 何回当てれば壊せるかの回数
hitPoints: 1,
// ボールが衝突したときの特殊効果(必須ではない)
effect: (ball) => { },
// 壊せないブロックか否か(必須ではない)
isUnbreakable: false,
}

このようなブロックを blocks の中に生成していきます。ブロックが存在しない場所にはnullを入れます。例えば次のような感じになります。

blocksの二次元配列の例

[
[ {...}, {...}, {...}, {...} ],
[ {...}, {...}, null , {...} ],
[ {...}, null , null , null ],
[ null , null , null , null ]
]

ブロックの種類を作成

blockDictionary にブロックの種類ごとに色やボールが当たったときの効果などを設定していきます。まずはボールが1回当たったら壊れるだけのノーマルブロックを作ります。

blocks.js

const blockDictionary = {
'nomal': {
borderColor: 'midnightblue',
fillColor: 'deepskyblue',
hitPoints: 1,
},
};

ボールが衝突したときの特殊効果はないので、 effect はありません。のちのち、いろんな特殊効果のブロックを追加していきます。

ブロックを作成する関数

blocks.js

const createBlock = (blockName, rowIndex, columnIndex) => {
const block = {
...blockDictionary[blockName],
rowIndex: rowIndex,
columnIndex: columnIndex,
x: columnIndex * blockWidth,
y: rowIndex * blockHeight
};
blocks[rowIndex][columnIndex] = block;
// 壊れるブロックなら個数を1つ増やす
if (!block.isUnbreakable) {
blocksCount++;
}
// ブロックを描く関数
drawBlock(block);
};

引数にはブロックの名前、行番号、列番号を受け取ります。

たとえば、block[2][3] にノーマルブロックを生成したい場合は createBlock('nomal', 2, 3) のように書きます。

ブロックをcanvasに描く関数

blocks.js

const drawBlock = (block) => {
// 縁を描く
blocksCtx.fillStyle = block.borderColor;
blocksCtx.fillRect(block.x, block.y, blockWidth, blockHeight);
// 中身を描く
blocksCtx.fillStyle = block.fillColor;
blocksCtx.fillRect(block.x + 1, block.y + 1, blockWidth - 2, blockHeight - 2);
};

縁と中身の色を分けるため、最初に四角形を描き、そのあとその中に少し小さめの四角形を描きます。

strokeRect(block.x, block.y, blockWidth, blockHeight) で枠線を描くこともできるのですが、 blockWidthblockHeight のサイズを越えて描いてしまうためここでは使えません。

ブロックをcanvasから消す関数

blocks.js

const eraseBlock = (block) => {
blocksCtx.fillStyle = backgroundColor;
blocksCtx.fillRect(block.x, block.y, blockWidth, blockHeight);
};

ブロックを背景色と同じ色で塗りつぶしますことでcanvasから消えたように見せます。

ブロックを削除する関数

blocks.js

const removeBlock = (block) => {
blocks[block.rowIndex][block.columnIndex] = null;
// ブロックをcanvasから消す
eraseBlock(block);
// ブロックの個数をっ1つ減らす
blocksCount--;
// ブロックの個数の表示を更新させる
updateBlocksCountLabel();
if (blocksCount === 0) {
// ゲームの状態を変える
changeGameState('gameClear');
}
};

ブロックの削除後、残っているブロックの個数が0個であればゲームクリアしたということなので、ゲームの状態を gameClear に変えます。

updateBlocksCountLabelchangeGameState はあとで作成します。

ボールが当たったときの関数

blocks.js

const clideBlock = (ball, block) => {
// 当たったブロックが壊れないブロックなら何もしない
if (block.isUnbreakable) {
return
}
// hitPointsを1つ減らす
block.hitPoints--;
// 特殊効果があれば実行する
if (block.effect) {
block.effect(ball);
}
// hitPointsが0になったらこのブロックを削除する
if (block.hitPoints === 0) {
removeBlock(block);
}
};

引数には衝突したボールとブロックを受け取ります。

当たったブロックが壊れないブロックであったら何もしません。

壊れるブロックならば hitPoints を1つ減らし、特殊効果があれば effect を実行します。

もしブロックの hitPoints が0になっていたらそのブロックを削除します。

ブロックを初期配置する関数

blocks.js

const initBlocks = () => {
blocks = [];
blocksCount = 0;
// canvas全体の背景色を塗る
blocksCtx.fillStyle = backgroundColor;
blocksCtx.fillRect(0, 0, canvasWidth, canvasHeight);
for (let rowIndex = 0; rowIndex < blocksRowLength; rowIndex++) {
blocks.push([]);
for (let columnIndex = 0; columnIndex < blocksColumnLength; columnIndex++) {
createBlock('normal', rowIndex, columnIndex);
}
}
// ブロックの個数の表示を更新させる
updateBlocksCountLabel();
};

二次元配列を作成しながら、すべての要素にノーマルブロックを生成しています。

ブロックの個数を表示させる関数

blocks.js

const updateBlocksCountLabel = () => {
blocksCountLabel.textContent = blocksCount;
};

以上でblocks.jsは完成です。