0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

ゲームを作りながら学ぶ!JavaScript レベルアップ講座 part5

Last updated at Posted at 2020-12-28

こんにちは、Yuiです。

今回は前回描画したスライムを動かす方法について書いていきます。
JavaScript道場はこちら

今回の成果物はこちらです。
Image from Gyazo

キーボードの↑↓→←キーで動かしています。

スライムのデフォルトの場所を中心にする

前回は(0,0)を始点にしてましたが、それだと少し見にくいのでスライムのデフォルトの位置を中央にしましょう。
絶対値で表しても良いのですが、今回はcanvasサイズから計算します。

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <canvas id="canvas" width="640" height="480" style="background-color: black;"></canvas>
  <script>
    const CANVAS_SIZE_W = 640
    const CANVAS_SIZE_HW = 320 // 画面の半分の広さ
    const CANVAS_SIZE_H = 480
    const CANVAS_SIZE_HH = 240 // 画面の半分の高さ
    const CHARACTER_SIZE = 100 // キャラクターの大きさ
    const CHARACTER_HSIZE = 50 // キャラクターの半分の大きさ
    let CHARACTER_POS_X = CANVAS_SIZE_HW - CHARACTER_HSIZE
    let CHARACTER_POS_Y = CANVAS_SIZE_HH - CHARACTER_HSIZE
    const canvas = document.getElementById("canvas")
    const ctx = canvas.getContext("2d")
    const img = new Image()
    img.src = "https://cache-www.dragonquest.jp/hoshidora/assets_190310/narikirislime/pc/slime.png"
    img.onload = () => ctx.drawImage(
      img,
      CANVAS_SIZE_HW - CHARACTER_HSIZE,
      CANVAS_SIZE_HH - CHARACTER_HSIZE,
      CHARACTER_SIZE,
      CHARACTER_SIZE
    )
  </script>
</body>
</html>

これでスライムが中央に来ました。

キーボードに反応してスライムが動くようにする

そして今回肝となるキーボードに反応する部分です。
そのためにはaddEventListenerを使います。

公式ドキュメントはこちら→https://developer.mozilla.org/ja/docs/Web/API/EventTarget/addEventListener

今回はwindowが対象になりますので、window.addEventListenerという風に書きます。

以下を追加します。


    window.addEventListener("keydown", (e) => {
      if (e.key === "ArrowLeft") {
        CHARACTER_POS_X -= 10
        ctx.drawImage(
          img,
          CHARACTER_POS_X,
          CHARACTER_POS_Y,
          CHARACTER_SIZE,
          CHARACTER_SIZE
        )
      }
      if (e.key === "ArrowUp") {
        CHARACTER_POS_Y -= 10
        ctx.drawImage(
          img,
          CHARACTER_POS_X,
          CHARACTER_POS_Y,
          CHARACTER_SIZE,
          CHARACTER_SIZE
        )
      }
      if (e.key === "ArrowRight") {
        CHARACTER_POS_X += 10
        ctx.drawImage(
          img,
          CHARACTER_POS_X,
          CHARACTER_POS_Y,
          CHARACTER_SIZE,
          CHARACTER_SIZE
        )
      }
      if (e.key === "ArrowDown") {
        CHARACTER_POS_Y += 10
        ctx.drawImage(
          img,
          CHARACTER_POS_X,
          CHARACTER_POS_Y,
          CHARACTER_SIZE,
          CHARACTER_SIZE
        )
      }
    })

ここで、keydownというのはkeyがdownしたとき、つまりキーを押してる状態のことをいいます。
そのときにどのキーが押されたかによって反応を変えたいのでeという変数に入れてあげます。
もし→がArrowRightなどと覚えている場合は良いのですが、もし覚えていない場合はここでconsole.log(e)などをするとわかりやすいかと思います。

スクリーンショット 2020-10-19 22.08.21.png

console.log(e)をした状態で→のキーを押してログを出した状態です。
これを見ると→をクリックすると、e.keyArrowRightになることがわかります。これを利用して↑↓→←で動きをそれぞれ付けたのが上記のコードです。

この状態で動かすとこのようになります。

Image from Gyazo

スライムが動くことは動くのですが、軌跡まで残ってしまいます。

スライムが動くたびに毎回描画し直す

