さくらの作業ログ

今度は三日坊主にしないといいな

初期設定画面を作った

初期設定の動作イメージ図
動作イメージ

長いんですがコードがこう

public class InitialSceneController : MonoBehaviour
{
    public SaveData saveData;
    public GameObject SelectLanguage;
    public GameObject InputName;
    public GameObject SelectMode;
    public Canvas LoadingOverlay;
    private SaveManager saveManager;
    private string targetSceneName = "FieldScene";

    async void Start(){
        saveManager = new SaveManager(saveData);

        VisibleLanguageSelect(false);
        VisibleInputName(false);
        VisibleModeSelect(false);
        LoadingOverlay.enabled = false;

        await PlayerInitialSettings();

        LoadingOverlay.enabled = true;
        InitialSaveData initialSaveData = new InitialSaveData(saveData);

        await initialSaveData.createAsync(saveData.selectedMode);
        saveManager.Save();

        Complete();
    }

    public void VisibleLanguageSelect(bool visible){
        SelectLanguage.transform.parent.gameObject.GetComponent<Canvas>().enabled = visible;
        SelectLanguage.GetComponent<LocaleSelector>().enabled = visible;
    }

    public void VisibleInputName(bool visible){
        InputName.transform.parent.gameObject.GetComponent<Canvas>().enabled = visible;
        InputName.GetComponent<PlayerNameSettings>().enabled = visible;
    }

    public void VisibleModeSelect(bool visible){
        SelectMode.transform.parent.gameObject.GetComponent<Canvas>().enabled = visible;
        SelectMode.GetComponent<ModeSelector>().enabled = visible;
    }

    public async UniTask PlayerInitialSettings(){
        saveData.selectedLocale = await PlayerLanguageSetting();
        saveData.playerName = await PlayerNameSetting();
        saveData.selectedMode = await PlayerPlayModeSetting();
    }

    private async UniTask<string> PlayerLanguageSetting(){
        VisibleLanguageSelect(true);
        LocaleSelector localeSelector = SelectLanguage.GetComponent<LocaleSelector>();
        string language = await localeSelector.selectAsync();
        VisibleLanguageSelect(false);
        Debug.Log(language);
        return language;
    }

    private async UniTask<string> PlayerNameSetting(){
        VisibleInputName(true);
        PlayerNameSettings playerNameSettings = InputName.GetComponent<PlayerNameSettings>();
        string playerName = await playerNameSettings.DecideNameAsync();
        VisibleInputName(false);
        Debug.Log(playerName);
        return playerName;
    }

    private async UniTask<string> PlayerPlayModeSetting(){
        VisibleModeSelect(true);
        ModeSelector selector = SelectMode.GetComponent<ModeSelector>();
        string selectedMode = await selector.selectAsync();
        VisibleModeSelect(false);
        Debug.Log(selectedMode);
        return selectedMode;
    }

    // すべての設定を終えたら遷移
    void Complete()
    {
        SceneManager.LoadScene(targetSceneName);
    }
}

個別に説明していきます。

設定用のCanvasをすべて非表示にする

       VisibleLanguageSelect(false);
        VisibleInputName(false);
        VisibleModeSelect(false);
   public void VisibleLanguageSelect(bool visible){
        SelectLanguage.transform.parent.gameObject.GetComponent<Canvas>().enabled = visible;
        SelectLanguage.GetComponent<LocaleSelector>().enabled = visible;
    }

最初は Canvas.enabled だけするようになってたんですが、KeyDownイベントが全部のスクリプトで発火したのでスクリプトもdisabledにするようになっています。

設定用のCanvasを順番に表示する

   public async UniTask PlayerInitialSettings(){
        saveData.selectedLocale = await PlayerLanguageSetting();
        saveData.playerName = await PlayerNameSetting();
        saveData.selectedMode = await PlayerPlayModeSetting();
    }

ユーザーの決定を待つためにUniTaskを使ってawaitすることにしました。
呼ばれる側のスクリプトはこうとか

   // ボタンが選択された時に実行
    public async UniTask<string> DecideNameAsync()
    {
        await buttonEvent.OnInvokeAsync();
        return inputName.GetComponent<TMP_InputField>().text;
    }

こうとか

   public async UniTask<string> selectAsync(){

        await UniTask.WhenAny(waitKeyDown(), waitMouseClick());

        Toggle selected = this.gameObject.GetComponent<ToggleGroup>().ActiveToggles().First<Toggle>();
        string value = selected.GetComponent<ButtonWithValue>().value;

        return value;
    }

await UniTask.WhenAny(waitKeyDown(), waitMouseClick()); のところはキー入力かマウスクリックを待機するというコードで、マウスクリックの検知は今まだ無いんですけど、キー入力の方を例に挙げておきます。

   public UniTask waitKeyDown(){
        return UniTask.WaitUntil(() => Input.GetKeyDown(KeyCode.Return));
    }

ラムダ式」という言葉が思い出せなくてしばらく呻いてしまった。Javaラムダ式が導入された時期くらいからJava触らなくなったので記憶が遠かった…
これと似たような感じでマウスクリックの判定も作りたいんだけど、これがどうしてうまくいかない。難しいねー。
イメージとしては「矢印キーで選択してエンターで決定」もしくは「マウスクリックで決定」という感じなんですが、素のままだとマウスクリックも選択なのよね。マウス前提ならボタンの方がいい、キーボード前提ならトグルの方がいい。たぶん。ここを共存させたいんだけどなー。

設定が終わったらセーブデータを作成する

       LoadingOverlay.enabled = true;
        InitialSaveData initialSaveData = new InitialSaveData(saveData);

        await initialSaveData.createAsync(saveData.selectedMode);
        saveManager.Save();

ここもawaitしています。今のところデータが無いので動作はサクッと終わりますが、今後フラグが増えたときにどうなるかはよくわからないため、ローディングオーバーレイ(Web屋の言い方かもしれない、スピナーとかプログレスバーとか表示するアレ)を表示するようになっています。

InitialSaveDataの中身はまだあんまり考えていないのでこうとか(最強モード)

   private async Task<bool> createStrongModeData(){
        // 注意:特に非同期処理をやっていないので黄色エラーが出ているコードです
        Debug.Log("createStrongModeData");
        saveData.selectedMode = "strongmode";
        saveData.attackPower = 999;
        saveData.defensePower = 999;
        return true;
    }

そもそも「最強モード」っていうのが既に超バカっぽい。バカっぽいもの大好きですが

簡単なユーザー登録画面くらいの気持ちで組んでたのにスレッドの概念を完全に忘れてて結構時間かかっちゃった。
でもまあいいリハビリになったかなー。

ソースはここから
github.com

いまだによくわかっていないんだけど、 *.meta ってコミットする必要あるのか?