アマゾンバナーリンク

Unityで作る15パズル

こんにちは!ジェイです。只今TPSオンラインゲーム制作中ですが、たまにはサクッと短時間で作れるゲームを紹介したいと思って、今回は15パズルをUnityで作ります。

下準備

まずはSpriteの準備をします。Spriteでは以下の画像データを利用することができます。今回使う素材は、私の誕生日のお祝いの時にミーゼアちゃんが描いてくれた絵を使わせていただきます。

BMP・EXR・GIF・HDR・IFF・JPG・PICT・PNG・PSD・TGA・TIFF・GIF・JPG・PNGといった定番の形式から幅広く対応しています。

次にスプライトを分割して使うための設定をします。まずはResourcesをつくり素材となる画像を入れます。その後、画像を選択し、以下のようにMultipluを選びSprite Editorを選択します。

詳細設定はこちら

今回は4×4=16にパズルを配置したいので、TypeをGrid By Countにしました。他にもピクセルを指定したりする方法もあります。その後Resourcesフォルダを作成し中にいれておきましょう。(Resources.LoadAllで使うため)

カメラの設定

ソースコード

次に空のオブジェクトを作り以下のコードを張り付けましょう!

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class CPazuru : MonoBehaviour
{
    public AudioClip audioClip1;
    private AudioSource audioSource;
    public Text NumberText;
    const int PANEL_X_NUM = 4;
    const int PANEL_Y_NUM = 4;
    const int ALL_PANEL_NUM = PANEL_X_NUM * PANEL_Y_NUM;

    int PanelXSize;
    int PanelYSize;
    int PicAll;
    int[] Pics = new int[ALL_PANEL_NUM];
    int[] Panel = new int[ALL_PANEL_NUM];
    enum EState
    { 
        TITLE, MAIN, CLEAR 
    }
    EState State = EState.TITLE;

    // スプライト画像格納用の配列
    Sprite[] sprites;
    GameObject[] PanelObj;

    Vector2[] BasePos;
    // Start is called before the first frame update
    void Start()
    {
        audioSource = gameObject.GetComponent<AudioSource>();
        audioSource.clip = audioClip1;
        // スプライトを配列にロードする
        sprites = Resources.LoadAll<Sprite>("jay");

        // 空のゲームオブジェクトを作成する
        GameObject obj = new GameObject();
        PanelObj = new GameObject[sprites.Length];
        BasePos = new Vector2[sprites.Length];
        // とりあえずスプライトの数だけループ
        for (int i = 0; i < sprites.Length; i++)
        {
            // 空のゲームオブジェクトを生成する、横に並べてみた
            PanelObj[i] = Instantiate(obj, new Vector3(2.6f*(i%4), -1.85f*(i/4), 0), Quaternion.identity) as GameObject;

            // 生成したゲームオブジェクトはTransformのみなのでSpriteRendererをスクリプトから追加、スプライトに配列の画像を代入
            SpriteRenderer sr = PanelObj[i].AddComponent<SpriteRenderer>();
            sr.sprite = sprites[i];
            PanelObj[i].AddComponent<BoxCollider2D>();

            PanelObj[i].name = i.ToString();
            PanelObj[i].tag = "Panle";
            BasePos[i].x = PanelObj[i].transform.position.x;
            BasePos[i].y = PanelObj[i].transform.position.y;
        }

        // 空のゲームオブジェクトが気に入らないのでとりあえず消しとく
        Destroy(obj);

        PanelXSize = Screen.width / PANEL_X_NUM;
        PanelYSize = Screen.height / PANEL_Y_NUM;
    }
    void Change(int x, int y)
    {
        int p1 = y * PANEL_X_NUM + x; // クリックしたパネル番号
        int p2 = -1; // 次に移動する予定のパネル番号

        // 左端に空白がある場合は左へ移動
        if (x > 0 && Panel[p1 - 1] == ALL_PANEL_NUM - 1)
        {
            p2 = p1 - 1;
        }
        // 右に空白がある場合は右へ移動
        if (x < PANEL_X_NUM - 1 && Panel[p1 + 1] == ALL_PANEL_NUM - 1)
        {
            p2 = p1 + 1;
        }

        // 上に空白がある場合は上へ移動
        if (y > 0 && Panel[p1 - PANEL_Y_NUM] == ALL_PANEL_NUM - 1)
        {
            p2 = p1 - PANEL_Y_NUM;
        }
        // 下に空白がある場合は下へ移動
        if (y < PANEL_Y_NUM - 1 && Panel[p1 + PANEL_Y_NUM] == ALL_PANEL_NUM - 1)
        {
            p2 = p1 + PANEL_Y_NUM;
        }

        if (p2 != -1)
        {
            Panel[p2] = Panel[p1]; // クリックしたパネルを次の場所へ移動
            Panel[p1] = ALL_PANEL_NUM - 1; // クリックしたパネルを空白にする
        }
        NumberText.text = string.Empty;
        for (int i = 0; i < ALL_PANEL_NUM; i++)
        {
            if (Panel[i] < ALL_PANEL_NUM - 1)
            {
                PanelObj[Panel[i]].transform.position = BasePos[i];
                PanelObj[Panel[i]].name = i.ToString();
            }
            else
            {
                Vector2 temp = PanelObj[Panel[i]].transform.position;
                temp.y = 2.0f;
                PanelObj[Panel[i]].transform.position = temp;
                PanelObj[Panel[i]].name = i.ToString();
            }
            NumberText.text += (Panel[i]+1).ToString() + " ";
            if(i%PANEL_X_NUM == PANEL_X_NUM-1)
            {
                NumberText.text += "\n";
            }
        }
    }
    void GameTitle()
    {
        if (Input.GetMouseButtonDown(0))
        {
            for (int i = 0; i < ALL_PANEL_NUM; i++)
            {
                Panel[i] = i;
            }

            for (int i = 0; i < ALL_PANEL_NUM * 1000; i++)
            {
                Change(Random.Range(0, PANEL_X_NUM), Random.Range(0, PANEL_Y_NUM));
            }
            State = EState.MAIN;
            audioSource.Play();
        }
    }
    GameObject clickedGameObject;
    void GameMain()
    {
        PanelXSize = Screen.width / PANEL_X_NUM;
        PanelYSize = Screen.height / PANEL_Y_NUM;
        if (Input.GetMouseButtonDown(0))
        {
            clickedGameObject = null;

            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            RaycastHit2D hit2d = Physics2D.Raycast((Vector2)ray.origin, (Vector2)ray.direction);

            int x = 0, y = 0;
            if (hit2d)
            {
                clickedGameObject = hit2d.transform.gameObject;
                x = int.Parse(clickedGameObject.name)% PANEL_X_NUM;
                y = int.Parse(clickedGameObject.name)/ PANEL_Y_NUM;
            }

            Change(x , y);
            bool clear = true;
            for (int i = 0; i < ALL_PANEL_NUM; i++)
            {
                if (Panel[i] != i)
                    clear = false;
            }
            if (clear)
            {
                for (int i = 0; i < ALL_PANEL_NUM; i++)
                {
                    PanelObj[i].transform.position = BasePos[i];
                }
                State = EState.CLEAR;
            }
        }
    }
    void GameClear()
    {
        NumberText.text = "Game Clear";
    }
    // Update is called once per frame
    void Update()
    {
        switch (State)
        {
            case EState.TITLE: GameTitle(); break;
            case EState.MAIN: GameMain(); break;
            case EState.CLEAR: GameClear(); break;
        }
    }
}

テキストとサウンドをスクリプトにアタッチ

こんな感じで設定できれば完成です!

実行結果