軌跡を消すために使うのがcanvasの中のclearRectというメソッドです。
これは範囲を指定することで、その範囲内のものをすべてリセットすることができます。

そういうわけで、ctx.clearRect(0 ,0, CANVAS_SIZE_W, CANVAS_SIZE_H);を以下のように追加します。


    window.addEventListener("keydown", (e) => {
      ctx.clearRect(0 ,0, CANVAS_SIZE_W, CANVAS_SIZE_H);
      if (e.key === "ArrowLeft") {
        CHARACTER_POS_X -= 10
        ctx.drawImage(
          img,
          CHARACTER_POS_X,
          CHARACTER_POS_Y,
          CHARACTER_SIZE,
          CHARACTER_SIZE
        )
      }
      if (e.key === "ArrowUp") {
        CHARACTER_POS_Y -= 10
        ctx.drawImage(
          img,
          CHARACTER_POS_X,
          CHARACTER_POS_Y,
          CHARACTER_SIZE,
          CHARACTER_SIZE
        )
      }
      if (e.key === "ArrowRight") {
        CHARACTER_POS_X += 10
        ctx.drawImage(
          img,
          CHARACTER_POS_X,
          CHARACTER_POS_Y,
          CHARACTER_SIZE,
          CHARACTER_SIZE
        )
      }
      if (e.key === "ArrowDown") {
        CHARACTER_POS_Y += 10
        ctx.drawImage(
          img,
          CHARACTER_POS_X,
          CHARACTER_POS_Y,
          CHARACTER_SIZE,
          CHARACTER_SIZE
        )
      }
    })

これで軌跡が消え、いい感じにスライムが動くようになりました!

#クラス構文を使って書く

上記のままでももちろん良いのですが、今後スライムがたくさん出てきたときのために、クラス構文化して書いておきます。

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <canvas id="canvas" width="640" height="480" style="background-color: black;"></canvas>
  <script>
    const CANVAS_SIZE_W = 640
    const CANVAS_SIZE_HW = 320 // 画面の半分の広さ
    const CANVAS_SIZE_H = 480
    const CANVAS_SIZE_HH = 240 // 画面の半分の高さ
    const CHARACTER_SIZE = 100 // キャラクターの大きさ
    const CHARACTER_HSIZE = 50 // キャラクターの半分の大きさ

    const canvas = document.getElementById("canvas")
    const ctx = canvas.getContext("2d")
    class Slime {
      constructor(posX, posY) {
        const img = new Image()
        img.src = "https://cache-www.dragonquest.jp/hoshidora/assets_190310/narikirislime/pc/slime.png"
        this.img = img
        this.posX = posX
        this.posY = posY
        this.sizeX = 100
        this.sizeY = 100
        img.onload = () => this.drawImage()
      }
      drawImage() {
        ctx.drawImage(this.img, this.posX, this.posY, this.sizeX, this.sizeY)
      }
      move(e) {
        ctx.clearRect(0 ,0, CANVAS_SIZE_W, CANVAS_SIZE_H);
        if (e.key === "ArrowLeft") {
          this.posX -= 10
        }
        if (e.key === "ArrowUp") {
          this.posY -= 10
        }
        if (e.key === "ArrowRight") {
          this.posX += 10
        }
        if (e.key === "ArrowDown") {
          this.posY += 10
        }
        this.drawImage()
      }
    }
    let s = new Slime(CANVAS_SIZE_HW - CHARACTER_HSIZE, CANVAS_SIZE_HH - CHARACTER_HSIZE)
    window.addEventListener("keydown", (e) => {
      s.move(e)
    })
  </script>
</body>
</html>

こうすることで、今後スライムを追加したい場合はnew Slimeと書くだけで生成することができますね!

クラス構文、便利ですね。

今回はスライム一個だけの設計なので、正直クラス構文にしてもしなくてもどちらでも問題は無いです。
ただ、今後ゲームを作っていく中で、敵をいくつか生成したりすることがあるかとおもいます。
そのたびに毎回同じコードを書くようでは効率が悪いので、使えるときはクラス構文でまとめておくのが楽でいいですね。

それでは今回はスライムを動かすところまでやりました。

それでは次回はパーティメンバーのステータスを表示する部分を実装していきます。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?