1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

第23回 自己ベストを保存してリザルト画面に表示する

1
Posted at

Unityで無限ランナーを作る:第23回 自己ベストを保存してリザルト画面に表示する

1. はじめに

このゲームでは、どれだけ遠くまで走れたかという「走破距離」がプレイの成果になります。
しかし、現在の実装では、リザルト画面に今回の走破距離を表示するだけで、過去の記録を保存する機能がありません。自己ベストを更新しても、ゲームを終了するとその記録は失われてしまいます。
今回は、走破距離の自己ベストを保存し、リザルト画面に表示する機能を追加します。

実装する内容は、次の二つです。

  • 今回の走破距離が自己ベストを上回った場合に、記録を保存する。
  • リザルト画面に、今回の走破距離と過去の自己ベストを表示する。

実装後のイメージはこのようになります。

レコード機能実装後のリザルト画面

2. GameRecordStoreクラスを追加する

まず、自己ベストの保存と読み込みを担当するGameRecordStoreクラスを追加します。
リザルト画面を管理するResultManagerに保存処理まで書くこともできますが、今回は役割を分けます。ResultManagerは画面の表示を担当し、GameRecordStoreは記録の保存と読み込みを担当する構成です。

2.1. PlayerPrefsについて

記録の保存には、Unityが提供するPlayerPrefsを使用します。
PlayerPrefsは、文字列のキーと値を組み合わせて、整数・小数・文字列をローカルに保存できる機能です。保存した値は、ゲームを再起動した後も読み込めます。
今回は、走破距離の自己ベストという整数値を一つ保存するだけなので、手軽に利用できるPlayerPrefsを採用しました。
一方、セーブデータのバックアップやファイルへの書き出しが必要な場合はファイル保存、異なる端末間でデータを共有したい場合はクラウド保存など、要件に応じて別の方法も検討します。

なお、PlayerPrefsには標準で暗号化や改ざん検出の仕組みがありません。今回は個人の自己ベストを保存する用途なので採用していますが、機密情報の保存や、不正対策が必要なオンラインランキングの記録管理には、そのまま使用することは避けます。

2.2. 保存キーの定義

自己ベストを保存する際のキーを、定数として定義します。

// 自己ベストを保存するためのキー
private const string BestDistanceKey = "BestDistance";

保存時と読み込み時には、同じキーを指定する必要があります。
文字列をそれぞれの処理に直接書くのではなく、共通の定数を使うことで、キーの書き間違いを防ぎます。

2.3. 自己ベストの読み込み

保存済みの自己ベストを読み込むメソッドを追加します。

public static int LoadBestDistance()
{
    return PlayerPrefs.GetInt(BestDistanceKey, 0);
}

PlayerPrefs.GetInt()は、指定したキーに対応する整数を取得します。第2引数には、値が保存されていない場合に返す初期値を指定します。今回は0を指定しているため、初回プレイなど、自己ベストがまだ保存されていない場合は0が返されます。

2.4. 自己ベストの保存

続いて、今回の走破距離が自己ベストを上回った場合だけ、記録を保存するメソッドを追加します。

public static bool SaveBestDistanceIfNeeded(int distance)
{
    int bestDistance = LoadBestDistance();

    if (distance <= bestDistance)
    {
        return false;
    }

    PlayerPrefs.SetInt(BestDistanceKey, distance);
    PlayerPrefs.Save();

    return true;
}

まず、LoadBestDistance()で保存済みの自己ベストを読み込みます。
今回の走破距離が自己ベスト以下であれば、保存せずにfalseを返します。同じ距離だった場合も更新は行いません。自己ベストを上回った場合は、PlayerPrefs.SetInt()で新しい値を設定し、PlayerPrefs.Save()で保存先に書き込みます。設定した値は通常、アプリ終了時に自動で書き込まれますが、強制終了された場合などに備えて、記録を更新したタイミングで明示的に保存します。

戻り値は、記録を更新した場合がtrue、更新しなかった場合がfalseです。今回はこの戻り値を使用しませんが、今後、記録更新時に演出を加える場合などに利用できます。

2.5. GameRecordStoreクラスの全体

クラス全体は、次のようになります。

using UnityEngine;

public static class GameRecordStore
{
    // 自己ベストを保存するためのキー
    private const string BestDistanceKey = "BestDistance";

    public static int LoadBestDistance()
    {
        return PlayerPrefs.GetInt(BestDistanceKey, 0);
    }

