Unityでマインスイーパーを作ろう 1

マインスイーパーを作ろう

今回はマインスイーパーを作ってみようと思います。WindowsOSに標準搭載されていたこともあり、多くの人が遊んだことのあるゲームだと思います。Windows 8 以降だと搭載されていないので、ストアからDLする必要があるみたいですね。

ゲーム画面は正方形のマスが敷き詰められた長方形のフィールドから構成されている。それぞれのマスは開けることができるが、地雷の置かれているマスを開けると負けとなる。地雷の置かれていないマスを開けたときは、隣接する8マスのいずれかに地雷がある場合はその個数が表示され、隣接するマスに地雷が置かれていないときは、それらが自動的に開けられる。地雷の置かれていないマスをすべて開ければ勝ちとなる。

ゲームの基本的なルールは上記のとおりです。これをベースに以下のルールで実装を行います。
  • 爆弾のあるセルを開いたらゲームオーバー
  • 隣接する爆弾が0個のセルを開いたら隣接するセルすべての展開を行う
  • 爆弾のないセルすべてが展開できたらゲームクリア

なお本ゲームでは “正方形のマス” を “セル” と呼ぶことにします。

完成予定のゲームとソース

完成するゲームは以下のページで遊べます。

Unity WebGL Player | Minesweeper

ソースはGitHub上にあります。

gamegame-game/Minesweeper
Unity Game, Minesweeper. Contribute to gamegame-game/Minesweeper development by creating an account on GitHub.

処理シーケンス

だいたいの流れは以下の図の通りです。登場するクラスは3つだけ。

使うもの

今回使用するのは uGUI のボタンです。セルをボタンで表現します。uGUIのクリックイベントは使用しませんが、クリックしてる感がボタンにはあるのでこれを使います。

プロジェクトの作成と設定

プロジェクトの作成

2DでUnityプロジェクトを作成し、名前を「Minesweeper」とします。

シーンの保存

まずは何もない状態でシーンを保存だけしておきます。名前を GameScene とします。

ビルド設定

先にビルド設定だけ済ましておきます。File -> Build Settings からビルド設定画面を開きます。

Scenes In Build

先ほど保存した GameScene をドラッグ&ドロップで Scenes In Build 追加しましょう。

ランタイム設定

Player Settings から .NET 4.6 (C#6) を使用して開発を行えるようにします。以下の記事を参考にどうぞ。

Unity2017 で .NET 4.6 (C# 6.0) を使う方法

画面レイアウト、Prefabの作成

まずはマインスイーパーに必要な画面構成要素を洗い出します。といっても必要なのは展開できるセルだけです。

GameManager の作成

GameManagerという名前のからのオブジェクトを作成しておきます。

Canvas の作成

まずはCanvasを作成します。

Hierarchy -> Create -> UI -> Canvas

作成したらインスペクターから表示サイズの設定を行います。横800x縦600で表示させるために、UIを縦横比に合わせてスケールするようにします。

Field の作成

Canvasの子として空のオブジェクトを作成します。名前を Field とします。このオブジェクトはセルを子に持つようにします。

インスペクターで以下のようにサイズとポジションを設定します。

特にセルの数に応じてサイズは動的に変更されるようにするので設定値の 540*540 は仮の値です。

Cell の作成

爆弾が設定されるセルのオブジェクトを作成します。まずは Button を Field の子に作成し、名前を Cell とします。

Anchor Presets を設定し、左下基準で配置されるようにします。セルのサイズを30*30とします。あと展開されたセルと未展開のセルの色を変更できるようにしたいので、色を “00FFFFFF” としておきます。

あとで必要になるので、コライダーも追加しておきます。

ということでまとめて設定して、以下のようなインスペクターとなります。

Button のテキスト

Font Size を24にして、中央に表示されるようにしておきます。

Hierarchy

この時点でこのような Hierarchy になっています。

Prefab にする

作成した Cell をPrefabにしておきます。PrefabにしたらHierarchyから削除しておきます。

スクリプトの作成

GameManager, Field, Cell という名前の スクリプト(.cs)を作成し、それぞれ同名のオブジェクトに貼り付けておきます。Cell はもちろん Prefab に貼り付けます。

自動生成したセルが画面に配置されるようにする

セルが画面上に配置されるようにします。

Cell.cs

public class Cell : MonoBehaviour
{
    // セル1辺の大きさ
    public static int Size = 30;
}

まずはセルの1辺のサイズを持つようにします。この値は配置される位置を計算するために使います。Prefabのセルのサイズが 32 なのは 30 にすると一回り小さく見えるからです。

Field.cs

次に Field クラスです。Initialize メソッドでCellのPrefabからオブジェクトを生成し、画面上に配置できるようにします。

public class Field : MonoBehaviour
{
    // 生成するセルのプレファブです。
    [SerializeField]
    private GameObject CellPrefab;

    // フィールドに存在するすべてのセルです。
    public Cell[,] Cells { get; private set; }

    // フィールドの初期化(爆弾位置)を行います。
    public void Initialize(int row, int col, int bombCount)
    {
        this.Cells = new Cell[row, col];

        // セルを生成します。
        for (int r = 0; r < this.Cells.GetLength(0); r++)
        {
            for (int c = 0; c < this.Cells.GetLength(1); c++)
            {
                // ひとまず爆弾のないセルとして生成します。
                this.Cells[r, c] = GenerateCell(r, c, false);
            }
        }

        // フィールドサイズを調整します。
        this.GetComponent<RectTransform>().sizeDelta = new Vector2(col * Cell.Size, row * Cell.Size);
    }

    // セルを盤面に初期化・生成します。
    private Cell GenerateCell(int r, int c, bool isBomb)
    {
        // ゲームオブジェクトを画面に配置します。
        var go = Instantiate(CellPrefab, this.gameObject.GetComponent<RectTransform>());
        go.GetComponent<RectTransform>().anchoredPosition = new Vector2(Cell.Size / 2 + Cell.Size * c, Cell.Size / 2 + Cell.Size * r);

        // セルクラスを初期化します。
        var cell = go.GetComponent<Cell>();

        return cell;
    }
}

Initialize(int row, int col, int bombCount)

フィールドの状態を初期化するためのメソッドです。メソッドの引数は、行数、列数、存在する爆弾の個数です。行数*列数がセルの個数になります。

フィールドに存在するCellは、2次元配列で管理するようにします。2次元配列の各要素は GenerateCell で生成します。

GenerateCell(int r, int c, bool isBomb)

このメソッドで行うのは以下の3点です。

  1. Prefabからゲームオブジェクトの生成
  2. 画面上に表示
  3. Cellコンポーネントを取得して返す

メソッドの引数は、行番号、列番号、爆弾の有無です。

まず、Instantiateでオブジェクトを生成します。表示位置はanchoredPositionでいい感じに調整しています。

生成したオブジェクトからCellコンポーネントを取得します。これを戻り値として返します。

GameManager.cs

using UnityEngine;

public class GameManager : MonoBehaviour
{
    void Start()
    {
        Play();
    }

    // ゲームを開始します
    private void Play()
    {
        var field = GameObject.Find("Field").GetComponent<Field>();

        // 行数、列数、爆弾の個数を指定してフィールドを初期化します。
        field.Initialize(9, 9, 10);
    }
}

動かしてみる

この時点で動かしてみましょう。すると画面中央に 9*9 のボタンが並びます。こんな感じです。

適当に行数と列数を設定してみて、画面中央にいい感じで表示されるようになっているか確認しておきましょう。

まとめ

きりが良いのでここまでにします。

コメント