JavaScript canvas ブロック崩しみたいなやつ(仮・終)
4日目 復習がてらまとめていきます( 復習大事!)
*昨日の記事 に今日纏める以前の説明載ってますので、よければ覗いてください
・今日書くこと
- ボールがブロックに当たったら、消える
- ボールを弾く板を作る&操作できるようにする
- ゲームオーバーの実装
- ボールが板にぶつかったら、弾き返す
- ゲーム自体は4まで動く( 味気ないので、機能を足してみた )
・ブロックにボールが触れることをどう条件付けていくのか?
壁にぶつかった時に跳ね返る条件と似ているのではないかなと推測(したけど、すぐにはできませんでした)。しかし、冷静に図を書いて、ブロックの座標とボールの座標(ボールの中心が座標なので、そこからボールの半径分足し引きした座標が必要)が重なったら、ぶつかったことになる。この練習全体を通して、常にx軸とy軸について考えることが大切で、x軸は画面の右にいくごとに数値が大きくなる。y軸は画面の上が0で、下にいくほど値は大きくなる ことを確認しながら、考えると全体の関係性は掴みやすいと思います。これを考えて書いたコードが
x > block.x - ball_radius && x < block.x + block_width + ball_radius
&& y > block.y - ball_radius && y < block.y + block_height + ball_radius
ball_radius(円の半径)消してしまうと、ボール半分埋まってから消えるので、注意が必要。&&を使用しているの意味は、図で表すとわかりやすいかなと思いますが、ここでは割愛させてもらいます。そして、これをcollision_detection()関数の中に入れると
function collision_detection() {
for(var c = 0; c < block_column_count; c++) {
for(var r = 0; r < block_row_count; r++) {
let block = blocks[c][r];
if(block.status == 1) {
if(x > block.x - ball_radius && x < block.x + block_width + ball_radius
&& y > block.y - ball_radius && y < block.y + block_height + ball_radius) {
dy = -dy;
block.status = 0;
}
}
}
}
}
となります。block_status == 1ならば、ブロックを表示。ボールが方向を変えると、block_status = 0 とすることで、ブロックが消える処理をしています。このcollision_detection()関数は draw()関数内のボールを描画する後に記述する。
・ブロックの範囲を決める条件づけ
・ブロックstatusの扱い
二つの理解に時間を割いてしまったので、同じようなものを考えて慣れていきたい。
・棒(画面下でボールを弾き返すバー)を作成
ここは、そこまで頭を使わずに以前の知識でいきましょう。
// 棒の大きさを設定
const bar_height = 15, // 棒の高さ
bar_width = 100; // 棒の長さ この長さ次第でゲーム難度は変わります
let bar_x = (canvas.width - bar_width) / 2 // 棒のx座標
// 棒を描画する関数
function draw_bar() {
context.beginPath();
// rect(bar_x, 785, 75, 15) rectの形状を指定しています
context.rect(bar_x, canvas.height - bar_height, bar_width, bar_height);
context.fillStyle = color;
context.fill();
context.closePath();
}
これは、draw()関数内のボールを描画する関数のあとに記述する。この関数については以前も出てきたので説明は省きます。
・棒を動かす(キーボードの左右で移動させる)
ボタンを押すたびにイベントが起こるという処理をさせたいので、
addEventListener('keydown', 以下にかく関数, false)で書いていく。ここでkeyCodeを使っていきますが、これは調べれば出てくるので、省略しますがいろんなキーバインドを試してみる面白いですね(PCゲームはやりやすいキーバインドを見つけて設定しますし。ゲームのレベルが違いすぎますが言いたかっただけです)では、本題の関数を
function key_down_handler(e) {
if(e.keyCode == 39) {
if(bar_x < canvas.width - bar_width) {
bar_x += 20; //ここの大小で動く速度が変わる
}
} else if(e.keyCode == 37) {
if(bar_x > 0) {
bar_x -= 20; //ここの大小で動く速度が変わる
}
}
}
document.addEventListener('keydown', key_down_handler, false);
これで、棒が動きます。応用していけば、y軸方向にも動かせる(●●んビー的やつ)
・ゲームオーバーを追加
これまでは画面下(y軸の最大値)でも弾むようにしていましたが、その条件を消して、画面下にボールが着いたら、ゲームオーバー(処理を停止)するようにします。
すなわち、ボールを弾ませるコードをいじって、y軸の最大値よりボールの座標が大きくなったらとします
if(x + dx > canvas.width - ball_radius || x + dx < 0 + ball_radius) {
dx = -dx;
}
if(y + dy < 0) {
dy = -dy;
} else if(y + dy > canvas.height -ball_radius) {
alert("game over");
document.location.reload();
}
ゲームオーバーはelse if 節で処理しています。ball_radiusがないとボールが画面のしたをぶち抜いてから、ゲームオーバーになってしまうので注意が必要です。これだけでも、結構考えるのに、FPSゲームの当たり判定とかの処理はどれだけ難しいのか?できるようになったら、楽しいのかなぁ。想像もつかない。
そろそろ終わり見えてきたので、もう一踏ん張りです!!
・ボールが棒に触れたら、跳ね返す
ここまでくると、すこーーーし考え方が思いつくようになってきたような。
考え方としては、ボールの座標が 棒の右端と左端の間の座標内にあるか かつ ボールが棒に触れているか?を条件付けする。
上述したコードの if(y + dy < 0) 以下を下記のように変更
if(y + dy < 0) {
dy = -dy;
} else if(x > bar_x - ball_radius && x < bar_x + bar_width + ball_radius
&& y + dy == canvas.height - bar_height -ball_radius) {
dy = -dy;
} else if(y + dy > canvas.height -ball_radius) {
alert("game over");
document.location.reload();
}
一応これで完成となります。しかし、イマイチ棒とボールがぶつかる箇所の判定がガバガバな気がします。これも含めて、改善余地はまだまだありそうですね。しかし、今回の練習したことで、canvasという未知の技術を知り、条件分岐を考えて、JavaScriptの復習にもなったので、個人的には有意義であったかなと思っています。
コードで文字数稼げたけれど、文字だけで同じように書くにはまだまだ練習あるのみですし、わかりやすい表現、表示の仕方等も考えていきたいですね。
今まで、まとまった文章書いたり、端的にわかりやすく説明することが苦手でしたが、これらも変えていきたいですね。
書くこと、プログラミング、生活がもっと楽しくなるように、頑張るか?
ねっ!!
以上でJavaScript編がひとまずおしまい(パチパチ)
今日の出来事
・KOTOKOさんに今更ハマる
しかし、ダウンロードやCD化されていない良曲多くて、出先で聞けないのはすごく勿体無い。なんとかなると良いですね。
・北海道日本ハムファイターズの新球場発表
イメージ見ただけで、行ってみたくなりましたね。日本にはない施設、雰囲気になりそうですし、野球の他にもたくさん楽しめそうなのもいいですね。
では