FarmRPG　Unity Scene Management Part3 Playerが別のSceneに移動できるよう実装

# 概要
今回はPlayerオブジェクトが別シーンに移動できるように実装します。
以下実装後の様子です。

![0614.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710623/1dbd334b-4705-c6cf-3b24-e06bdaee5b26.gif)



# 開発環境

IDE:Rider
Unity:2020.3.42(LTS)
OS:Windows10

# UnityEditor上の設定
## シーン移動地点のプレハブを作成
BoxCollider2D　SceneTeleportスクリプトをアタッチして移動地点のプレハブを作成します
移動地点に配置します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710623/bf71af27-b7e6-41cf-7bdb-ff761a1f2368.png)


## ↑で作ったプレハブを使って各シーンの移動地点を作成

### Farm

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710623/bf71af27-b7e6-41cf-7bdb-ff761a1f2368.png)

### Field

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710623/93bef378-26d2-5189-790d-291e742daea3.png)



# 実装のポイント

SceneTeleportクラスにOnTriggerEnter2Dメソッドを追加
Playerが接触した時にシーンを移動する処理をを実行します。

SceneControllerManagerクラス
シーンの読み込み終了後にSwitchBoudingShapeを実行します。SwitchBoudingShapeはカメラの位置をプレイヤーに合わせるメソッドです。

SceneControllerManagerクラス
bool型の変数isFadeを加えます。isFadeを加えることでシーンの多重読み込みを防ぎます。
移動先のシーンと座標を引数にするFadeAndSwitchScenesメソッドを追加します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710623/9abc9095-fd75-ce4a-a8c4-ba01697e8f53.png)

# コード部分

## SceneControllerManager

```diff_c_sharp:SceneControllerManager.cs

using UnityEngine;
using UnityEngine.UI;
using System.Collections;
using UnityEngine.SceneManagement;

public class SceneControllerManager :SingletonMonobehaviour<SceneControllerManager>
{
+    private bool isFading;
    [SerializeField] private float fadeDuration = 1f;
    [SerializeField] private CanvasGroup faderCanvasGroup;
    [SerializeField] private Image faderImage;
    public SceneName startingSceneName;
    
    private IEnumerator Start()
    {
        faderImage.color = new Color(0f, 0f, 0f, 1f);
        faderCanvasGroup.alpha = 1f;

        yield return StartCoroutine(LoadSceneAndSetActive(startingSceneName.ToString()));
+        EventHandler.CallAfterSceneLoadEvent();       
        StartCoroutine(Fade(0f));
    }

    private IEnumerator Fade(float finalAlpha)
    {
+        isFading = true;
        faderCanvasGroup.blocksRaycasts = true;

        float fadeSpeed = Mathf.Abs(faderCanvasGroup.alpha - finalAlpha) / fadeDuration;

        while (!Mathf.Approximately(faderCanvasGroup.alpha, finalAlpha))
        {
            faderCanvasGroup.alpha = Mathf.MoveTowards(faderCanvasGroup.alpha, finalAlpha, fadeSpeed * Time.deltaTime);
            yield return null;    
        }

+        isFading = false;
        faderCanvasGroup.blocksRaycasts = false;
    }
    
    
    private IEnumerator LoadSceneAndSetActive(string sceneName)
    {
        yield return SceneManager.LoadSceneAsync(sceneName,LoadSceneMode.Additive);

        Scene newlyLoadedScene = SceneManager.GetSceneAt(SceneManager.sceneCount - 1);
        SceneManager.SetActiveScene(newlyLoadedScene);
    }

+    private IEnumerator FadeAndSwitchScenes(string sceneName, Vector3 spawnPosition)
+    {
+        yield return StartCoroutine(Fade(1f));
+
+        Player.Instance.gameObject.transform.position = spawnPosition;
+        yield return SceneManager.UnloadSceneAsync(SceneManager.GetActiveScene().buildIndex);
+
+        yield return StartCoroutine(LoadSceneAndSetActive(sceneName));        
+        EventHandler.CallAfterSceneLoadEvent();       
+        yield return StartCoroutine(Fade(0f));     
+    }

+    public void FadeAndLoadScene(string sceneName, Vector3 spawnPosition)
+    {
+        if (!isFading)
+        {
+            StartCoroutine(FadeAndSwitchScenes(sceneName, spawnPosition));
+        }
+    }   
}


```


