JavaScript - 矢印キーで動かす方法
HTML のキャンバス <canvas> に描いたオブジェクトを JavaScript で動かすコードを解説します。ゲームでプレイヤーを操作するように、キーを押してオブジェクトを移動させる方法を学びましょう。
キャンバスに描いたオブジェクトを矢印キーで操作しよう
この記事では、キーボードのキーを使ってオブジェクト(物)を動かす方法を紹介します。今回は、HTML のキャンバス <canvas>
に JavaScript で正方形のオブジェクトを描き、上下左右の矢印キーで操作できるようにコーディングします。
この記事を読むと分かること
keydown
イベントkeyup
イベントswitch
文key
プロパティ
サンプルプロジェクト
最初に、キャンバスに描いたオブジェクトを矢印キーで操作する動きを確認しておきましょう。
- オブジェクトは、キャンバスの内側で上下左右に移動する(キャンバスの外には行かない)
- 上下と左右のキーを同時に押すと、斜めに移動する
キャンバスの使い方はもう知っていますか?キャンバスに描画する方法や、キャンバスを使ったアニメーションの作り方(オブジェクトを動かす方法)は、以下の記事で解説しているので、併せてご覧ください。
HTML と CSS
まずは HTML です。
- 描画エリア
<canvas>
を作成し、width
属性とheight
属性でキャンバスのサイズを指定します。
<canvas width="500" height="300"></canvas>
続いて CSS です。
- キャンバスの領域が分かるように、灰色の枠線を設定します。
canvas {
border: 3px solid lightgray;
}
JavaScript
次は JavaScript です。最初に、キャンバスに描画する準備をしましょう。
- 描画エリアを取得し、キャンバスの
2d
コンテキストを変数ctx
で参照できるようにします。
//キャンバス(描画エリアの取得)
const canvas = document.querySelector('canvas');
//2dコンテキスト(描画ツールの取得)
const ctx = canvas.getContext('2d');
四角形を描くための変数
矢印キーで動かすのは、キャンバスに描いた四角形です。四角形を描画するために必要な変数を用意しましょう。
- 変数
rectWidth
とrectHeight
は、四角形の横と縦のサイズです。ここでは同じ値を設定し、正方形になるようにします。 - 変数
rectX
とrectY
は、四角形を描画する位置の x 座標と y 座標を表します。最初は、キャンバスの中央を指定します。 - 変数
speedX
とspeedY
は、四角形の横移動と縦移動の速さを表します。値が大きければ大きいほど、動きが速くなります。
//四角形のサイズ
const rectWidth = 50;
const rectHeight = 50;
//四角形の最初の位置はキャンバスの中央
let rectX = canvas.width / 2 - rectWidth / 2;
let rectY = canvas.height / 2 - rectHeight / 2;
//四角形の移動速度
let speedX = 3;
let speedY = 3;
キーが押されているかどうかを示す変数
矢印キーで操作するためには、キーが押されているのか、押されていないのかをチェックする必要があります。そのための変数を、上下左右それぞれのキーに用意しましょう。
- キーが押されている
true
か、押されていないfalse
かを示します。この変数の値によって、オブジェクトを動かすか動かさないかを判断します。最初は、キーが押されていないfalse
で初期化します。
//キーが押されているかどうか(trueまたはfalse)
let upPressed = false; //上矢印キー
let downPressed = false; //下矢印キー
let leftPressed = false; //左矢印キー
let rightPressed = false; //右矢印キー
キーを押したら true にする
ここからは、キーが押されていることを確認する処理を書いていきましょう。
キーが押されたときに発生するのは、keydown
イベントです。addEventListener()
メソッドでドキュメントに keydown
イベントを追加し、keyDownHandler
を呼び出します。keyDownHandler
は押されたキーを示す関数で、このあと定義します。
- キーが押されたとき、そのキーを示します。
//ドキュメントにkeydownイベントを追加
document.addEventListener('keydown', keyDownHandler);
キーが押されたときに実行する関数 keyDownHandler
を定義しましょう。関数には引数 e
を指定し、keyDownHandler(e)
のようにします。こうすることで、keydown
イベントが発生したときに、押されたキーの情報を受け取ることができるようになりますよ。
//押されたキーを示す
function keyDownHandler(e) {
//-------------------------
// キーが押されたときに実行する処理
//-------------------------
}
引数 e
はイベントオブジェクトを表します。詳しくは以下の記事で解説しているのでご覧ください。
押されたキーが上下左右どのキーに一致するのかを switch
文で調べましょう。switch
は、括弧 ()
内の式をチェックし、それに当てはまる case
を探して実行します。押されたキーの値を取得するために使うのが、引数 e
と key
プロパティです。引数 e
には、keydown
イベントが発生したときのキー情報が保存されています。
e
が持つ情報の中からkey
プロパティで押されたキーの値を取得し、switch
文でどのcase
に当てはまるかを調べます。
function keyDownHandler(e) {
//押されたキーの値をチェックする
switch (e.key) {
case /* 押されたキーが上矢印キーの場合 */:
//上矢印キーが押されていることを示す
case /* 押されたキーが下矢印キーの場合 */:
//下矢印キーが押されていることを示す
case /* 押されたキーが左矢印キーの場合 */:
//左矢印キーが押されていることを示す
case /* 押されたキーが右矢印キーの場合 */:
//右矢印キーが押されていることを示す
}
}
上下左右それぞれのキーが押された場合の処理を書いていきましょう。
- 当てはまる
case
を見つけたら、そのキーが押されていることを示すために、false
で初期化した変数をtrue
にします。 break
文でswitch
文を終了します。
function keyDownHandler(e) {
switch (e.key) {
//押されたキーが上矢印キーの場合
case 'ArrowUp':
upPressed = true;
break;
//押されたキーが下矢印キーの場合
case 'ArrowDown':
downPressed = true;
break;
//押されたキーが左矢印キーの場合
case 'ArrowLeft':
leftPressed = true;
break;
//押されたキーが右矢印キーの場合
case 'ArrowRight':
rightPressed = true;
break;
}
}
switch
文は、以下のように if…else
文で書くこともできますよ。
//switch文をif...else文で書いた場合の例
function keyDownHandler(e) {
if (e.key === 'ArrowUp') { //押されたキーが上矢印キーの場合
upPressed = true;
} else if (e.key === 'ArrowDown') { //押されたキーが下矢印キーの場合
downPressed = true;
} else if (e.key === 'ArrowLeft') { //押されたキーが左矢印キーの場合
leftPressed = true;
} else if (e.key === 'ArrowRight') {//押されたキーが右矢印キーの場合
rightPressed = true;
}
}
以上で、上下左右どのキーが押されたかを示す関数 keyDownHandler
を定義できました。
キーを離したら false にする
今度は、キーが離された(押下をやめた)ことを確認する処理を書いていきましょう。
キーが離されたときに発生するのは、keyup
イベントです。ドキュメントに keyup
イベントを追加し、keyUpHandler
を呼び出します。keyUpHandler
は、離されたキーを示す関数です。
- キーが離されたとき、そのキーを示します。
//ドキュメントにkeyupイベントを追加
document.addEventListener('keyup', keyUpHandler);
関数 keyUpHandler
を定義しましょう。keyup
イベントが発生したときにそのキーの情報を受け取れるよう、関数にはkeyUpHandler(e)
のように引数 e
を指定してくださいね。
//離されたキーを示す
function keyUpHandler(e) {
//-------------------------
// キーが離されたときに実行する処理
//-------------------------
}
押されたキーを調べたときと同じように、上下左右どのキーが離されたかを switch
文で調べます。離されたキーの変数の値を false
にして、そのキーが離れされたことを示しましょう。
function keyUpHandler(e) {
switch (e.key) {
case 'ArrowUp': //離されたキーが上矢印キーの場合
upPressed = false;
break;
case 'ArrowDown': //離されたキーが下矢印キーの場合
downPressed = false;
break;
case 'ArrowLeft': //離されたキーが左矢印キーの場合
leftPressed = false;
break;
case 'ArrowRight': //離されたキーが右矢印キーの場合
rightPressed = false;
break;
}
}
以上で、上下左右どのキーが離されたかを示す関数 keyUpHandler
を定義できました。
押されているキーの方向へ動かす
さて、上下左右のキーが押されているかどうかをチェックできるようになったら、その情報を使って四角形を動かしましょう。
押されたキーによって動かす方向を決める関数を定義していきますよ。キャンバスに描いた四角形を動かすためには、四角形を描画する位置を更新するので、関数には update
という名前をつけます。
//押されているキーの方向へ四角形の描画位置を更新
function update() {
//-------------------------
// 押されているキーの方向へ動かす処理
//-------------------------
}
キャンバスの x 座標と y 座標について、ここでおさらいしておきましょう。座標を増やすとオブジェクトはどちらへ動くのか、減らすとどちらへ動くのかを理解しておいてくださいね。
- 上へ動かす… y 座標を減らす
- 下へ動かす… y 座標を増やす
- 左へ動かす… x 座標を減らす
- 右へ動かす… x 座標を増やす
上へ動かす
上下左右のどちらに動かすかは、if
文で条件分岐します。まずは、上矢印キーが押されているときに上へ動かす文を書きましょう。上へ動かすためには、以下の二つの条件を指定します。
upPressed
:上矢印キーが押されているrectY > 0
:四角形の y 座標が 0 より大きい
upPressed
は、upPressed === true
を意味し、上矢印キーが押されていることを示します。rectY > 0
では、四角形の y 座標(左上角)がキャンバスの上端より下にあることを条件としています。これは、上矢印キーを押し続けてもキャンバスの外側には行かないようにするためです。論理積演算子 &&
で両方の条件が満たされているときだけ上へ動くようにしましょう。
- 上矢印キーが押されていて、かつ、四角形の y 座標が 0 より大きいなら
function update() {
//上へ動かす条件
if (upPressed && rectY > 0) {
}
}
条件を満たす場合は、四角形の y 座標を更新して上へ動かします。ここで必要になるのが、変数 speedY
です。減算代入演算子 -=
を使って、四角形の y 座標 rectY
から縦移動のスピードを表す speedY
をマイナスし、変数 rectY
の値を更新します。
- 四角形の描画位置を
speedY
の値だけずらし、上へ動かします。
function update() {
if (upPressed && rectY > 0) {
//上へ動かす
rectY -= speedY;
}
}
下へ動かす
次は、下矢印キーが押されているときに下へ動かす文を書きましょう。if
文に以下の二つの条件を指定します。
downPressed
:下矢印キーが押されているrectY + rectHeight < canvas.height
:四角形の y 座標と四角形の高さを足した値がキャンバスの高さより小さい
一つ目の条件では、上矢印キーのときと同じように、キーが押されていることをチェックします。ここでは、二つ目の条件式が長くなっていますね。下の図を見ながら、キャンバスと四角形の位置を確認してみてください。
- 両方の条件を満たす場合は、加算代入演算子
+=
を使って四角形の y 座標rectY
に変数speedY
をプラスし、下へ動かします。
function update() {
if (upPressed && rectY > 0) {
rectY -= speedY;
}
//下へ動かす
if (downPressed && rectY + rectHeight < canvas.height) {
rectY += speedY;
}
}
左右へ動かす
左右へ動かす方法も、上下へ動かす方法と考え方は同じです。キーが押されていることと四角形の位置を if
文で調べます。両方の条件を満たす場合は、変数 speedX
をマイナスまたはプラスし、左右へ動かします。
function update() {
if (upPressed && rectY > 0) {
rectY -= speedY;
}
if (downPressed && rectY + rectHeight < canvas.height) {
rectY += speedY;
}
//左へ動かす
if (leftPressed && rectX > 0) {
rectX -= speedX;
}
//右へ動かす
if (rightPressed && rectX + rectWidth < canvas.width) {
rectX += speedX;
}
}
以上で、押されているキーの方向へ四角形の描画位置を更新する関数 update
を定義できました。
キャンバスに描画してアニメーションする
関数 update
で描画位置を更新できるようになったら、実際に四角形を描きます。キャンバスに描画して四角形を動かす(アニメーションする)関数、draw
を定義していきましょう。キャンバスでアニメーションするためには、次のような流れで処理を行いますよ。
- キャンバスをクリアする
- 描画位置を更新する
- 描画する
- 1〜3 を繰り返してアニメーションする
//キャンバスに描画してアニメーションする
function draw() {
/*-------------------------
1. キャンバスをクリアする
2. 描画位置を更新する
3. 描画する
4. 1〜3を繰り返してアニメーションする
-------------------------*/
}
1. キャンバスをクリアする
clearRect()
メソッドで、キャンバス全体を消去します。
function draw() {
//1. キャンバスをクリアする
ctx.clearRect(0, 0, canvas.width, canvas.height);
/*-------------------------
2. 描画位置を更新する
3. 描画する
4. 1〜3を繰り返してアニメーションする
-------------------------*/
}
2. 描画位置を更新する
- 関数
update
を呼び出し、描画位置を更新します。
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
//2. 描画位置を更新する
update();
/*-------------------------
3. 描画する
4. 1〜3を繰り返してアニメーションする
-------------------------*/
}
3. 描画する
fillRect()
メソッドで、四角形を描きます。
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
update();
//3. 描画する
ctx.fillRect(rectX, rectY, rectWidth, rectHeight);
/*-------------------------
4. 1〜3を繰り返してアニメーションする
-------------------------*/
}
4. 1〜3を繰り返し、アニメーションする
requestAnimationFrame()
メソッドで、関数draw
を繰り返し呼び出してアニメーションします。
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
update();
ctx.fillRect(rectX, rectY, rectWidth, rectHeight);
//4. 1〜3を繰り返してアニメーションする
requestAnimationFrame(draw);
}
以上で、キャンバスに描画してアニメーションする関数 draw
を定義できました。アニメーションを開始するためには、あらかじめ関数 draw
を呼び出しておきましょう。
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
update();
ctx.fillRect(rectX, rectY, rectWidth, rectHeight);
requestAnimationFrame(draw);
}
//アニメーション開始
draw();
完成コード
キャンバスに描いたオブジェクトを矢印キーで操作するコードが完成です。
/**************************************************/
/* キャンバスに描いたオブジェクトを矢印キーで操作するコード */
/**************************************************/
//キャンバスに描画する準備
const canvas = document.querySelector('canvas');
const ctx = canvas.getContext('2d');
//四角形のサイズ
const rectWidth = 50;
const rectHeight = 50;
//四角形の最初の位置はキャバスの中央
let rectX = canvas.width / 2 - rectWidth / 2;
let rectY = canvas.height / 2 - rectHeight / 2;
//四角形の移動速度
let speedX = 3;
let speedY = 3;
//キーが押されているかどうか(trueまたはfalse)
let upPressed = false;
let downPressed = false;
let leftPressed = false;
let rightPressed = false;
//押されたキーを示す
function keyDownHandler(e) {
switch (e.key) {
case 'ArrowUp':
upPressed = true;
break;
case 'ArrowDown':
downPressed = true;
break;
case 'ArrowLeft':
leftPressed = true;
break;
case 'ArrowRight':
rightPressed = true;
break;
}
}
//離されたキーを示す
function keyUpHandler(e) {
switch (e.key) {
case 'ArrowUp':
upPressed = false;
break;
case 'ArrowDown':
downPressed = false;
break;
case 'ArrowLeft':
leftPressed = false;
break;
case 'ArrowRight':
rightPressed = false;
break;
}
}
//押されているキーの方向へ四角形の描画位置を更新
function update() {
if (upPressed && rectY > 0) {
rectY -= speedY;
}
if (downPressed && rectY + rectHeight < canvas.height) {
rectY += speedY;
}
if (leftPressed && rectX > 0) {
rectX -= speedX;
}
if (rightPressed && rectX + rectWidth < canvas.width) {
rectX += speedX;
}
}
//キャンバスに描画してアニメーションする
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
update();
ctx.fillRect(rectX, rectY, rectWidth, rectHeight);
requestAnimationFrame(draw);
}
//キーが押されたことを確認
document.addEventListener('keydown', keyDownHandler);
//キーが離されたことを確認
document.addEventListener('keyup', keyUpHandler);
//アニメーション開始
draw();
もし、矢印キーを押すたびに画面も動いてしまう場合は、keyDownHandler(e)
関数の先頭に e.preventDefault();
を追加すると、矢印キーを押下しても画面がスクロールしないようになりますよ。以下の CodePen の JavaScript コードを参考にしてください。
See the Pen JavaScript - Moving an Object with the Arrow Keys by Pyxofy (@pyxofy) on CodePen.
「きょうからはじめるスクラッチプログラミング入門」
Pyxofy から Scratch の基本をまとめた電子書籍を出版しました。
Kindle・Apple Books からご購入ください。
まとめ
今回は、HTML のキャンバス <canvas>
に JavaScript で四角いオブジェクトを描き、上下左右の矢印キーで動かす方法を紹介しました。
キーボードのキーで操作するためには、キーが押されていることと押されていないことを確認できるようにします。そして、該当するキーが押されているときだけ、オブジェクトの座標を更新して描画する位置を少しずつずらし、requestAnimationFrame()
メソッドでアニメーションします。矢印キーだけでなく他のキーにも応用できるので、試してみてくださいね。
最後まで読んでいただき、ありがとうございます。この記事をシェアしてくれると嬉しいです!
SNSで Pyxofy とつながりましょう! LinkedIn・ Threads・ Mastodon・ X (Twitter) @pyxofy・ Facebook