【Unity(C#)】PlayerPrefsを使用したステージ解放の実装

##ステージ解放の実装
unity1weekに参加しました。今回のテーマは「密」です。
磁石の力で壁に密着したり、逆に反発の力で飛んだり、、、という
引っ張りアクションゲームです。
<img width="300" alt="MMTitleSSFix.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244071/473743d5-fd19-5041-bcbd-06747ff68274.png">



【投稿した作品】：[MAGNET MONSTER](https://unityroom.com/games/kento_magnet)

そのゲームの中で
**あるステージをクリアすると遊べるようになるステージが出現する実装**
に試みました。

次遊ぶとき(ブラウザを閉じて再度読み込んだとき)にも
前回のクリアデータは保持されるという前提もクリアしたかったです。

##PlayerPrefs
今回は**PlayerPrefs**を使った実装を行いました。
理由としては、**手軽さ**、ただそれだけです。

多くのデータを保存したり、
改変、閲覧されて困る情報を保存するのには向いていないそうですが、
今回はあまり関係が無いのでセーフです。

##実装の詳細
ステージをクリアするまでは
Easyモード以外は？？？という項目となっており、
選択しても遊べません。
<img width="318" alt="MMMenuReset.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244071/19409d24-b7a5-d652-d08b-572d6967ea8f.png">

クリア後の画像が下記画像です。
Easyモード以外の項目の文字が？？？から変更されており、
選択して遊ぶことができます。

<img width="317" alt="MMMenu.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244071/5f234d91-c3b5-3192-ec56-3a8cc48a1f1e.png">


##コード

**情報を保存する側(SetIntする側)**と
**保存された情報を取り出す側(GetInt)**が必要です。

###PlayerPrefs.SetInt

まずは**情報を保存する側(SetIntする側)**を見ていきます。

```C#:SetIntする側　プレイヤーにアタッチ
private void OnCollisionEnter(Collision other)
{
    if (other.gameObject.layer == LayerMask.NameToLayer("Goal"))
    {
        //どのシーンをクリアしたかでSetIntする数字を変更
        if (SceneManager.GetActiveScene().name == "EasyScene")
        {
            PlayerPrefs.SetInt ("LEVEL", 1);
        }   
        else if (SceneManager.GetActiveScene().name == "NormalScene")
        {
            PlayerPrefs.SetInt ("LEVEL", 2);
        }
        else if (SceneManager.GetActiveScene().name == "HardScene")
        {
            IsClearHardThisTime = true;
            PlayerPrefs.SetInt ("LEVEL", 3);
        }
        
        //念のためセーブしとく　クラッシュすることあるらしい
        PlayerPrefs.Save();
    }
}
```
下記画像のようにプレイヤーがゴールに衝突した瞬間に
今開いているシーンを参照してセットする値を決めています。

<img width="300" alt="EXPrefs.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244071/3adfc426-340a-6f2f-8ec9-ab938f10caf4.png">


###PlayerPrefs.GetInt

**保存された情報を取り出す側(GetInt)**です。

```C#:GetIntする側
using UnityEngine;
using UnityEngine.UI;    
    
public class TitleSceneManager : MonoBehaviour
{
    [SerializeField] private Image _normalImage;
    [SerializeField] private Image _hardImage;
    [SerializeField] private Image _rankingImage;

    [SerializeField] private Sprite _normalSprite;
    [SerializeField] private Sprite _hardSprite;
    [SerializeField] private Sprite _rankingSprite;
    
    private void Start()
    { 
        int clearLevel = PlayerPrefs.GetInt("LEVEL",0);

        //レベルに応じてUI画像入れ替え
        switch (clearLevel)
        {
            case 1:
                _normalImage.sprite = _normalSprite;
                break;
            case 2:
                _normalImage.sprite = _normalSprite;
                _hardImage.sprite = _hardSprite;
                break;
            case 3:
                _normalImage.sprite = _normalSprite;
                _hardImage.sprite = _hardSprite;
                _rankingImage.sprite = _rankingSprite;
                break;
        }
    }
}
```

タイトルシーンの読み込み時に
保存されたステージクリアの情報を取得して、
画像の差し替えを行っています。

あとはステージ選択ボタンを押したら、、、という処理に
if文でReturn処理を書くなどすればボタンの選択も制限できます。

##PlayerPrefs.Save
このSaveのタイミング、どうやらタイミング次第では
たまにデータが吹き飛ぶことがあるそうなので
SetIntするたびに`PlayerPrefs.Save();`を
呼び出しておいた方がよさそうです

【参考リンク】：[Playerprefsを確実に保存する](http://tsubakit1.hateblo.jp/entry/20121015/1350311333)リンク


##デバッグ時のリセット

```C#
#if UNITY_EDITOR

using UnityEngine;
using UnityEditor;

/// <summary>
/// PlayerPrefsを初期化するクラス
/// </summary>
public static class PrefsClear
{
    [MenuItem("Tools/Reset PlayerPrefs")]
    public static void ResetPlayerPrefs()
    {
        PlayerPrefs.DeleteAll();
        PlayerPrefs.Save();
        Debug.Log("Reset PlayerPrefs");
    }
}
#endif
```

下記参考リンクから頂戴しました。

【参考リンク】：[PlayerPrefsをリセットするメニューを追加する【Unity】【エディタ拡張】](https://kan-kikuchi.hatenablog.com/entry/PlayerPrefsResetter)

クリアしたデータはEditor上での実行時にも保存されるので
削除する機能があるとデバッグがはかどります。

##最後に
私はこういう実装でやってますというのがあれば教えてください。
初めての試みなので、なんか動いたからヨシ！って感じです。