2024-09-24 18:00:00

【Unity】スイカ風マージパズルゲームの作り方 その3 ~ くっついて進化・消す処理を作る ~【2024年最新】

Unityを使ってスイカ風のマージパズルゲームを作成する方法を解説します。

前回までの記事はこちらです。

【Unity】スイカ風マージパズルゲームの作り方 その1【2024年最新】 - なぎなぎブログ

【Unity】スイカ風マージパズルゲームの作り方 その2 ~ スポナーを作る ~【2024年最新】 - なぎなぎブログ

今回は、駒(ボール)をくっついたときに進化・消す処理を作っていきます。

目次

くっついた(マージした)ときに駒(ボール)消す処理の作成

駒がくっついたときに進化・消す処理を作成します。

駒がくっついたときに進化する条件は下記の通りです。

  • 同じ種類の駒がぶつかったとき
  • 駒が進化可能なとき

駒がくっついたときに消す条件は下記の通りです。

  • 同じ種類の駒がぶつかったとき
  • 駒が進化できないとき

駒が進化できないときというのは、最大まで進化して次の進化がないときです。

つまり今回の将棋をモチーフにしたゲームの場合は、王将と王将がぶつかったときに消えるということです。

駒のスクリプトの修正

先程の条件で、駒を進化または消す処理をスクリプトに記述していきます。

Assets/Scripts/Koma.cs を修正します。

using UnityEngine;

public class Koma : MonoBehaviour
{
    // 駒の種類
    public int Type { get; set; }

    // マージ済みフラグ
    public bool IsMerge { get; set; }

    // 進化可能かどうか
    public bool CanPromote { get; set; }


    // 衝突したときの処理
    private void OnCollisionEnter2D(Collision2D other)
    {
        // 衝突先が駒でない場合は処理を行わない
        var otherKoma = other.gameObject.GetComponent<Koma>();
        if (!otherKoma)
        {
            return;
        }

        // マージ済みの場合は処理を行わない
        if (IsMerge || otherKoma.IsMerge)
        {
            return;
        }

        // 同じタイプの駒出ない場合は処理を行わない
        if (Type != otherKoma.Type)
        {
            return;
        }


        // 衝突元と衝突先で複数回マージ処理が動かないように、マージ済みフラグを立てる
        IsMerge = true;
        otherKoma.IsMerge = true;
        // 2つの駒の中間地点を取得
        var position = Vector2.Lerp(transform.position, other.transform.position, 0.5f);
        // 進化先があれば新しい駒を生成
        if (CanPromote)
        {
            // 2つの駒の中間地点に新しい駒を生成
            KomaFactory.Instance.CreateKoma(position, Type + 1);
        }

        // 衝突した駒を削除
        Destroy(gameObject);
        Destroy(other.gameObject);
    }
}

ソースコードにコメントを書いているので、処理の流れはわかると思います。

1点分かりづらそうな部分の補足として、Vector2.Lerp というメソッドを使って、2つのオブジェクトの中間地点を取得しています。

public static Vector2 Lerp(Vector2 a, Vector2 b, float t); と宣言されていて、 Vector2.Lerpは、ベクトルaとベクトルbの間のtで線形に補間します。

tが0のときはa、tが1のときはb、tが0.5のときはaとbの中間地点を返します。

今回は中点を取得するため、tを0.5にしています。

スクリプトを修正後はの動作は次のような動画のようになります。

まとめ

今回は、駒がくっついたときに進化・消す処理を作成しました。

ゲームのコア部分の動きとしてはほとんど完成しているように思いますね。

次回は、スコアの保持や、ゲームオーバーの処理を作成してきます。

2024-09-16 18:00:00

【Unity】スイカ風マージパズルゲームの作り方 その2 ~ スポナーを作る ~【2024年最新】

Unityを使ってスイカ風のマージパズルゲームを作成する方法を解説します。

前回の記事はこちらです。

【Unity】スイカ風マージパズルゲームの作り方 その1【2024年最新】 - なぎなぎブログ

前回は容器と駒(ボール)を作成しました。

今回は、駒を生成するスポナーの作成を行います。

目次

スポナーの作成

スポナーは、駒を生成するためのオブジェクトです。

スポナーも駒と同じように画像をインポートして、ゲームオブジェクトを作成します。

スポナー画像のインポート

まずは、スポナーの画像をインポートします。

Spritesフォルダに画像を入れて、Pixels Per Unitを設定します。

今回画像は 512x512 で作成していたので、Pixels Per Unitは 512 に設定します。

スポナーのゲームオブジェクト作成

次に、スポナーのゲームオブジェクトを作成します。

