JavaScript を使ってスライドパズルゲームを作成する

JavaScriptBeginner
オンラインで実践に進む

はじめに

JavaScript を使って簡単なスライドパズルゲームを作成するこのプロジェクトへようこそ。このガイドを終えると、ブラウザで遊ぶことができる機能付きの 3x3 のスライドパズルゲームができます。このゲームには、番号付きのタイル、タイマー、ゲームの開始、一時停止、リセットを行うコントロールが備えられています。

事前の経験は必要ありませんが、JavaScript と HTML の基本的な理解が役立ちます。さあ、始めましょう!

👀 プレビュー

Sliding Puzzle Game Preview

🎯 タスク

このプロジェクトでは、以下を学びます。

  • HTML でゲームのレイアウトをデザインする方法
  • ゲームの CSS スタイルを記述する方法
  • JavaScript でゲーム変数を初期化する方法
  • タイルの移動を処理するための move 関数を実装する方法
  • 可能なタイルの移動を判断する方法
  • ゲームタイマーを実装する方法
  • 開始、一時停止、リセット関数でゲームフローを制御する方法
  • 最初またはリセット時にタイルをランダムにシャッフルする方法
  • ページ読み込み時にゲームを初期化する方法

🏆 成果

このプロジェクトを完了すると、以下のことができるようになります。

  • HTML を使ってゲームのレイアウトをデザインする
  • CSS を使って要素をスタイリッシュにする
  • JavaScript を使ってゲームロジックを実装する
  • ユーザー入力を処理し、それに基づいてアクションを実行する
  • DOM を操作してゲーム状態を更新し、情報を表示する

HTML でゲームのレイアウトをデザインする

前の解説で述べた通り、index.html でゲームのレイアウトをデザインします。

<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Puzzle</title>
    <link rel="stylesheet" type="text/css" href="puzzle.css" />
    <script type="text/javascript" src="puzzle.js"></script>
  </head>
  <body>
    <div id="container">
      <!-- 最外側の DIV。内部構造を含むために使用 -->
      <div id="game">
        <!-- ゲームエリア。大きな DIV ブロック -->
        <div id="d1" onclick="move(1)">1</div>
        <!-- 小さな DIV。8 つの小ブロック。クリックすると move() 関数が実行される。パラメータは表示されている数字なので、どのブロックがクリックされたかを知ることができる -->
        <div id="d2" onclick="move(2)">2</div>
        <div id="d3" onclick="move(3)">3</div>
        <div id="d4" onclick="move(4)">4</div>
        <div id="d5" onclick="move(5)">5</div>
        <div id="d6" onclick="move(6)">6</div>
        <div id="d7" onclick="move(7)">7</div>
        <div id="d8" onclick="move(8)">8</div>
      </div>
      <div id="control">
        <!-- ゲーム制御エリア -->
        <p>
          <rowspan id="timeText">Total Time</rowspan>
          <!--  "Total Time" -->
          <rowspan id="timer"></rowspan>
        </p>
        <!-- ゲーム時間を表示するエリア -->
        <p>
          <rowspan id="start" onclick="start()">Start</rowspan>
          <!--  "Start" -->
          <rowspan id="reset" onclick="reset()">Retry</rowspan>
          <!--  "Retry" -->
        </p>
        <!-- 制御ボタンを表示するエリア -->
      </div>
    </div>
  </body>
</html>
✨ 解答を確認して練習

CSS スタイルの記述

レイアウト構造を完成させたら、CSS スタイルでゲームを美化しましょう。この段階では、好みに合わせてゲームをカスタマイズし、独自のコンセプトや詳細を追加することができます。また、ゲームの美観を高めるために、さらに装飾要素を導入することもできます。ただし、重要なポイントとして、ゲームのメイン DIV のサイズを変更する場合、付随する JavaScript コードも調整する必要があります。これについては、すぐに詳しく説明します。

puzzle.css に以下を追加します。

