LoginSignup
12
9

More than 3 years have passed since last update.

[連載]スーパーマリオ的なゲームをjavascriptで作ってみる 初級編 〜3章〜 画像を動かしてみる

Last updated at Posted at 2020-01-04

本連載について

本章の概要

  • 本章では主人公の画像を表示して、キーボードの入力に応じて動かすとこまでいきます
  • ゲームっぽくジャンプしたり、落ちたり敵にぶつかってゲームオーバーになったりはこの後やります
  • 本章の内容は大きく4ステップです
    • その1 〜画像を表示できるよの巻〜
    • その2 〜画像が動くよの巻〜
    • その3 〜キーボードの入力が検知できるよの巻〜
    • その4 〜画像を動かせるよの巻〜
  • 各ステップごとに実際のソースをQiita上に記載しています
  • 上記と同じくソースの実態を保存しているgitのリポジトリも記載しています
    リンクにアクセスして実際のソースをダウンロードすることができます
    ぜひダウンロードして動かしながら試してみてください!

その1 〜画像を表示できるよの巻〜

ゴール

  • 特定の画像をcanvas要素のエリアに表示すること
  • マリオのゲーム作るにはマリオを画面に表示することは必要ですからね!

前提

  • 大枠の流れとしては、 canvas 要素に対して どこに どんな画像 を表示するかを指定します
  • canvas 要素に対して画像の指定する際は drawImage の関数を使用します
  • 画像を表示する場合、主に 画像ファイルのパス指定する または 画像をエンコードして文字列としたものを記載する の2択がありますが今回は前者を採用します

やること

  • 画像ファイルを作成し、配置します ([参考]ドッド絵を作成する)
  • index.jsindex.html で定義した canvas 要素を取得するように修正します
  • Image 要素を作成し、 canvas 要素に対して追加(draw)するように修正します
  • フォルダ階層は以下ようにしています
└┬─ src    ┬─ index.html
 │         └─ index.js
 └─ images ── character-01 ── base.png

▼ソース

index.js
// canvas要素の取得
const canvas = document.getElementById("maincanvas");
const ctx = canvas.getContext("2d");

// ロード時に画面描画の処理が実行されるようにする
window.addEventListener("load", update);

// 画面を更新する関数を定義 (繰り返しここの処理が実行される)
function update() {
  // 画面全体をクリア
  ctx.clearRect(0, 0, 640, 480);

  // 主人公の画像を表示
  var image = new Image();
  image.src = "../images/character-01/base.png";
  ctx.drawImage(image, 0, 0, 32, 32);

  // 再描画
  window.requestAnimationFrame(update);
}

※ 実際のソースコードは こちら からダウンロードできます

▼CodePenのサンプル

See the Pen mario-game-tutorial-01-03-01 by taku7777777 (@taku7777777) on CodePen.

説明

  • document.getElementById("maincanvas")canvas 要素を取得しています
    maincanvasindex.htmlcanvas 要素の id として指定しているものです
    index.js 内から index.html に記載している要素を取得することができます
  • canvas.getContext("2d") で取得した canvas 要素からさらに二次元の情報(今回描画したい対象の情報)を取得します
    ここまでは定型文のようなものなので、深く突っ込まず「へぇーこうゆうふうに記載すればいいんだ」くらいでOKです!
  • ctx.clearRect(0, 0, 640, 480)canvas 要素の描画対象をクリアしている
    これをしないと、この後に実施する画像表示の処理が重複して、意図せず複数の画像が表示されかねないので注意です
  • var image = new Image() で新しく画像要素を作成し、 image.src = "../images/character-01/base.png" で画像要素の画像情報を定義しています
  • ctx.drawImage(image, 0, 0, 32, 32) では どの画像要素どこに どのような大きさで 表示するかを定義しています
    今回の例では、"../images/character-01/base.png" の画像をx座標が0(一番左から右に0ピクセル移動したとこ)、y座標が0(一番上から下に0ピクセル移動したとこ)に横幅32ピクセル、縦幅32ピクセルで画像を表示するということになります
    例えば ctx.drawImage(image, 100, 200, 10, 20) の場合x座標が100(一番左から右に100ピクセル移動したとこ)、y座標が200(一番上から下に200ピクセル移動したとこ)に横幅10ピクセル、縦幅20ピクセルで画像を表示するということになります

その2 〜画像が動くよの巻〜

ゴール

  • 表示した画像が横に少しづつ動くようにします!(超簡単なアニメーション!?)

やること

  • 「その1 〜画像を表示できるよの巻〜」で対応した drawImage の画像表示位置を少しづつ変えます
  • 最初は一番左に画像を表示し、一定の速度で右に移動するようにします

▼ソース

index.js
// canvas要素の取得
const canvas = document.getElementById("maincanvas");
const ctx = canvas.getContext("2d");

// ロード時に画面描画の処理が実行されるようにする
window.addEventListener("load", update);

// 主人公の初期座標を定義
var x = 0;

// 画面を更新する関数を定義 (繰り返しここの処理が実行される)
function update() {
  // 画面全体をクリア
  ctx.clearRect(0, 0, 640, 480);

  // 座標を更新する
  x = x + 1;

  // 主人公の画像を表示
  var image = new Image();
  image.src = "../images/character-01/base.png";
  ctx.drawImage(image, x, 0, 32, 32);

  // 再描画
  window.requestAnimationFrame(update);
}