Spritesフォルダにあるスポナー画像をHierarchyにドラッグ&ドロップして、ゲームオブジェクトを作成します。

Spawnerは下記の設定しておきます

  • Spawner
    • 名前を Spawner に変更
    • Position を (0, 4.2, 0) に設定
    • Scale を (2, 2, 1) に設定

スポナーのスクリプト作成

スクリプトファイルの作成

いよいよスクリプトを書いていくので、まずスクリプトを保管するためのフォルダを作成します。

Assets > Create > Folder を選択し、名前を Scripts として作成します。

作成したスクリプトフォルダにスポナーのスクリプトを作成します。

Hierarchy にある Spawner を選択し、Inspector にある Add Component を選択し、New Script を選択し「Spawner」という名前でスクリプトを作成します。

作成したスクリプトは Scripts フォルダに移動させておいてください。

作成すると次の図のような状態になります。

スポナーを動かすスクリプトの記述

スポナースクリプトを記述します。

using UnityEngine;

public class Spawner : MonoBehaviour
{
    // スポナーのY位置
    private const float SpawnerImagePositionY = 4.2f;
    
    // Start is called once before the first execution of Update after the MonoBehaviour is created
    void Start()
    {
        
    }
    
    // Update is called once per frame
    void Update()
    {
        UpdateSpawnerPosition();
    }
    
    private void UpdateSpawnerPosition()
    {
         
        // マウスの座標を取得
        var mousePosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);
        var newPosition = new Vector2(mousePosition.x, SpawnerImagePositionY);
        // x の範囲がボックスのサイズ内にあるかどうか
        if (newPosition.x < -2.5f)
        {
            newPosition.x = -2.5f;
        }
        else if (newPosition.x > 2.5f)
        {
            newPosition.x = 2.5f;
        }
        transform.position = newPosition;
    }
}

クリックして駒を生成する

駒を生成するために、スポナーをクリックした時に駒を生成するようにします。

まずは駒を生成するためのスクリプトを作成します。

駒生成のスクリプトをアタッチするオブジェクトの作成

駒のスクリプトをアタッチするオブジェクトを作成します。

Hierarchy を右クリックし、Create Empty を選択し、名前を KomaFactoryObject に変更します。

Inspector の Add Component から New Script を選択し、名前を KomaFactory にしてスクリプトを作成します。

作成したスクリプトは Scripts フォルダに移動させておいてください。

![駒のスクリプトをアタッチするオブジェクト]/imgs/how-to-create-unity-merge-puzzle-2-4.png)

駒のスクリプトの作成

駒のスクリプトを作成します。

Inspectorからスクリプトを作成していましたが、今回は先にスクリプトを作ってからアタッチします。

Scriptsフォルダで右クリックをし、Create > MonoBehaviour Script を選択し、名前を Koma にしてスクリプトを作成します。

ProjectウィンドウからPrefabsフォルダを開き、駒のプレファブを一括選択して、Inspectorから Add Component を選択し、Komaスクリプトをアタッチします。

駒のスクリプトの記述

駒がぶつかったときの処理などは、後で追加していきます。 一旦今は、駒の情報を持たせるためのプロパティだけを追加しておきます。

Assets/Scripts/Koma.cs に下記のように記述します。

using UnityEngine;

public class Koma : MonoBehaviour
{
    
    // 駒の種類
    public int Type { get; set; }
    
    // マージ済みフラグ
    public bool IsMerge { get; set; }
    
    // 進化可能かどうか
    public bool CanPromote { get; set; }
    

}

駒のスクリプトには、下記の情報を持たせるためのプロパティを追加しています。

  • 駒の種類
  • マージ済みフラグ
  • 進化可能かどうか

駒生成スクリプトの記述

Assets/Scripts/KomaFactory.cs に下記のように記述します。

using System;
using UnityEngine;

public class KomaFactory : MonoBehaviour
{
    
    // シーン内でシングルトンにする
    public static KomaFactory Instance { get; private set; }
    
    // 駒のPrefabのリスト
    [SerializeField] private Koma[] komaPrefabList;

    private void Awake()
    {
        if (Instance == null)
        {
            Instance = this;
        }
        else
        {
            Destroy(gameObject);
        }
    }
    
    // 駒を生成する
    public Koma CreateKoma(Vector2 position, int komaType)
    {
        if (komaType < 0 || komaType >= komaPrefabList.Length)
        {
            throw new ArgumentOutOfRangeException(nameof(komaType), komaType, "komaType is out of range");
        }
        
        // 駒を生成
        var koma = Instantiate(komaPrefabList[komaType]);
        koma.transform.position = position;
        // 角度をランダムにする
        koma.transform.rotation = Quaternion.Euler(0, 0, UnityEngine.Random.Range(0, 360));
        // 駒の種類を設定
        koma.Type = komaType;
        // 進化可能かどうかを設定
        koma.CanPromote = komaType + 1 < komaPrefabList.Length;
        
        return koma;
    }
    