    public static bool SaveBestDistanceIfNeeded(int distance)
    {
        int bestDistance = LoadBestDistance();

        if (distance <= bestDistance)
        {
            return false;
        }

        PlayerPrefs.SetInt(BestDistanceKey, distance);
        PlayerPrefs.Save();

        return true;
    }
}

このクラスは、GameObjectにアタッチして動作させるものではありません。MonoBehaviourを継承せず、必要な場所から直接呼び出せるstaticクラスとして定義しています。

3. リザルト画面に自己ベストを表示する

次に、ResultManagerからGameRecordStoreを呼び出し、自己ベストの表示と保存を行います。

3.1. 表示用のテキストを追加する

リザルト画面に、過去の自己ベストを表示するためのTextMeshProのUIテキストを追加します。ResultManagerには、次のフィールドを追加します。

[SerializeField] private TextMeshProUGUI _bestDistanceText;

追加したUIテキストを、Inspectorで_bestDistanceTextに割り当ててください。
今回の走破距離を表示する既存のテキストと合わせて、今回の記録と過去の自己ベストを比較できるように配置します。

3.2. OnEnterメソッドを変更する

リザルト画面に入った際の処理に、自己ベストの読み込み・表示・保存を追加します。

public void OnEnter(object param)
{
    // BGM再生
    _bgmPlayer.Play(BGMType.GameOver, 0.01f);

    // 走破距離を取り出す
    GameResult gameResult = param as GameResult;

    if (gameResult != null)
    {
        Debug.Log(
            $"ResultManager.OnEnter. result:{gameResult.distanceTiles}");

        // 今回の走破距離を表示
        _distanceText.text =
            $"<size=180>{gameResult.distanceTiles}</size><size=96>m</size>";

        // 過去の自己ベストを表示
        int bestDistance = GameRecordStore.LoadBestDistance();

        _bestDistanceText.text =
            $"<size=72>Best </size><size=90>{bestDistance}</size><size=64>m</size>";

        // 自己ベストを上回っていれば保存
        GameRecordStore.SaveBestDistanceIfNeeded(
            gameResult.distanceTiles);
    }

    // UI表示
    SetVisible(true);

    // PlayerCharacterを削除するコルーチン開始
    _despawnAfterDelayCoroutine =
        StartCoroutine(DespawnAfterDelay());
}

既存の処理で取得しているGameResultから、今回の走破距離を取り出します。

その後、次の順に処理します。

  1. 今回の走破距離を表示する。
  2. 保存済みの自己ベストを読み込み、表示する。
  3. 今回の走破距離が自己ベストを上回っていれば保存する。

テキスト内の<size=...>は、文字のサイズを指定するためのタグです。数値と単位、Bestというラベルのサイズをそれぞれ調整しています。

3.3. 表示してから保存する理由

今回の実装では、自己ベストを表示した後に、新しい記録を保存しています。そのため、リザルト画面のBest欄に表示されるのは、今回のプレイを始める前の自己ベストです。
例えば、過去の自己ベストが500mで、今回600m走れた場合、リザルト画面には次のように表示されます。

表示項目 距離
今回の走破距離 600m
Best 500m

保存される自己ベストは600mに更新されますが、すでに表示したBest欄は500mのままです。次回のリザルト画面から、更新後の値が表示されます。これにより、今回の走破距離と、それまでの自己ベストを比較できます。

3.4. 動作確認

実装後は、次の点を確認します。

  • 記録が未保存の場合、Bestが0mと表示される。
  • 自己ベストを上回ると、その距離が保存される。
  • 自己ベスト以下の距離では、保存済みの記録が変わらない。
  • ゲームを終了して再起動しても、保存済みの自己ベストが読み込まれる。

自己ベストを更新した直後の画面には、更新前の値が表示される点に注意してください。更新後の値は、次回のリザルト画面で確認できます。

4. おわりに

今回は、走破距離の自己ベストを保存し、リザルト画面に表示する機能を追加しました。
保存と読み込みはGameRecordStoreにまとめ、ResultManagerから呼び出す構成にしています。これでゲームを終了しても記録が残り、次のプレイで過去の自己ベストと比較できるようになりました。
これで、主要な機能は一通りそろいました。
次回は、WebGL向けにビルドし、itch.ioで公開するまでの手順を取り上げます。

なお、実際に公開済みのゲームはこちらからプレイ可能です。(インストールは不要です)
ご興味のある方は一度プレイしてみてください。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?