※ 実際のソースコードは こちら からダウンロードできます

▼CodePenのサンプル (右下の"return"をクリックして、リフレッシュしてから確認してみてください)

See the Pen mario-game-tutorial-01-03-02 by taku7777777 (@taku7777777) on CodePen.

説明

  • x座標を変数化し(x)、update処理が実施されるごとに1増えるようにしています

その3 〜キーボードの入力が検知できるよの巻〜

ゴール

  • キーボードで上下右左が押されたことを検知できるようにします
  • これができると入力に応じていろんなことをできるようになります!

やること

  • 以下のソースをコピペ
    (これも定型文みたいなものなので細かいとこは気にしなくて大丈夫ですー)
index.js
// キーボードの入力状態を記録する配列の定義
var input_key_buffer = new Array();

// キーボードの入力イベントをトリガーに配列のフラグ値を更新させる
window.addEventListener("keydown", handleKeydown);
function handleKeydown(e) {
  console.log("key down : " + e.keyCode);
  input_key_buffer[e.keyCode] = true;

  if (e.keyCode === 37) {
    alert("左が押されたよ");
  } else if (e.keyCode === 38) {
    alert("上が押されたよ");
  } else if (e.keyCode === 39) {
    alert("右が押されたよ");
  } else if (e.keyCode === 40) {
    alert("下が押されたよ");
  }
}

window.addEventListener("keyup", handleKeyup);
function handleKeyup(e) {
  console.log("key up : " + e.keyCode);
  input_key_buffer[e.keyCode] = false;

  if (e.keyCode === 37) {
    alert("左がはなされたよ");
  } else if (e.keyCode === 38) {
    alert("上がはなされたよ");
  } else if (e.keyCode === 39) {
    alert("右がはなされたよ");
  } else if (e.keyCode === 40) {
    alert("下がはなされたよ");
  }
}

※ 実際のソースコードは こちら からダウンロードできます

説明

  • window.addEventListener("keydown", XXXXX) キーボードが押された際に XXXXX の関数を実行するよって定義することができます
  • window.addEventListener("keyup", XXXXX) キーボードが押された状態からはなされた際に XXXXX の関数を実行するよって定義することができます
  • handleKeydown handleKeyup でキーボーが押された際/はなされた際に実行される関数を定義しています
    引数 (e) の部分でキーボードが押された/はなされたイベント情報をもらい、なんのキーが入力されたかを e.keyCode で取得することができます
  • alertのとこの分岐は処理を確認するためのおまけ、本当は不要なコードになります

その4 〜画像を動かせるよの巻〜

ゴール

  • その2、その3を組み合わせて上下左右のボタンを押した方向に画像が動くようにします
  • ちょっとゲームっぽくなってくるのではないでしょうか?

やること

  • 画像のx座標、y座標を変数化します
  • キーボードの入力状態に応じてx座標、y座標を更新します

▼ソース

index.js
// キーボードの入力状態を記録する配列の定義
var input_key_buffer = new Array();

// キーボードの入力イベントをトリガーに配列のフラグ値を更新させる
window.addEventListener("keydown", handleKeydown);
function handleKeydown(e) {
  console.log("key down : " + e.keyCode);
  input_key_buffer[e.keyCode] = true;
}

window.addEventListener("keyup", handleKeyup);
function handleKeyup(e) {
  console.log("key up : " + e.keyCode);
  input_key_buffer[e.keyCode] = false;
}

// canvas要素の取得
const canvas = document.getElementById("maincanvas");
const ctx = canvas.getContext("2d");

// 画像を表示するの座標の定義 & 初期化
var x = 0;
var y = 0;

// ロード時に画面描画の処理が実行されるようにする
window.addEventListener("load", update);

// 画面を更新する関数を定義 (繰り返しここの処理が実行される)
function update() {
  // 画面全体をクリア
  ctx.clearRect(0, 0, 640, 480);

  // 入力値の確認と反映
  if (input_key_buffer[37]) {
    // 左が押されていればx座標を1減らす
    x = x - 1;
  }
  if (input_key_buffer[38]) {
    // 上が押されていればy座標を1減らす
    y = y - 1;
  }
  if (input_key_buffer[39]) {
    // 右が押されていればx座標を1増やす
    x = x + 1;
  }
  if (input_key_buffer[40]) {
    // 下が押されていればy座標を1増やす
    y = y + 1;
  }

  // 主人公の画像を表示
  var image = new Image();
  image.src = "../images/character-01/base.png";
  ctx.drawImage(image, x, y, 32, 32);

  // 再描画
  window.requestAnimationFrame(update);
}

※ 実際のソースコードは こちら からダウンロードできます

▼CodePenのサンプル

See the Pen mario-game-tutorial-01-03-04 by taku7777777 (@taku7777777) on CodePen.

説明

  • input_key_bufferkeyCode ごとにおされているか(true)、押されていないか(false)を保持しているので、update処理を実行する際に押されているキーに応じて座標を更新します

終わりに

お疲れまです!!!

ゲームっぽさが出てきましたね!

次に進みましょう!!!

4章へすすむ!!!



12
9
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
12
9