    // ランダムな位置に駒を生成する
    public Koma CreateRandomKoma(Vector2 position, int maxKomaType)
    {
        var komaType = UnityEngine.Random.Range(0, maxKomaType);
        return CreateKoma(position, komaType);
    }

}

KomaFactoryクラスは、シーン内でシングルトンになるようにしています。

CreateKomaメソッドは、引数で渡された位置に、指定された種類の駒を生成します。

CreateRandomKomaメソッドは、引数で渡された位置に、ランダムな種類の駒を生成します。

これで、例えば別のスクリプトから、 KomaFactory.Instance.CreateRandomKoma(new Vector2(0,0), 3); のように記述することで、任意の位置に駒を生成することができます。

駒はPrefabを使って生成するので、komaPrefabListに生成対象となるPrefabを設定しておきます。

Inspectorから、KomaFactoryObjectを選択し、Inspectorにある Koma Factory (Script) の Koma Prefab List に、駒のPrefabを設定します。

スポナーでクリックした時に駒を生成するように修正

クリックした時に駒落とすようにスクリプトを修正します

Assets/Scripts/Spawner.cs に下記のように記述します。

using System.Collections;
using UnityEngine;

public class Spawner : MonoBehaviour
{
    // スポナーのY位置
    private const float SpawnerImagePositionY = 4.2f;
    
    // 現在持っている駒のY位置
    private const float CurrentKomaPositionY = 3.6f;
    
    // スポナーが現在持っている駒
    private Koma _currentKoma;
    
    void Start()
    {
        // 起動時に最初に持っている駒を生成
        var koma = KomaFactory.Instance.CreateRandomKoma(new Vector2(transform.position.x, CurrentKomaPositionY), 4);
        // 現在持っている駒に設定
        _currentKoma = koma;
        // 重力を0に設定
        _currentKoma.GetComponent<Rigidbody2D>().gravityScale = 0;
    }
    
    void Update()
    {
        UpdateSpawnerPosition();
        
        if (Input.GetMouseButtonDown(0) && _currentKoma)
        {
            // 現在持っている駒を落とす
            DropKoma();
            
            // 次落とす駒を生成
            StartCoroutine(GenerateNextKoma(4));
        }
    }
    
    private void UpdateSpawnerPosition()
    {
         
        // マウスの座標を取得
        var mousePosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);
        var newPosition = new Vector2(mousePosition.x, SpawnerImagePositionY);
        // x の範囲がボックスのサイズ内にあるかどうか
        if (newPosition.x < -2.5f)
        {
            newPosition.x = -2.5f;
        }
        else if (newPosition.x > 2.5f)
        {
            newPosition.x = 2.5f;
        }
        // スポナーの位置を更新
        transform.position = newPosition;
        // スポナーが持っている駒の位置を更新
        if (_currentKoma)
        {
            _currentKoma.transform.position = new Vector2(newPosition.x, CurrentKomaPositionY);
        }
    }
    
    
    private void DropKoma()
    {
        if (!_currentKoma) return;
        // 重力を元に戻して落とす
        _currentKoma.GetComponent<Rigidbody2D>().gravityScale = 1;
        // 落とすとスポナーは駒を持たない状態になるので、スポナーが持っている駒をnullに設定
        _currentKoma = null;
    }
    
    private IEnumerator GenerateNextKoma(int maxKomaType)
    {
        // 1秒待つ
        yield return new WaitForSeconds(1.0f);
        // 駒を生成
        var koma = KomaFactory.Instance.CreateRandomKoma(new Vector2(transform.position.x, CurrentKomaPositionY), maxKomaType);
        // 重力を0に設定
        koma.GetComponent<Rigidbody2D>().gravityScale = 0;
        // 現在スポナーが持っている駒に設定
        _currentKoma = koma;
        
    }
}

ここまでのスクリプトを記述することで、クリックすると駒が落ちるようになります。

レイヤー位置の設定

うまい感じに動いていますが、スポナーと駒が重なっているときに、駒が手前に表示されるようにレイヤー位置を設定します。

下記のようにそれぞれのオブジェクトのレイヤー位置を設定します。

  • Box->Field
    • Order in Layer: -50
  • Spawner
    • Order in Layer: -20
  • Prefabs->各駒
    • Order in Layer: -10