* {
  padding: 0;
  margin: 0;
  border: 0;
}
/* '*'はワイルドカードで、すべての要素のデフォルトスタイルを削除します。一部のブラウザはデフォルトスタイルを追加することがあり、レイアウトの問題を引き起こす可能性があるためです。 */

body {
  width: 100%;
  height: 100%;
}
/* body の高さと幅を 100% に設定することで、ブラウザの画面サイズに自動的に適応します。 */

#container {
  position: relative;
  width: 620px;
  height: 450px;
  margin: 0 auto;
  margin-top: 100px;
  border-radius: 1px;
}
/* これはすべての要素を囲む DIV です。幅を 620px、高さを 450px に設定します。このサイズは増やすことができますが、減らすことはできません。内部のすべての要素を収容できるだけの大きさである必要があります。 */

#game {
  position: absolute;
  width: 450px;
  height: 450px;
  border-radius: 5px;
  display: inline-block;
  background-color: #ffe171;
  box-shadow: 0 0 10px #ffe171;
}
/* これはゲームエリアの DIV です。サイズは小さなブロックのサイズに基づいて計算されます。ここではブロックのサイズを 150px×150px に設定しているため、ゲームエリアは 150px×3 = 450px になります。 */

#game div {
  position: absolute;
  width: 149px;
  height: 149px;
  box-shadow: 1px 1px 2px #777;
  background-color: #20a6fa;
  color: white;
  text-align: center;
  font-size: 150px;
  line-height: 150px;
  cursor: pointer;
  -webkit-transition: 0.3s; /* Chrome 互換のブラウザプレフィックス */
  -moz-transition: 0.3s; /* Firefox 用 */
  -ms-transition: 0.3s; /* IE 用 */
  -o-transition: 0.3s; /* Opera 用 */
  transition: 0.3s;
}
/* これは小さなブロックのサイズを設定します。位置を絶対位置に設定することで、位置の変更が他の要素の位置に影響を与えなくなります。幅と高さはともに 149px です。特に、box-shadow を設定することで全体のサイズが増えます。'transition:0.3s'プロパティにより、変更がアニメーションとして表示されるようになります。つまり、ブロックの位置が変更されると、自動的にアニメーションが再生されます。 */

#game div:hover {
  color: #ffe171;
}
/* ブロックに対するマウスホバーアニメーションを設定します。マウスが要素の上にホバーすると、これらのプロパティが上記のものに置き換えられ、マウスが離れると元に戻ります。ここでは、フォントカラーを変更しています。 */

#control {
  width: 150px;
  height: 450px;
  display: inline-block;
  float: right;
}
/* 制御セクションです。'display:inline-block'により、要素はブロックプロパティを維持しながら、1 行を埋め尽くさずに表示されます。'float:right'により、右側に配置されます。 */

#control rowspan {
  height: 25px;
  font-size: 20px;
  color: #222;
  margin-top: 10px;
}
/* 制御エリアのボタンの共通スタイルです。 */

#start {
  display: inline-block;
  font-size: 28px;
  width: 100px;
  height: 28px;
  background-color: #20a6fa;
  color: #ffe171;
  text-shadow: 1px 1px 2px #ffe171;
  border-radius: 5px;
  box-shadow: 2px 2px 5px #4c98f5;
  text-align: center;
  cursor: pointer;
}
/* 'Start'ボタンのスタイルです。'cursor:pointer'により、マウスが上にホバーすると、カーソルが手の印に変わります。 */

#reset {
  display: inline-block;
  font-size: 28px;
  width: 100px;
  height: 28px;
  background-color: #20a6fa;
  color: #ffe171;
  text-shadow: 1px 1px 2px #ffe171; /* フォントシャドウ */
  border-radius: 5px; /* 角丸 */
  box-shadow: 2px 2px 5px #4c98f5; /* ボックスシャドウ */
  text-align: center; /* テキストを中央に配置 */
  cursor: pointer;
}
/* 'Reset'ボタンのスタイルです。 */

