【Unity】他のSceneに変数などの情報を渡すカンタンな方法

# まずは Scene について説明

Scene とはゲーム画面というとわかりやすいんでしょうか。よく具体例で言っているのはロールプレイングゲームですね。フィールド歩く「マップ画面」と敵に遭遇したら切り替わる「バトル画面」は、それぞれ違う画面として管理した方が良さそうじゃないですか。そういうときに Scene で「マップ Scene」や「バトル Scene」という形でそれぞれの画面ごとに作ることができます。

# 他の Scene に変数の情報とか渡したい

こう書かれてもピンと来ないかもしれませんので以下のような Scene で構成されているゲームがあるとします。

- タイトル画面
- ゲーム画面
- クリア画面

やりたいことはゲーム画面でプレイした結果をクリア画面に渡したいんです！具体的にいうとゲーム画面でクリアしたかどうかを bool 値で判定して、その bool 値をリザルト画面に渡したい。

# 方法１：public で static な変数を使う

public で static な変数を使えば他のスクリプトへの変数に参照できます。どこからでも変数を呼べるし格納もできるので Scene が違っていても変数に格納できます。以下にサンプルとなるソースを記載します。GamePlaying が実際に遊ぶゲーム画面にアタッチされており、GameResult がゲーム結果画面にアタッチされているモノとしてご確認ください。

▼【保存する場合のスクリプト】▼

```csharp
using UnityEngine;

public class GamePlaying
{
    public static bool isClear = false;
    void Start () {
        //スタートからクリア判定を置く
        //isClear = true;
    }
}
```

▼【読み込みたい場合のスクリプト】▼

```csharp
using UnityEngine;

public class GameResult
{
    void Start () {
        //ゲーム結果画面でGamePlayingの変数を読み込み
        if(GamePlaying.isClear){
            Debug.Log("isClear が true なのでクリアしてる状態です");
        }
    }
}
```

共通で使用したい変数である isClear は、GameResult 側に宣言してもよいです。その場合は GamePlaying 側からは`GameResult.isClear`で参照することができます。

## public で static な変数のリスクも知っておこう

上記のような形で public で static な変数を使用すれば、ほぼどこからでも参照できます。どこからでも参照できるというのは便利ではありますが、それはそれで意図しない場所から参照される場合もあります。特に人と作業される場合は「この変数は参照できるから利用しよう！」と変数に対して意図しない値を格納されたりすることもあるのでご注意ください。
「staticおじさん」という揶揄もあったりして多用しすぎるとよくない可能性もあるにはありますが、リスクなどを把握しながら上手く使い分けて行くことが重要だと思います。とりあえずは個人でやる分には上記の方法を使ってみてもイイかなと思っています悩んで停滞するよりは進めることの方が重要だと思うので。

# 方法２：DontDestroyOnLoad()を使用する
通常、他のSceneに切り替わった（遷移）場合は、遷移前のSceneのオブジェクトは全て破棄されます。`DontDestroyOnLoad()`を使用すれば、使用したSceneについて他のSceneに切り替わった（遷移する）場合でもオブジェクトが破棄されません。オブジェクト自体は残っているのでオブジェクトを検知して変数を参照したりオブジェクトを操作することが可能です。

▼【ゲーム画面にアタッチするスクリプト】▼

```csharp
using UnityEngine;
using UnityEngine.SceneManagement;

public class GamePlaying : MonoBehaviour {

    public string test = "他のSceneで読み込まれるぜ！";

    void Start () {
        DontDestroyOnLoad (this);
    }

    //クリックしたら「GameResult」に遷移
    void Update () {
        if (Input.GetMouseButtonDown (0)) {
            SceneManager.LoadScene ("GameResult");
        }
    }
}
```
▼【結果画面にアタッチするスクリプト】▼

```csharp
using UnityEngine;

public class GameResult : MonoBehaviour {

    void Start () {
        //オブジェクトを名前で探す
        GameObject resultObj = GameObject.Find ("ResultObject");
        //変数「test」を参照しDebug.Logに出力
        Debug.Log (resultObj.GetComponent<GamePlaying> ().test);

        //オブジェクトの位置情報を変更
        resultObj.transform.position = new Vector3 (
            resultObj.transform.position.x,
            resultObj.transform.position.y - 5,
            resultObj.transform.position.z
        );
    }
}
```


▼【ゲーム画面スクリーンショット】▼
![DontDestroyOnLoad()-Playing.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412322/f02ed043-fb77-5cb6-0c4d-c6ed149dcc80.png)

▼【結果画面スクリーンショット】▼
![DontDestroyOnLoad()-Result.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412322/6f8eb8cc-5af9-83ae-9ee9-7c40faab1fa0.png)

結果画面で`test`という変数を参照していますが public な変数です。public を付けないと他からは参照できないのですが static でなくてもオブジェクトを通して参照できます。ちなみにざっくりと static について説明しますが static は静的なモノで最初に領域を確保されるため参照対象となる変数は１つしか存在しません。この説明だけだとわかりにくいですが、今回の場合を例にするとちょっとわかりやすいかも。
今回の場合はオブジェクト`ResultObject`の変数`test`を参照していますが、もし他のオブジェクトなら他のオブジェクトを探して、探し出したオブジェクトの変数`test`を参照できます。つまりオブジェクトの数だけ変数`test`が存在することになります。

▼【試しにstaticの変数を追加してみるが・・・】▼

```csharp
using UnityEngine;
using UnityEngine.SceneManagement;

public class GamePlaying : MonoBehaviour {

    public string test1 = "他のSceneで読み込まれるぜ！";
    static public string test2 = "staticのテストだぜ";

    void Start () {
        DontDestroyOnLoad (this);
    }

    void Update () {
        if (Input.GetMouseButtonDown (0)) {
            SceneManager.LoadScene ("GameResult");　
        }
    }
}
```

▼【GameObjectから参照しても参照できない】▼
![TESTAAAA.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412322/19cb4eac-73a5-2352-86a6-834034c67c7a.png)



# 方法３：永続的に保存する「PlayerPrefs」

プログラムおよびアプリ自体に値を保存してしまえば Scene を跨いでも受け取れるようになります。値を渡す目的だけで使うのは微妙かもしれません。ゲーム画面のスコアなどの記録したいモノであれば使ってもイイかなと。

以下にサンプルのソースを記載します。以下のことを気をつけてご利用いただければ幸いです。

- 保存するときは必ず`PlayerPrefs.Save()`を忘れない
- 保存や読み込みのキーは大文字小文字を区別するので注意

▼【保存する場合のスクリプト】▼

```csharp
using UnityEngine;

public class GamePlaying
{
    void Start () {
        //「SCORE」というキーで、Int値の「20」を保存
        PlayerPrefs.SetInt("SCORE", 20);
        PlayerPrefs.Save();
    }
}
```

▼【読み込みたい場合のスクリプト】▼

```csharp
using UnityEngine;

public class GameResult
{
    void Start () {
        //「SCORE」というキーで保存されているInt値を読み込み
        int resultScore = PlayerPrefs.GetInt("SCORE");
        Debug.Log("保存されている点数：" + resultScore )
    }
}
```