質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.10%

フェード処理を何度も呼び出したいがNullReferenceExceptionが出てしまう

解決済

回答 2

投稿

  • 評価
  • クリップ 0
  • VIEW 467

score 9

前提・実現したいこと

Unity初心者です。
ゲームのタイトル画面シーンでパネルにUIをまとめ、そのパネルをフェードで表示、非表示にするスクリプトを書きました。
こちら
https://teratail.com/questions/244118
の質問でいただいた回答のとおりにスクリプトを書き換え、ボタンでパネルを呼び出すたびに
フェードで出現するようにしました。
ところが、FadeManagerを各パネル(LoadGameパネル、Settingパネル、Aboutパネル)
にアタッチした直後はちゃんと動くのですが、別のシーンからタイトル画面シーンに遷移したり
Unityを再起動してタイトル画面シーンをPlayしようとすると、FadeManagerのSetAlpha ()部分で
エラーNullReferenceExceptionが出てしまいます。
エラーが出てからもう一度FadeManagerを各パネルにアタッチしなおすとエラーが消えるのですが
やはり別シーンから遷移・Unityの再起動をするとNullReferenceExceptionが出ます。

TitleSceneManagerのBackToMenu()からFadeManagerのResetAlpha()を呼び出して実行する際に
alfa=0;としたフェードカラーの設定が残ってしまっているのでは?と思うのですが
どうしたらいいかわかりません。
回答よろしくお願い申し上げます。

出ているエラー

NullReferenceException: Object reference not set to an instance of an object
FadeManager.SetAlpha () (at Assets/Scripts/FadeManager.cs:125)
FadeManager.ResetAlpha () (at Assets/Scripts/FadeManager.cs:162)
TitleSceneManager.BackToMenu () (at Assets/Scripts/TitleSceneManager.cs:88)
TitleSceneManager.Start () (at Assets/Scripts/TitleSceneManager.cs:34)

Unityのバージョン

2019.3.1f1

該当のソースコード

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI; //パネルのイメージを操作するのに必要
using UnityEngine.SceneManagement;

public class TitleSceneManager : MonoBehaviour
{
    //4つのPanelを格納する変数
    //インスペクターウィンドウからゲームオブジェクトを設定する
    [SerializeField] GameObject titleMenuPanel;   //TitleMenuパネル
    [SerializeField] GameObject loadGamePanel;   //LoadGameパネル
    [SerializeField] GameObject settingPanel;    //Settingパネル
    [SerializeField] GameObject aboutPanel;      //Aboutパネル

    FadeManager fadeLoad;   //LoadGameパネルをフェードで出現させるためのオブジェクト
    FadeManager fadeSetting;//Settingパネル
    FadeManager fadeAbout;  //Aboutパネル





    // Start is called before the first frame update
    void Start()
    {

        fadeLoad = GameObject.Find("Panel_LoadGame").GetComponent<FadeManager>();  //newが使えないらしいのでこうやってFadeManagerを読み込むよ
        fadeSetting = GameObject.Find("Panel_Setting").GetComponent<FadeManager>();
        fadeAbout= GameObject.Find("Panel_About").GetComponent<FadeManager>();


        //BackToMenuメソッドを呼び出す
        BackToMenu();

    }

    // Update is called once per frame
    void Update()
    {


    }

    //TitleMenuパネルでLoadGameボタンが押されたときの処理
    public void SelectLoadGameDescription()
    {
        titleMenuPanel.SetActive(false);
        loadGamePanel.SetActive(true);

        fadeLoad.isFadeOutHalf = true; //フェードで半透明のパネルを出現させるフラグ


    }


    //TitleMenuパネルでSettingボタンが押されたときの処理
    public void SelectSettingDescription()
    {
        titleMenuPanel.SetActive(false);
        settingPanel.SetActive(true);

        fadeSetting.isFadeOutHalf = true; //フェードで半透明のパネルを出現させるフラグ
    }

    //TitleMenuパネルでAboutボタンが押されたときの処理
    public void SelectAboutDescription()
    {
        titleMenuPanel.SetActive(false);
        aboutPanel.SetActive(true);

        fadeAbout.isFadeOutHalf = true; //フェードで半透明のパネルを出現させるフラグ
    }