#d1 {
  left: 0px;
}
#d2 {
  left: 150px;
}
#d3 {
  left: 300px;
}
#d4 {
  top: 150px;
}
#d5 {
  top: 150px;
  left: 150px;
}
#d6 {
  top: 150px;
  left: 300px;
}
#d7 {
  top: 300px;
}
#d8 {
  left: 150px;
  top: 300px;
}
/* 各ブロックの事前定義の位置を順に設定します。 */

スタイルを設定することは大きな一歩です。次に、JavaScriptロジックに移り、パズルゲームを動かしましょう。最初のスタイリングは上記の指示に従って行うことをお勧めします。ゲームの機能が十分に理解されたら、自由に創造性を発揮してスタイルをさらにカスタマイズすることができます。ただし、初期段階で無計画な変更を行うと、予期せぬ不具合が発生する可能性があります。
✨ 解答を確認して練習

JavaScript でゲーム変数を初期化する

ゲーム機能を追加する前に、必須のゲーム状態変数を初期化します。

puzzle.js に以下を追加します。

// puzzle.js

var time = 0;
// 経過時間を保存する
var pause = true;
// ゲームが一時停止しているかどうかを示すフラグ。true の場合、一時停止している
var set_timer;
// タイマー関数
var d = new Array(10);
// 大きな DIV の中に現在ある小さな DIV の番号を格納する
var d_direct = new Array(
  [0],
  [2, 4], // 数字 1 の大きな DIV は位置 2 と 4 に移動できる
  [1, 3, 5],
  [2, 6],
  [1, 5, 7],
  [2, 4, 6, 8],
  [3, 5, 9],
  [4, 8],
  [5, 7, 9],
  [6, 8]
);
// 大きな DIV の可能な移動位置を保存する
var d_posXY = new Array(
  [0],
  [0, 0], // 最初の数字は左を表し、2 番目は上を表す。例えば、最初のブロックの位置は左:0px、上:0px
  [150, 0],
  [300, 0],
  [0, 150],
  [150, 150],
  [300, 150],
  [0, 300],
  [150, 300],
  [300, 300]
);
// 大きな DIV の位置
d[1] = 1;
d[2] = 2;
d[3] = 3;
d[4] = 4;
d[5] = 5;
d[6] = 6;
d[7] = 7;
d[8] = 8;
d[9] = 0;
// 初期配置。9 番目の大きな DIV は空なので 0。空白のタイルを表すために 0 を使用する
✨ 解答を確認して練習

移動関数を実装する

ユーザーの操作に基づいてタイルを移動させる関数を作成します。

puzzle.js に以下を追加します。

// puzzle.js

function move(id) {
  // 移動関数
  var i = 1;
  for (i = 1; i < 10; ++i) {
    if (d[i] == id) break;
  }
  // このループは、大きな DIV 内の小さな DIV の位置を見つけます
  var target_d = 0;
  // 小さな DIV の可能な位置を保存します。0 は移動できないことを意味します
  target_d = whereCanTo(i);
  // 小さな DIV が移動できる場所を見つけます。0 を返す場合は移動できないことを意味し、それ以外の場合はターゲット位置番号を返します
  if (target_d != 0) {
    d[i] = 0;
    // 現在の大きな DIV の番号を 0 に設定します。小さな DIV が移動したため、現在の大きな DIV は空になりました
    d[target_d] = id;
    // ターゲットの大きな DIV をクリックされた小さな DIV の番号に設定します
    document.getElementById("d" + id).style.left = d_posXY[target_d][0] + "px";
    document.getElementById("d" + id).style.top = d_posXY[target_d][1] + "px";
    // 最後に、クリックされた小さな DIV の位置をターゲットの大きな DIV の位置に設定します
  }

  var finish_flag = true;
  // ゲームが完了したかどうかを示すフラグ。true の場合、完了しています
  for (var k = 1; k < 9; ++k) {
    if (d[k] != k) {
      finish_flag = false;
      break;
    }
  }
  // 1 から始めて、各大きな DIV の番号をチェックします。順序が正しくない場合は、ゲームは完了していません
  if (finish_flag == true) {
    if (!pause) start();
    alert("Congratulations!");
  }
  // true の場合、ゲームは完了しています。一時停止していない場合は、一時停止関数を呼び出して成功メッセージを表示します
}
✨ 解答を確認して練習