これできれいに表示されるようになりました。

まとめ

今回は、スポナーを作成し、クリックした時に駒を生成するようにしました。

次回は、駒がぶつかった時の処理を追加していきます。

2024-09-15 18:00:00

【Unity】スイカ風マージパズルゲームの作り方 その1【2024年最新】

Unityを使ってスイカ風のマージパズルゲームを作成する方法を解説します。

今回はUI ToolkitというUnityの中でも最新のUIフレームワークを使ってUIを作成します。 まだ開発途上のため古いバージョンでは使えない機能なども多いため、今回は最新のUnity 6(旧Unity2023)を使っていきます。

目次

例えば 歩と歩をくっつけると、香車になります。

王将と王将をくっつけると、消えます。

ゲームオーバーになる条件は、容器に入れた駒が上まで溜まり、スポナーが持っている駒と接触するとゲームオーバーとなります。

駒をくっつけていくと、スコアがたまるので、ハイスコアを目指して遊びます。

必要なソフトウェア・環境

  • Unity 6(Unity2023) (v: 6000.0.13f1)

プロジェクト作成

まずはUnity Hubを起動し、新規プロジェクトを作成します。

項目
Editor Version6000.0.13f1
プロジェクト名MergePuzzleGame
テンプレートUniversal 2D

プロジェクトのテンプレートは「Universal 2D」を選択します。

プロジェクト名は「MergePuzzleGame」、プロジェクトの場所は任意の場所に作成してください。

Gameウィンドウの設定

次にGameウィンドウの設定を行います。

  • Gameウィンドウ > Aspect > Full HD (1920x1080)

と設定します

シーンの編集、ゲームオブジェクトの作成

シーン名を「GameSceneに変更し、シーンを保存します。

容器の作成

容器のゲームオブジェクト作成

まずは、駒を入れる容器を作成します。

CreateEmptyを選択し、名前を「Boxとして作成します。

  • Box
    • Position: (0, -1, 0)
    • Scale: (1, 1, 1)

Boxオブジェクトの下に下記の4つのオブジェクトを作成します。

  • Field
    • 2D Object > Sprite > Square
    • 名前を「Field」として作成します。
    • Position: (0, 0, 0)
    • Scale: (6, 7, 1)
    • Color: RGBA(255, 255, 255, 160)
  • LeftWall
    • 2D Object > Sprite > Square
    • 名前を「LeftWall」として作成します。
    • Position: (-3, 0, 0)
    • Scale: (0.3, 7, 1)
    • Color: RGBA(255, 160, 255, 255)
  • RightWall
    • 2D Object > Sprite > Square
    • 名前を「RightWall」として作成します。
    • Position: (3, 0, 0)
    • Scale: (0.3, 7, 1)
    • Color: RGBA(255, 160, 255, 255)
  • BottomWall
    • 2D Object > Sprite > Square
    • 名前を「BottomWall」として作成します。
    • Position: (0, -3.5, 0)
    • Scale: (6.3, 0.3, 1)
    • Color: RGBA(255, 160, 255, 255)

作成が完了すると画像のようになります。

容器にRigidbody2Dの追加

Box配下のWallオブジェクトにRigidbody2Dを追加します。

Hierarchyから「LeftWall」、「RightWall」、「BottomWall」を選択し、Add Component > Rigidbody2Dを選択します。

Rigidbody2Dを追加すると、物理演算の影響を受けるようになります。

これによって、この後作る上から落とす駒(ボール)を落としたときに、容器の壁で跳ね返るようになります。

ただデフォルトではRigidbody2Dを追加すると重力の影響を受けて、下に落ちてしまうので、それを防ぐために以下の設定を行います。

Rigidbody2Dの設定から Constraints > Freeze Position X, Y にそれぞれチェックを入れます。 同様に Constraints > Freeze Rotation Z にもチェックを入れます。

容器にBoxCollider2Dの追加

Box配下のWallオブジェクトにBoxCollider2Dを追加します。

Hierarchyから「LeftWall」、「RightWall」、「BottomWall」を選択し、Add Component > BoxCollider2Dを選択します。

これで容器が作成できました。

駒の作成(ボールの作成)

次に落としたり、容器に溜まっていく実際のパズルの要素である駒(ボール)を作成します。

画像のインポート

まずは画像を用意します。

今回は将棋の駒を使うので、将棋の駒の画像を用意します。

ここでは駒の画像を使いますが、ボールの画像など任意の画像を複数用意してください。

注意点としては画像のサイズはすべて同じにしてください。調整が大変になります。

