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化されていない良曲多くて、出先で聞けないのはすごく勿体無い。なんとかなると良いですね。
・北海道日本ハムファイターズの新球場発表
イメージ見ただけで、行ってみたくなりましたね。日本にはない施設、雰囲気になりそうですし、野球の他にもたくさん楽しめそうなのもいいですね。
では
JavaScript canvasで円が動いたように・・・
3日目 続 canvas ブロック崩しみたいなの作りたい
・何をしたのか?
- 円(ボールに見立てる)を書いて、それを動かす
- 指定したcanvasタグのwidth,heightを指定してその上下左右の端を壁に見立てて、1のボールがぶつかったら弾ませる(ボールが半分壁 に吸い込まれる)
- 以上を少しいじって、研究(ほぼ遊び)
- ブロックを作成 絵心の無さを再認識
-
ボールがブロックにぶつかったら消える
それでは、復習していきます
注)初学なので、間違っている箇所・認識等あると考えられますので、ご容赦ください
CSSの指定は省いています。
・ボールを描いて、壁にぶつかったら、跳ね返るようにするまで
今回からは<script>が長くなるので、別ファイルに記述していきます
HTMLファイルの関連している部分
<body>
<div class="game-area">
<canvas id="xxx" width="800" height="800"></canvas>
</div>
<div class="opreation-btn">
<button id="start" class="btn">START</button>
<button id="stop" class="btn">STOP</button>
</div>
<script type="text/javascript" src="xxxx.js"></script>
</body>
canvasタグのwidthをX軸 heightをY軸に四角形をイメージした方がわかりやすいかも。
では、ボール(円)を描きます
にDOM等について書いているので、それらの説明は省略します
window.onload = function() {} の {} 中にコードを書いていく
let canvas = document.getElementById('xxx'), // xxxはcanvasタグ内のid
context = canvas.getContext('2d'), // 2Dコンテキスト
ball_radius = 10, // ボールの半径
x = canvas.width * Math.random(), // ballのX座標を指定
y = canvas.height -30, // ballのY座標を指定
dx = 1,
dy = -1;
r = Math.random() * 256,
g = Math.random() * 256,
b = Math.random() * 256;
color = "rgb(" + r + "," + g + "," + b + ")";
// ここまでは変数を定義して、次のdraw_ball() で円を描きます
function draw_ball() {
context.beginPath();
context.arc(x, y, ball_radius, 0, Math.PI*2);
context.fillStyle = color;
context.fill();
context.closePath();
}
// ボールが動いているように見せる draw()
function draw() {
//以下の一文をコメントアウトするとどういう働きをしているかわかります
context.clearRect(0, 0, canvas.width, canvas.height); // 指定された範囲を透明な黒に
draw_ball(); // ボールを描いていく
// 以下の条件はボールが壁にぶつかったら、反転して跳ね返るための記述
if(x + dx > canvas.width || x + dx < 0) {
dx = -dx;
}
if(y + dy > canvas.height || y + dy <0) {
dy = -dy;
end
}
x += dx;
y += dy;
requestAnimationFrame(draw);
}
// スタートボタンをクリックするとボールが描き出す
document.getElementById('start').addEventListener('click', draw, false);
以上でボールが動いて、壁にぶつかって、跳ね返るように見えるようにはできました
悩んだところは、緑に色を変えた壁にぶつかった場合の条件分岐
他の部分が調べて、値を考えれば何とか時間かけずにできましたが、条件分岐が毎度頭を悩ませています。繰り返して力をつけていくしかないですね!ここら変になると、イメージしづらくなってくるので、悩んだらノートに図を書いて考えるようにすると良いかも知れないですね(絵心がない自分でも強くそう思います。模写がある程度できますが自分のイメージを絵にするの本当に難しい)
どうせ書くなら、楽しく、自分らしくと思うので、余計な話がちょいちょい入りますので、ごめんなさい
実は、上記の条件だとまだ不十分でして、動かして貰えばわかります。
ボールが壁にぶつかったら、半分消える(めり込んでいる)様に見えます。
なぜでしょうか。自分も動いて、跳ね返って、やった!!と思ったんですけど、おかしいですよね。目を逸らしたらいけません。ここで妥協したら何も変わりません。と言うことで、考えて見ました。答えは、
' ボールの半径を計算に入れていなかった '
arc(x, y, ball_radius, 0, Math.PI*2) のx yは円の中心の座標を指定していて、見えているボールはそれから ball_radius 分大きく見えているので、中心の座標が壁にぶつかったら、跳ね返る条件となっていたと考えられ(たぶん)、ball_radius分を足し引きしたら、うまくいくのでは?と推測して、以下に値を変更
if(x + dx > canvas.width - ball_radius || x + dx < 0 + ball_radius) {
dx = -dx;
}
if(y + dy > canvas.height - ball_radius || y + dy < 0 + ball_radius) {
dy = -dy;
}
今見たら、0 + の部分はいらないのでは?と思いましたが、復習の記録でもあるので、直さずに残しておきます。この様にすれば、ボールがめり込まず、壁にぶつかって跳ね返っている様に見えると思います。
今回ここまでできるのに、だいぶ時間がかかりました。一つ一つ調べながらで、次また何も見ないで書いてと言われたら、かけません。でも、また調べながらなら、少し理解してきたから、時間かけずにかけるかな?自分の中ではそんな認識です。
・ブロックの作成
どういったものを作るか?絵で例えたりするとイメージしやすいと思います。
目標としては、x軸に5個、Y軸に4個 計20個のブロック(配列)を描きたい
では、以下に記述していきます
const block_padding = 10,
block_offset_top = 30,
block_offset_left = 30,
block_column_count = 5, // column(列)の数
block_row_count = 4, // row(行)の数
margin = ( (block_offset_left * 2) + (block_padding * (block_column_count -1) ) ),
block_width = (canvas.width - margin) / block_column_count,
block_height = 50;
以上がブロックの設定値
20個分できていると思うので、図に書き換えて表すとイメージしやすいと思います(ここでは省略させてもらいます。すいません)
ブロックを描くコード
let blocks = ;
for(let c = 0; c < block_column_count; c++) {
blocks[c] = ;
for(let r = 0; r < block_row_count; r++) {
blocks[c][r] = { x: 0, y: 0, status: 1 }
}
}
// x y はブロックの座標データ statusはブロックにボールがぶつかった時に力を発揮します。配列の中に配列を作って、x yの値を保存していくようなイメージです。
ブロックを描画する処理
function draw_blocks() {
for(let c = 0; c < block_column_count; c++) {
for(let r = 0; r < block_row_count; r++) {
if (blocks[c][r].status == 1) {
let block_x = (c * (block_width + block_padding)) + block_offset_left;
let block_y = (r * (block_height + block_padding)) + block_offset_top;
blocks[c][r].x = block_x;
blocks[c][r].y = block_y;
context.beginPath();
context.rect(block_x, block_y, block_width, block_height);
//block_width: 140 height:50
context.fillStyle = '#0095dd';
context.fill();
context.closePath();
}
}
}
}
for分でX座標とY座標をsetteisite,beginPath以下でブロックの大きさを指定して、描く。その繰り返しで、20個のブロックを描画する。x座標30でY座標が違うブロックを4個、X座標が170でY座標の違うブロックを という感じでfor文を利用しています。
いろいろと値を変えてみると、どうのように描画しているか理解できるかなと思いますし、ブロックを崩す時にもっとあった方が良い!と思ったら、増やすこともできるので是非お試しください。
このdraw_blocks()関数はdraw()関数の中でボールを描く前に呼び出します。
今回はここまでにしておきます。
まだ、文を書くことに慣れていないせいもあって、結構時間がかかってしまっています。勉強しないとダメなので、この続きはまた別の記事に書こうと思います。
次はボールがブロックに当たったら、消える処理
ここも難しく感じた部分なので、これから復習して、違う機能を追加することなどを、本日のテーマにして、勉強してきます。
昨日の出来事
・2年連続でホークスが日本一(おめでとうございます)
野球でキャッチャーしていたことあるので、甲斐選手のプレイに心動きました。ちなみに、特にどの球団が好きとかはなく、すごいなと思ってみる勢です。
・ラグビー日本代表対オールブラックスを見逃す
ただただ勿体無かった。それだけです。。。
最後まで、見ていただいでありがとうございました
2日目(canvas , javascript開始)
今日やったこと( 日はまたいだけど、気にしない 気にしない )
*勉強したての内容を復習する意味で書いていますので、間違っているかもしれないのでご注意ください!!
-
JavaScript(以下、JS) Canvasを使って色々描いてみた
ちなみに、JSが久しぶり、かつ、Canvasってなに?な状態です。
- canvas とは?
簡単に言うと、HTMLとJSの力を借りて、四角形、円形などなど描画できる
調べてみると、アニメーションみたいなこともできるらしいです。
画像に比べてデータ量が軽くできるらしい - 準備
エディタに、sample.html(sampleの部分は何でもOK!)を作成
<body>
<canvas id="canvas"></canvas>
<script>
#ここに処理を書いていく
</script>
</body>
#ここに処理を書いていく部分について
1. function 〇〇() { }
2. var 〇〇1= document.getElementById('canvas') で<canvas>ないの id="canvas"と関連助ける
3. canvasに対応していないブラウザがあるらしく、if文を使って対応
4. 2Dコンテキスト(英語だとcontext 文脈の意味)を指定
var 〇〇 = 〇〇1.getContext('2d')
5. 後はbeginPath()で線を描く宣言をして、moveTo, lineTo(X, Y), clothPath,strokeなど使って、四角形を描画していく。
円の場合はarc(x, y, z, 0, Math.PI*2, false);
x, yは座標 zは半径(ピクセル) 0 は 0° から描く Math.PI*2は360°らしい falseは時計回り trueにすると反時計回りで円を描ける.
*この他にも当然まだまだ色々とやれることはあるので、勉強していこう
ex) ラジェ曲線 - 最後に
やってみて、普段 Railsしかやっていなかったせいか JSの書き方忘れていました。;とか忘れがちなので注意! やはり定期的にJSもやらないとダメですね。せっかく覚えたのだから、自分で手動かして記憶に残していかないと。 - 勉強以外の出来事
・kalafinaのhikaruさんがついに事務所退所
・Aimerさんが体調不良になってしまった
お二人共好きで、ほぼ毎日曲を聴いているだけに辛い
今書いてみて、今日の出来事的なものは何かあれば日記がわりになる(名案だ!!)と思いましたが、あまりバッドなニュースは遠慮したいですね。
今日は結構書けたので、慣れてどんどんうまく書けるようになりたいですね
アニメなんか見て寝よう
それでは
これから変わるために はじめのいっぽ
- 2018年11月1日
今から 自分をかえるため 本気になりたい
ずっと逃げてきました 自分で自分に言い訳して
-
きっかけに
とあるご縁でお話しさせていただいた方からズバッと核心を言ってもらえた。
言ってもらえたと未来の自分が思えるように、変わるための
はじめのいっぽ 自分をかえるきっかけに
そういう思いで始めました。
- 変えるために
1 プログラミングの勉強内容を書く
2 サボったり、緩んだら書く
3 思ったままの言葉で書く(偽るな)
4 以下、順次追加
これだけ書いてても、長い間逃げてきたせいか、甘やかそうとしている自分がいます。そんな簡単に抜け出せないでしょ。また、いつも通りに熱が過ぎ去ったら、忘れて楽するに決まってる。一回逃げてから、ずーっと変われてないでしょ。思いついたこと書いてるだけなので、意味なんかどうでもいいんです。長いか短いかわからんけれど、このはじめのいっぽ見た時にやってよかったって思えるようにやるだけなんだから。
この はじめのいっぽ が黒歴史になるように頑張ります。
核心をついてもらった方に、堂々と会うために
頑張れや 弱い自分 まっすぐに見れるように
完全に訳がわからないブログ 第一話 完