可能なタイルの移動を決定する

現在の位置に基づいてタイルがどこに移動できるかを決定する関数を作成します。

puzzle.js に以下を追加します。

// puzzle.js

function whereCanTo(cur_div) {
  // 与えられた DIV が移動できるかどうかと、どの位置に移動できるかを決定する関数
  var j = 0;
  var move_flag = false;
  for (j = 0; j < d_direct[cur_div].length; ++j) {
    if (d[d_direct[cur_div][j]] == 0) {
      move_flag = true;
      break;
    }
  }
  if (move_flag == true) {
    return d_direct[cur_div][j];
  } else {
    return 0;
  }
  // 移動できる場合は、ターゲット位置番号を返し、そうでない場合は 0 を返す
}
✨ 解答を確認して練習

ゲームタイマーを実装する

ゲーム中の経過時間を追跡するためのタイマー関数を追加します。

puzzle.js に以下を追加します。

// puzzle.js

function timer() {
  // タイマー関数。1 秒ごとに実行されます
  time += 1;
  var min = parseInt(time / 60); // 秒を分に変換する
  var sec = time % 60; // 残りの秒数を取得する
  document.getElementById("timer").innerHTML =
    min + " minutes " + sec + " seconds";
}
✨ 解答を確認して練習

ゲームフローを制御する

ユーザー入力に基づいてゲームを開始、一時停止、またはリセットする関数を実装します。

puzzle.js に以下を追加します。

// puzzle.js

function start() {
  // ゲームを開始または一時停止する
  if (pause) {
    document.getElementById("start").innerHTML = "Pause";
    pause = false;
    set_timer = setInterval(timer, 1000);
  } else {
    document.getElementById("start").innerHTML = "Start";
    pause = true;
    clearInterval(set_timer);
  }
}
function reset() {
  // ゲームをリセットする
  time = 0;
  random_d();
  if (pause) start();
}
✨ 解答を確認して練習

タイルをランダムにシャッフルする

ゲーム開始時またはリセット時にタイルをランダムにシャッフルする関数を作成します。

puzzle.js に以下を追加します。

// puzzle.js

function random_d() {
  // タイルをランダムにシャッフルする
  for (var i = 9; i > 1; --i) {
    var to = parseInt(Math.random() * (i - 1) + 1);
    if (d[i] != 0) {
      document.getElementById("d" + d[i]).style.left = d_posXY[to][0] + "px";
      document.getElementById("d" + d[i]).style.top = d_posXY[to][1] + "px";
    }
    if (d[to] != 0) {
      document.getElementById("d" + d[to]).style.left = d_posXY[i][0] + "px";
      document.getElementById("d" + d[to]).style.top = d_posXY[i][1] + "px";
    }
    var tem = d[to];
    d[to] = d[i];
    d[i] = tem;
  }
}
✨ 解答を確認して練習

ページ読み込み時にゲームを初期化する

最後に、Web ページが読み込まれたときにゲームのタイルが表示され、プレイ準備ができていることを確認します。

puzzle.js に以下を追加します。

// puzzle.js

// ページ読み込み時にゲームを初期化する
window.onload = function () {
  reset();
};
✨ 解答を確認して練習

プロジェクトの実行

  • Web ブラウザで index.html を開きます。
    open web

  • ページの表示は以下の通りです。
    puzzle game page preview

✨ 解答を確認して練習

まとめ

これで、JavaScript を使って構造化された方法でスライドパズルゲームを成功裏に作成しました!段階的な解説により、学習者がゲームのロジックの各コンポーネントを理解しやすくなるはずです。これはただの基本バージョンであり、拡張や追加機能の余地がたくさんあることを忘れないでください。挑戦して、自分だけのものにしてみましょう。楽しいコーディングを!