【Unity】2Dシューティングを作る ~タイトルの改良~

Unityで抽象やコルーチンを使う unity

プレイするゲームがないなら、自分で作ればいいじゃない!

ということで Unity 初心者が「ゲームを作る」ゲームをやっていきます!

今回は「前回のタイトル処理を改良」の記事です

 

スポンサーリンク

内容

「抽象メソッド」「コルーチン」を使って

タイトル画面の処理を改良していきます

 

抽象メソッドで決定の処理を作る

前回の TitleMenu のスクリプトを改良していく

クラスの宣言部分に「abstract」を追加して抽象クラスにする

public abstract class TitleMenu : MonoBehaviour

 

決定処理用の抽象メソッドを追加します

// 決定されたときの動作
public abstract void Select();

これを保存してエディターに戻るとエラーが表示されます

 

抽象クラス

抽象化されたクラスは生成(new)することができない
※おそらくエディターのエラーはこれが原因

生成できなくなるので継承用のクラスになる

抽象メソッド

抽象クラス内で使用できる

この関数は継承先のクラスで必ず実装しなければならない
※実装しないとエラーになる

 

継承するクラスを作る

Start と Option の TitleMenu スクリプトコンポーネントを削除して

新たなC#スクリプトコンポーネントを追加します

 

抽象クラスの「TitleMenu」を継承して

抽象メソッドは「override」を追加して実装します

 

Start
public class StartMenu : TitleMenu
{
    // 決定されたときの動作
    public override void Select()
    {
        StartCoroutine(LoadScene());
    }

    IEnumerator LoadScene()
    {
        AsyncOperation asyncLoad = SceneManager.LoadSceneAsync("SampleScene");

        // ロードがまだなら次のフレームへ
        while (!asyncLoad.isDone)
        {
            yield return null;
        }
    }
}

 

Option
public class OptionMenu : TitleMenu
{
    // 決定されたときの動作
    public override void Select()
    {
    }
}

 

エディター側の再設定

Sprite や MenuTable の設定が消えているので再設定する

 

タイトルのスクリプトを更新

キー入力で Select を呼び出す処理を追加する

TItleMenu の配列ですが、Select は継承先のものを呼び出してくれる

else if (Input.GetButtonDown("CursorDown"))
{
    Cursor++;
}
else if (Input.GetButtonDown("Fire1"))
{
    MenuTable[Cursor].Select();
}

 

実行すると…

Option でキーを押してもゲームメインに遷移せず

Start だとシーンの切り替えが行われました!

 

しかしこのままだと問題がありそうな気がするので

もう少し修正します

 

タイトルスクリプトのUpdateを止めたい

シーンの切り替えが非同期なので、シーンの読み込みに時間がかかると

Start を押して Option をさらに押すという動作が可能になってしまうはず…

 

今は一瞬でロードが完了するので問題ないですが

後々バグになりそうなのでメニュー決定後は

タイトル画面の操作が出来なくなるようにしたい

 

コルーチンで制御してみる

コルーチンの中でさらにコルーチンを呼び出すと

yield return StartCoroutine(コルーチン());

「呼び出したコルーチンが終了するまで処理を中断することができる」

なのでこれを使って Update の制御をしてみました

 

Inputをコルーチンで処理する

Update を消して Start でコルーチンを呼び出すようにする

// Input更新
IEnumerator UpdateInput()
{
    // 開始時はスルー
    yield return null;

    // シーンが切り替わるまで無限ループ
    while (true)
    {
        int oldCursor = Cursor;
        int cursorMax = MenuTable.Length;

        if (Input.GetButtonDown("CursorUp"))
        {
            Cursor--;
        }
        else if (Input.GetButtonDown("CursorDown"))
        {
            Cursor++;
        }
        else if (Input.GetButtonDown("Fire1"))
        {
            yield return StartCoroutine(MenuTable[Cursor].Select());
        }

        // カーソルの制御
        if (Cursor < 0)
        {
            Cursor = MenuTable.Length - 1;
        }
        if (Cursor >= cursorMax)
        {
            Cursor = 0;
        }

        // カーソルに変更があったら
        if (Cursor != oldCursor)
        {
            SetMenu();
        }

        yield return null;
    }
}

 

yield return StartCoroutine(MenuTable[Cursor].Select());

決定後の処理をコルーチンとして呼び出せば

Select が完了するまで UpdateInput が中断される

 

その他のコルーチン対応

TitleMenu
// 決定されたときの動作
public abstract IEnumerator Select();

 

StartMenu
public override IEnumerator Select()
{
    AsyncOperation asyncLoad = SceneManager.LoadSceneAsync("SampleScene");

    // ロードがまだなら次のフレームへ
    while (!asyncLoad.isDone)
    {
        yield return null;
    }
}

 

OptionMenu
public override IEnumerator Select()
{
    // 試しに2秒待つ
    yield return new WaitForSeconds(2.0f);
}

 

実行すると

Option を選択したら2秒ほど操作が効かなくなりました

これでシーンのロード待ちも出来ているはず…!

 

さいごに

コルーチン便利!

正しい使い方かは分からないですが(笑)

 

かれいど

ゲームをしたり、作ったり
色々な事に挑戦していきたい!

サッカー観戦も趣味で
主にJ1リーグを観ています。

かれいどをフォローする
unity
スポンサーリンク
シェアする

コメント