種類によって大きさを変更する必要はあるのですが、これらの設定はUnity上で行います。

駒画像を管理するためにフォルダを作成します。

Assets > Create > Folderを選択し、名前を「Sprites」として作成します。

作成したSpritesフォルダに駒(ボール)の画像をドラッグ&ドロップします。

Pixels Per Unitの設定

画像のサイズによってPixels Per Unitを設定します。

Pixels Per Unitは画像のピクセル数を1ユニットとして扱う設定です。

今回の画像は93x103なので、縦のピクセル数に合わせて103に設定しました。

本来は正方形の画像を使うのが良いですが、今回は縦長の画像を使っているため、縦のピクセル数に合わせて設定しました。

もし 200x200の画像を使う場合は、200に設定することになります。

駒(ボール)のゲームオブジェクト作成

次に駒(ボール)のゲームオブジェクトを作成します。

Spritesフォルダにインポートした画像をHierarchyにドラッグ&ドロップします。

まずは一番小さい駒である「歩兵」をゲームオブジェクトを作成します

駒(ボール)のゲームオブジェクトが作成されます。

下記のように一旦初期位置に設定します。

  • 駒(ボール)
    • Position: (0, 0, 0)
    • Scale: (1, 1, 1)

駒にRigidbody2Dの追加

駒(ボール)にRigidbody2Dを追加します。

Rigidbody2Dを追加することで、駒(ボール)が物理演算の影響を受けるようになります。

これによって、駒(ボール)が重力によって落ち、容器の壁で止まるようになります。

駒にPolygonCollider2Dの追加

駒(ボール)にPolygonCollider2Dを追加します。

PolygonCollider2Dを追加することで、駒(ボール)が物理演算の影響を受けるようになります。

今回は題材を将棋の駒にしたので、PolygonCollider2Dを使って駒の形に合わせて当たり判定を設定します。

もし、円形の画像を使う場合はCircleCollider2Dで設定することもできます。

PolygonCollider2Dの設定

基本的に追加したPolygonCollider2Dは画像の形に合わせて自動で設定されますが、必要に応じて編集することもできます。

Sceneパネルを開き、InspectorからEdit Colliderを選択すると、駒の形に合わせて当たり判定を設定することができます。

問題なければそのままで大丈夫です。 もし、自動での設定ではうまくいかない場合は、手動で設定してください。

駒の動作確認

ここまでで駒(ボール)の作成が完了しました。

再生ボタンを押して、駒(ボール)が重力によって落ちることを確認します。

駒のPrefab化

駒(ボール)をPrefab化して、後で使いやすくします。

Prefabにすると、同じオブジェクトを簡単に複製することができます。 例えば、同じ駒を複数作成する場合などに便利です。

また、Prefabの元データを編集すると、Prefabを使って生成したオブジェクトも一緒に変更されるので、一括で変更することができます。

後で作りますが、スポナーが駒を生成するので、その際はPrefabを使って生成します。

基本的に再利用するオブジェクトや、何度もスクリプトから生成するオブジェクトはPrefab化しておくと便利です。

Prefabsフォルダの作成

Prefabsフォルダをまず作成します。

Projectパネルから Assets フォルダを右クリックし、Create > Folderを選択し、名前を「Prefabs」として作成します。

Prefab化

作成したPrefabsフォルダに駒のゲームオブジェクトをドラッグ&ドロップしてPrefab化します。

Prefab化が完了すると、Prefabsフォルダに駒のPrefabが作成されます。 また、Hierarchy上の駒のゲームオブジェクトも水色になります。Prefabになっていることがわかります。

Prefab化が完了したら、Hierarchy上の駒のゲームオブジェクト不要なので削除しておきます。

他の駒の作成

同じように他の駒も作成します。

基本的には「駒の作成(ボールの作成)で行った手順と同じです。

1点だけ異なる部分としては、駒がマージされて次の駒になると大きな駒に進化する事を考えているので、 Scaleだけ変更します。

例えば、歩兵の次の駒である香車は、Scaleを(1.2, 1.2, 1)に変更します。

同様に、次の駒である桂馬は、Scaleを(1.4, 1.4, 1)に変更します。 のような形で、 駒がマージされるたびに大きくなるように設定します。

今回は 0.2 ずつ大きくなるように設定しましたが、任意の値に変更してください。

すべて完成すると、下記のようになります。

まとめ

今回はUnityでスイカ風のマージパズルゲームの容器と駒(ボール)を作成しました。

次回からは、駒(ボール)を生成するスポナーの作成を行います。

そして、スクリプトを利用してゲームのコアとなる部分を作成していきます。

次回もお楽しみに!