【Unity/2D】スイカゲーム風の落ち物ゲームを作ってみる話 #6 果物を進化させる

記事をご覧いただき、誠にありがとうございます。


投稿主の無能です。

前回は、果物がポインターに追従し、スペースキーを連打しても闇雲に果物が生成されないよう待機時間を実装しました。

今回は果物の進化を実装してみたいと思います。

果物の進化

果物の進化は、二つの同じ果物が接触したら一つ上の果物になります。

機能の実装の前に、ここで今の果物の状態を振り返ってみましょう。

今の果物は、果物の種類までは設定されています。
しかし、果物の種類は特定できていても、今度は個別の識別ができません。

つまり、進化の機能をこのまま実装すると、「接触した果物」と「自身の果物」との両方の進化の処理になっていしまい、さくらんぼからいきなりスイカになって、最後はお互いを破棄して消えてしまう、という状態になってしまいます。

今の果物での状態で進化の機能を実装すると…?

そうならないように、個別の違いを識別する何かを持たせなければなりません。

そこで、果物にはユニーク(重複しない一意)な通し番号を持たせます。

ユニークな通し番号を持たせ、通し番号のどちらかが進化の処理をすることで、前述のような事が防げるようになります。

進化の処理は、通し番号の大きい果物が行うようにします。

そして進化して生成される果物は、接触した果物と自身の果物の中心を結んだ中心に生成されるようにします。

進化した果物を生成する位置

では見当が付いたので、その機能を実装させてみましょう。

スクリプトの編集

ではスクリプトを編集します。

Variables.cs

using UnityEngine;

public class Variables : MonoBehaviour
{
    #region Var-Number
    public const float zero = 0f;                               // floatの0
    public const float half = 2f;                               // floatの2
    #endregion

    #region Var-String
    public const string tag_Fruits = "Fruits";                  // タグ:果物
    #endregion
}

定数のfloatのhalfを追加しています。
Fruisで位置の算出のために使います。

ではFruisを編集します。

Fruits.cs

using UnityEngine;

public class Fruits : MonoBehaviour
{
    #region Var-Fruits
    [Header("果物の種類")]
    [SerializeField] type fruitsType;
    #endregion

    #region Var-Evolution
    [Header("進化する果物")]
    [SerializeField] Fruits evolutionFruits;
    #endregion

    #region Var-Internal
    public static int number = 0;                                           // 果物の基礎の通し番号
    int fruitsNumber = 0;                                                   // 果物の個別の通し番号
    enum type                                                               // 果物の種類
    {
        cherry = 1, strawberry, grape, orange, persimmon, apple,
        pear, peach, pineapple, melon, watermelon
    }
    #endregion

    #region Start
    void Start()
    {
        // 果物に個別の通し番号を付ける
        fruitsNumber = number;
        // 基礎の通し番号を加算
        number++;
    }
    #endregion

    #region OnCollisionEnter2D
    // 果物の接触判定
    void OnCollisionEnter2D(Collision2D collision)
    {
        // 接触オブジェクトのタグが果物ではない場合
        if (!collision.gameObject.CompareTag(Variables.tag_Fruits))
        {
            // 処理を中断
            return;
        }
        // 接触オブジェクトと自身のFruitsを取得
        Fruits _collisionFruits = collision.gameObject.GetComponent<Fruits>(),
               _fruits = GetComponent<Fruits>();
        // 接触した果物と自身の果物の種類が同じ場合
        if (_collisionFruits.fruitsType == _fruits.fruitsType)
        {
            // 接触した果物の通し番号より自身の果物の通し番号が大きい場合
            if (_collisionFruits.fruitsNumber < _fruits.fruitsNumber)
            {
                // 進化する果物を生成
                Evolution(collision);
            }
            // 接触した果物を破棄
            Destroy(collision.gameObject);
            // 自身を破棄
            Destroy(gameObject);
        }
    }
    #endregion

    #region Evolution
    // 果物の進化
    void Evolution(Collision2D collision)
    {
        // 進化する果物がnullの場合
        if (evolutionFruits == null)
        {
            // 処理を中断
            return;
        }
        // 接触した果物と自身の果物の中心を結んだ中心位置を算出
        Vector2 _center = (collision.transform.position + transform.position) / Variables.half;
        // 進化する果物を生成 生成物:進化する果物 位置:算出した中心位置 回転無し
        Instantiate(evolutionFruits, _center, Quaternion.identity);
    }
    #endregion
}

それでは追加したメンバ変数から見ていきましょう。

メンバ変数

追加したメンバ変数は、進化する果物となるFruitsのevolutionFruitsです。

次に果物の基礎の通し番号となるintのnumberと、果物の個別の通し番号となるintのfruitsNumberです。

このnumberをスクリプト全体の共通の変数にするため、public staticが付いています。
この基礎の通し番号を作ることで、果物の個別のfruitsNumberが意味を持ってきます。

では処理を見ていきましょう。

Start関数

新たに追加したStart関数では、果物の個別のfruitsNumberに基礎の通し番号のnumberを代入し、その後インクリメントで基礎の通し番号を加算します。

これでユニークな通し番号になるわけです。

OnCollisionEnter2D関数

OnCollisionEnter2D関数では、接触した果物の通し番号と自身の果物の通し番号を比較して、自身の果物の通し番号の方が大きい場合、果物を進化させるEvolution関数を呼んでいます。

因みに通し番号は、後から生成される果物の方が絶対に大きくなります。

Evolution関数

Evolution関数では、まず設定した進化先の果物がnullの場合は、処理を中断します。
この場合、最終形態となるスイカが当てはまります。

次に接触した果物と自身の果物の位置を足して半分にすることで、進化する果物の生成位置を算出し、ローカル変数の_centerに代入します。

そして進化先の果物を生成します。
位置は算出した_center、回転無しです。

ではスクリプトの編集ができたので、Unityでの作業になります。

Unityでの作業

果物に進化する果物という項目が増えているので、進化する果物を設定します。
自身の果物の一つ次の果物をドラッグして設定します。

最終形態のスイカは進化しないのでNoneのままにしておきます。

01_Cherry

02_Strawberry

03_Grape

04_Orange

05_Persimmon

06_Apple

07_Pear

08_Peach

09_Pineapple

10_Melon

11_Watermelon

では設定が済んだら動作確認をします。

動作確認

今回の確認事項は
  • 同じ果物同士が接触したら、設定した進化先の果物になるか
を確認します。

では確認しましょう。

同じ果物がきた

同じ果物果物が来ましたね。
今回はぶどうなので、接触してみかんに進化すれば想定通りです。

みかんに進化した

想定通りみかんに進化してくれました。

後はスイカを確認したいのですが、流石に二つのスイカを作るのは骨が折れるので、ゲームの再生中にVariantsフォルダのスイカをHierarchyビューにドラッグして、スイカの進化の処理を確認します。

スイカは進化先の果物を設定していないので、スイカ同士が接触したら消えてくれれば問題ありません。

VariantsフォルダのスイカをHierarchyビューにドラッグ
もう一度スイカをドラッグしてスイカが消えるかを確認

スイカが消えた

スイカも想定通りの処理が確認できました。

これで果物の進化の機能を実装できました。

まとめ

今回は
  • 果物の進化の機能を実装した
という事をやりました。

次回は、果物が容器の上部まで積み重なって一定のラインを超えたら、また容器の外に零れ落ちたらゲームオーバーになる処理を作っていこうと思います。

では、また次回!

コメント