## SceneTeleport

```diff_c_sharp:SceneTeleport.cs
using System;
using UnityEngine;


[RequireComponent(typeof(BoxCollider2D))]
public class SceneTeleport : MonoBehaviour
{
    [SerializeField] private SceneName sceneNameGoto = SceneName.Scene1_Farm;
    [SerializeField] private Vector3 scenePositionGoto = new Vector3();


    private void OnTriggerEnter2D(Collider2D collision)
    {
        Player player = collision.GetComponent<Player>();
        if (player != null)
        {
            float xPosition = Mathf.Approximately(scenePositionGoto.x, 0f) ? player.transform.position.x : scenePositionGoto.x;
            float yPosition = Mathf.Approximately(scenePositionGoto.y, 0f) ? player.transform.position.y : scenePositionGoto.y;

            float zPosition = 0f;

            SceneControllerManager.Instance.FadeAndLoadScene(sceneNameGoto.ToString(),
                new Vector3(xPosition, yPosition, zPosition));
            
        }
    }
    
    
}


```

## SwitchConfineBoundingShape

```diff_c_sharp:SwitchConfineBoundingShape.cs
using UnityEngine;
using Cinemachine;

public class SwitchConfineBoundingShape : MonoBehaviour
{

+    private void OnEnable()
+    {
+        EventHandler.AfterSceneLoadEvent += SwitchBoundingShape;
+    }

+    private void Disable()
+    {
+        EventHandler.AfterSceneLoadEvent -= SwitchBoundingShape;
+    }
    
    private void SwitchBoundingShape()
    {
        PolygonCollider2D polygonCollider2D = GameObject.FindGameObjectWithTag(Tags.BoundsConfiner).GetComponent<PolygonCollider2D>();
        
        CinemachineConfiner cinemachineConfiner = GetComponent<CinemachineConfiner>();
        cinemachineConfiner.m_BoundingShape2D = polygonCollider2D;
        
        cinemachineConfiner.InvalidatePathCache();
           
    }
    
}


```


## EventHandler

```diff_c_sharp:EventHandler.cs
using System;
using System.Collections.Generic;

public static class EventHandler
{
    
    public static event Action AfterSceneLoadEvent;

    public static void CallAfterSceneLoadEvent()
    {
        if (AfterSceneLoadEvent != null)
        {
            AfterSceneLoadEvent();
        }
    } 
}

```

## Enums

```diff_c_sharp:Enums.cs
public enum SceneName
{
    Scene1_Farm,
+    Scene2_Field,
}

```





# 参考

## C#
### 三項間演算子
https://learn.microsoft.com/ja-jp/dotnet/csharp/language-reference/operators/conditional-operator

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710623/b4865905-54b6-cea3-40ca-0b6dbce8fcd1.png)


## Unity Editor コンポーネント

## Unity スクリプト
### SceneManager.UnloadSceneAsync

https://docs.unity3d.com/jp/2018.4/ScriptReference/SceneManagement.SceneManager.UnloadSceneAsync.html

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710623/e3871a1d-5f94-80b5-357c-723229ab3ff4.png)


### RequireComponent

https://docs.unity3d.com/ja/2020.3/ScriptReference/RequireComponent.html

## その他

Section9 38 Move Between Scenes

https://www.udemy.com/course/unity-2d-game-developer-course-farming-rpg/learn/lecture/19896566#content

github コミット分（個人確認用　privateなので見れません）

https://github.com/RYA234/LearnFarmRPG/commit/7e0ccbeb4a70ab44dcb82d2ca596d30684fc4531