ブロックの位置の決め方
blocks
に二次元配列を作成してその中にブロックを生成していきます。またブロックの個数を入れておく blocksCount
も用意しておきます。
blocks
を図で表すと次のようになります。
![ブロック崩しのブロック番号](/_next/static/media/blocks-index.13fcc177.svg)
例えば一番右上のブロックを取得したい場合には blocks[0][3]
のようにします。
次にこの blocks
を座標で表すと次のようになります。(一つ当たりのブロックの横幅が20px、縦幅が10pxだとします)
![ブロック崩しのブロック座標](/_next/static/media/blocks-coordinate.f26f38ae.svg)
たとえば blocks[2][3]
のブロックの左上のx座標は2×30px=60px、y座標は2×10px=20pxとなります。
このブロックを描く場合は、blocksCtx.fillRect(60, 20, 20, 10)
とすることで描くことができます。
ブロックのプロパティ
ブロックは次のようなプロパティを持ちます。
borderColor: 'midnightblue',
fillColor: 'deepskyblue',
// ボールが衝突したときの特殊効果(必須ではない)
このようなブロックを blocks
の中に生成していきます。ブロックが存在しない場所にはnullを入れます。例えば次のような感じになります。
[ {...}, {...}, {...}, {...} ],
[ {...}, {...}, null , {...} ],
[ {...}, null , null , null ],
[ null , null , null , null ]
ブロックの種類を作成
blockDictionary
にブロックの種類ごとに色やボールが当たったときの効果などを設定していきます。まずはボールが1回当たったら壊れるだけのノーマルブロックを作ります。
const blockDictionary = {
borderColor: 'midnightblue',
fillColor: 'deepskyblue',
ボールが衝突したときの特殊効果はないので、 effect
はありません。のちのち、いろんな特殊効果のブロックを追加していきます。
ブロックを作成する関数
const createBlock = (blockName, rowIndex, columnIndex) => {
...blockDictionary[blockName],
columnIndex: columnIndex,
x: columnIndex * blockWidth,
y: rowIndex * blockHeight
blocks[rowIndex][columnIndex] = block;
if (!block.isUnbreakable) {
引数にはブロックの名前、行番号、列番号を受け取ります。
たとえば、block[2][3]
にノーマルブロックを生成したい場合は createBlock('nomal', 2, 3)
のように書きます。
ブロックをcanvasに描く関数
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)
で枠線を描くこともできるのですが、 blockWidth
や blockHeight
のサイズを越えて描いてしまうためここでは使えません。
ブロックをcanvasから消す関数
const eraseBlock = (block) => {
blocksCtx.fillStyle = backgroundColor;
blocksCtx.fillRect(block.x, block.y, blockWidth, blockHeight);
ブロックを背景色と同じ色で塗りつぶしますことでcanvasから消えたように見せます。
ブロックを削除する関数
const removeBlock = (block) => {
blocks[block.rowIndex][block.columnIndex] = null;
updateBlocksCountLabel();
changeGameState('gameClear');
ブロックの削除後、残っているブロックの個数が0個であればゲームクリアしたということなので、ゲームの状態を gameClear
に変えます。
updateBlocksCountLabel
や changeGameState
はあとで作成します。
ボールが当たったときの関数
const clideBlock = (ball, block) => {
// 当たったブロックが壊れないブロックなら何もしない
if (block.isUnbreakable) {
// hitPointsが0になったらこのブロックを削除する
if (block.hitPoints === 0) {
引数には衝突したボールとブロックを受け取ります。
当たったブロックが壊れないブロックであったら何もしません。
壊れるブロックならば hitPoints
を1つ減らし、特殊効果があれば effect
を実行します。
もしブロックの hitPoints
が0になっていたらそのブロックを削除します。
ブロックを初期配置する関数
const initBlocks = () => {
blocksCtx.fillStyle = backgroundColor;
blocksCtx.fillRect(0, 0, canvasWidth, canvasHeight);
for (let rowIndex = 0; rowIndex < blocksRowLength; rowIndex++) {
for (let columnIndex = 0; columnIndex < blocksColumnLength; columnIndex++) {
createBlock('normal', rowIndex, columnIndex);
updateBlocksCountLabel();
二次元配列を作成しながら、すべての要素にノーマルブロックを生成しています。
ブロックの個数を表示させる関数
const updateBlocksCountLabel = () => {
blocksCountLabel.textContent = blocksCount;
以上でblocks.jsは完成です。