    //TitleMenuパネル以外の3つのパネルでBackボタンが押されたときの処理
    public void BackToMenu()
    {


        titleMenuPanel.SetActive(true);
        loadGamePanel.SetActive(false);
        settingPanel.SetActive(false);
        aboutPanel.SetActive(false);


        // 処理を追加
        fadeLoad.ResetAlpha();
        fadeSetting.ResetAlpha();
        fadeAbout.ResetAlpha();

    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI; //パネルのイメージを操作するのに必要
using UnityEngine.SceneManagement;

public class FadeManager : MonoBehaviour
{
    float fadeSpeed = 0.005f;        //透明度が変わるスピードを管理
    float red, green, blue, alfa;   //パネルの色、不透明度を管理

    public bool isFadeOut = false;  //フェードアウト処理の開始、完了を管理するフラグ
    public bool isFadeIn = false;   //フェードイン処理の開始、完了を管理するフラグ

    public bool isFadeOutHalf = false;  //半分フェードアウト処理の開始、完了を管理するフラグ


    private float stepTime;    // 経過時間カウント用

    public string sceneName = null; //シーンの名前






    Image fadeImage;                //透明度を変更するパネルのイメージ

    void Start()
    {
        fadeImage = GetComponent<Image>();
        red = fadeImage.color.r;
        green = fadeImage.color.g;
        blue = fadeImage.color.b;
        alfa = fadeImage.color.a;



        stepTime = 0.0f;       // 経過時間初期化

        sceneName = SceneManager.GetActiveScene().name; 

    }

    void Update()
    {

        if (isFadeIn)
        {
            StartFadeIn();
        }

        if (sceneName == "CasLogoScene"|| sceneName == "AttentionScene"|| sceneName == "WarningScene")
        {
            // 経過時間をカウント
            stepTime += Time.deltaTime;

            SetIsFadeOut();

            if (isFadeOut)
            {
                StartFadeOut();

                if (isFadeOut == false)
                {
                    ChangeSceneName();

                    SceneManager.LoadScene(sceneName);
                }
            }
        }


        if (isFadeOutHalf)
        {
            StartFadeOutHalf();
        }

        if (isFadeOut)
        {
            StartFadeOut();
        }


    }

    public void StartFadeIn()
    {
        alfa -= fadeSpeed;                //a)不透明度を徐々に下げる
        SetAlpha();                      //b)変更した不透明度パネルに反映する
        if (alfa <= 0)
        {                               //c)完全に透明になったら処理を抜ける
            isFadeIn = false;
            fadeImage.enabled = false;    //d)パネルの表示をオフにする
        }
    }

    public void StartFadeOut()
    {
        fadeImage.enabled = true;  // a)パネルの表示をオンにする
        alfa += fadeSpeed;         // b)不透明度を徐々にあげる
        SetAlpha();               // c)変更した透明度をパネルに反映する
        if (alfa >= 1)
        {             // d)完全に不透明になったら処理を抜ける
            isFadeOut = false;
        }
    }

    public void StartFadeOutHalf()
    {
        Debug.Log(alfa);
        fadeImage.enabled = true;  // a)パネルの表示をオンにする
        alfa += fadeSpeed;         // b)不透明度を徐々にあげる
        SetAlpha();               // c)変更した透明度をパネルに反映する
        if (alfa >= 0.5f)
        {
            isFadeOutHalf = false;


        }
    }

    void SetAlpha()
    {
        fadeImage.color = new Color(red, green, blue, alfa);
    }


    void SetIsFadeOut()
    {

        if (Input.GetMouseButtonDown(0) || Input.GetKeyDown("return") || stepTime >= 10.0f) //左クリックかエンターキー押下か10秒経つかで変数isFadeOutをtrueにする
        {
            isFadeOut = true;
        }


    }

    void ChangeSceneName()
    {
        switch (sceneName)
        {
            case "CasLogoScene":
                sceneName = "AttentionScene";
                break;

            case "AttentionScene":
                sceneName = "WarningScene";
                break;

            case "WarningScene":
                sceneName = "TitleScene";
                break;

        }
    }

    public void ResetAlpha()
    {
        alfa = 0.0f;
        SetAlpha();
    }


}
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

check解決した方法

0

こちらを参考にスクリプトを組み直し、Canvas Groupを利用して
UIをまとめてフェードできるようにしました。
https://kan-kikuchi.hatenablog.com/entry/CanvasFader

スクリプトを載せておきます。

using UnityEngine;
using System;
using System.Collections;
using System.Collections.Generic;

[RequireComponent(typeof(CanvasGroup))]

public class CanvasFader : MonoBehaviour
{
    //フェード用のキャンバス
    private CanvasGroup _canvasGroup;

    //フェードの状態
    private enum FadeState
    {
        None, FadeIn, FadeOut
    }
    private FadeState _fadeState = FadeState.None;

    //フェード時間
    [SerializeField]
    private float _duration;

    //タイムスケールを無視するか
    [SerializeField]
    private bool _ignoreTimeScale = true;

    //フェード終了後のコールバック
    private Action _onFinished = null;

    //=================================================================================
    //更新
    //=================================================================================

    private void Update()
    {
        if (_fadeState == FadeState.None)
        {
            return;
        }

        float fadeSpeed = 1f / _duration;
        if (_ignoreTimeScale)
        {
            fadeSpeed *= Time.unscaledDeltaTime;
        }
        else
        {
            fadeSpeed *= Time.deltaTime;
        }

        _canvasGroup.alpha += fadeSpeed * (_fadeState == FadeState.FadeIn ? 1f : -1f);

        //フェード終了判定
        if (_canvasGroup.alpha > 0 && _canvasGroup.alpha < 1)
        {
            return;
        }

        if (_onFinished != null)
        {
            _onFinished();
        }

        _fadeState = FadeState.None;
        this.enabled = false;
    }

    //=================================================================================
    //開始
    //=================================================================================

    /// <summary>
    /// 対象のオブジェクトのフェードを開始する
    /// </summary>
    public static CanvasFader Begin(GameObject target, bool isFadeOut, float duration, bool ignoreTimeScale = true, Action onFinished = null)
    {
        CanvasFader canvasFader = target.GetComponent<CanvasFader>();
        if (canvasFader == null)
        {
            canvasFader = target.AddComponent<CanvasFader>();
        }

        canvasFader.Play(isFadeOut, duration, ignoreTimeScale, onFinished);

        return canvasFader;
    }

    /// <summary>
    /// フェードを開始する
    /// </summary>
    public void Play(bool isFadeOut, float duration, bool ignoreTimeScale = true, Action onFinished = null)
    {
        this.enabled = true;

        if (_canvasGroup == null)
        {
            _canvasGroup = GetComponent<CanvasGroup>();
        }

        _canvasGroup.alpha = isFadeOut ? 1 : 0;
        _fadeState = isFadeOut ? FadeState.FadeOut : FadeState.FadeIn;

        _duration = duration;
        _ignoreTimeScale = ignoreTimeScale;
        _onFinished = onFinished;
    }

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

public class TitleSceneManager : MonoBehaviour
{
    //キャンバスを格納する変数
    //インスペクターウィンドウからゲームオブジェクトを設定する
    [SerializeField] GameObject titleMenuCanvas;   //TitleMenuキャンバス
    [SerializeField] GameObject loadGameCanvas;   //LoadGameキャンバス

    GameObject canvasFaderLoad;         //Loadキャンバス

    // Start is called before the first frame update
    void Start()
    {
        canvasFaderLoad = GameObject.Find("CanvasFader1");

        loadGameCanvas.SetActive(false);
    }

    // Update is called once per frame
    void Update()
    {
    }

    //TitleMenuパネルでLoadGameボタンが押されたときの処理
    public void SelectLoadGameDescription()
    {
        titleMenuCanvas.SetActive(false);
        loadGameCanvas.SetActive(true);

        CanvasFader.Begin(target: canvasFaderLoad, isFadeOut: false, duration: 0.2f, ignoreTimeScale: true, onFinished: OnFinished);
    }


    //Backボタン押下でLoadGameキャンバスのフェードアウト後に呼び出されるメッソッド
    private void OnFinishedLoadBack() 
    {
        loadGameCanvas.SetActive(false);
        titleMenuCanvas.SetActive(true);

    }


    //フェード後に呼び出されるメッソッド
    private void OnFinished()
    {

    }

    //LoadGame画面のBackボタン
    public void LoadBack()
    {
        CanvasFader.Begin(target: canvasFaderLoad, isFadeOut: true, duration: 0.2f, ignoreTimeScale: true, onFinished: OnFinishedLoadBack);


    }
}

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

FadeManagerを各パネルにアタッチした後にシーンを保存していますか?
アタッチ後にメニューバーの「File」->「Save」かキーボードのCtrl+Sでシーンを保存しないとアタッチした設定が保存されません。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/03/01 16:56

    すみません、なぜかそれでもダメでしたが別の方法で思い通りの動作をさせることに
    成功しました……!
    おそらくは教えていただいた方法を試しているつもりでどこかで私が間違えていたのだと
    思います。
    教えていただいて誠にありがとうございました、そしてお手数をおかけして
    申し訳ございませんでした……。
    また機会がありましたらご教授いただければ幸いです。
    本当にありがとうございました!

    キャンセル

  • 2020/03/01 17:53

    解決できたならよかったです

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.10%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る