プレイするゲームがないなら、自分で作ればいいじゃない!
ということで 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秒ほど操作が効かなくなりました
これでシーンのロード待ちも出来ているはず…!
さいごに
コルーチン便利!
正しい使い方かは分からないですが(笑)
コメント