JavaScript - 矢印キーで動かす方法

キャンバスに描いたオブジェクトを矢印キーで操作しよう

この記事では、キーボードのキーを使ってオブジェクト(物)を動かす方法を紹介します。今回は、HTML のキャンバス <canvas> に JavaScript で正方形のオブジェクトを描き、上下左右の矢印キーで操作できるようにコーディングします。

この記事を読むと分かること

  • keydown イベント
  • keyup イベント
  • switch
  • key プロパティ

サンプルプロジェクト

最初に、キャンバスに描いたオブジェクトを矢印キーで操作する動きを確認しておきましょう。

  • オブジェクトは、キャンバスの内側で上下左右に移動する(キャンバスの外には行かない)
  • 上下と左右のキーを同時に押すと、斜めに移動する
キャンバスに描いた四角形を矢印キーで操作するサンプル

キャンバスの使い方はもう知っていますか?キャンバスに描画する方法や、キャンバスを使ったアニメーションの作り方(オブジェクトを動かす方法)は、以下の記事で解説しているので、併せてご覧ください。

JavaScript - Canvas に図形を描く方法
HTML の canvas 要素を利用すると、JavaScript でグラフィックを描くことができます。基本的なメソッドを学んで、四角形や三角形、円やテキストなど簡単な図形を描画できるようになりましょう。
JavaScript - ボールが跳ね返るアニメーションの作り方
ボールが動き続けるアニメーションを JavaScript で作ります。requestAnimationFrame() メソッドの使い方や、キャンバスに図形を描画してアニメーションを作る基本的な方法を学びましょう。

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');

四角形を描くための変数

矢印キーで動かすのは、キャンバスに描いた四角形です。四角形を描画するために必要な変数を用意しましょう。

  • 変数 rectWidthrectHeight は、四角形の横と縦のサイズです。ここでは同じ値を設定し、正方形になるようにします。
  • 変数 rectXrectY は、四角形を描画する位置の x 座標と y 座標を表します。最初は、キャンバスの中央を指定します。
  • 変数 speedXspeedY は、四角形の横移動と縦移動の速さを表します。値が大きければ大きいほど、動きが速くなります。
// 四角形のサイズ
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 はイベントオブジェクトを表します。詳しくは以下の記事で解説しているのでご覧ください。

JavaScript - イベントオブジェクト - function(e) の e とは?
function(e) の e はイベントオブジェクトを受け取るための変数です。イベントオブジェクトにアクセスして、押されたキーの種類やマウスポインターの座標などの情報を取得できるようになりましょう。

押されたキーが上下左右どのキーに一致するのかを switch 文で調べましょう。switch は、括弧 () 内の式をチェックし、それに当てはまる case を探して実行します。押されたキーの値を取得するために使うのが、引数 ekey プロパティです。引数 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 座標を増やす
キャンバスの x 座標と y 座標

上へ動かす

上下左右のどちらに動かすかは、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. キャンバスをクリアする
  2. 描画位置を更新する
  3. 描画する
  4. 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を繰り返し、アニメーションする

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 とつながりましょう! LinkedInThreadsMastodon X (Twitter) @pyxofyFacebook

関連記事

JavaScript - setInterval() を使ったアニメーションの基本
この記事では JavaScript でアニメーションを作る方法を解説します。ポイントとなるのは setInterval() メソッドと clearInterval() メソッドです。ボタンをクリックしてアニメーションを動かしたり止めたりする方法を学びましょう。
CSS Art – How to Make a Sunset Scene
In this step-by-step article, we’ll combine CSS linear, radial, conic gradient and mask image to make a sunset scene.
CSS Animation – Jumping Box with @property – Part 1
You can make an orange-colored 3D-ish box jump up and down with CSS. Learn how to make this animation in this step-by-step article.
スクラッチプログラミング - プラットフォームゲームのつくりかた
かんたんなプラットフォーマーをプログラミングできるようになりましょう。変数(へんすう)をつかったリアルなジャンプ、スプライトのそうさ方法(ほうほう)やあたりはんていなど、つくりかたの基本(きほん)をしょうかいします。