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

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

新規登録して質問してみよう
ただいま回答率
85.48%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

Q&A

解決済

1回答

3314閲覧

実行終了時のNullReferenceExceptionの原因が知りたい。

FrostMan889

総合スコア20

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

0グッド

0クリップ

投稿2019/04/18 03:29

編集2019/04/18 10:13

前提・実現したいこと

Unity2018.2.20f1にて3Dのゲームを制作しています。
UIをクリックした際にUI管理オブジェクトが持っているUIcontoller.cs内の関数が呼ばれ、その関数でPlayerController内のフラグ切り替え処理が呼ばれるという部分を実装したいと思っています。

発生している問題・エラーメッセージ

上記箇所でエディタ上でのゲームの実行からの終了時にエラー文が出ます。
動作自体は意図した動作を実現できていますが、エラー文の原因を知りたいと思い質問させて頂きました。

NullReferenceException: Object reference not set to an instance of an object UIcontroller.AutoShot () (at Assets/Scripts/UIcontroller.cs:314) UnityEngine.Events.InvokableCall.Invoke () (at C:/buildslave/unity/build/Runtime/Export/UnityEvent.cs:166) UnityEngine.Events.UnityEvent`1[System.Boolean].Invoke (Boolean arg0) (at C:/buildslave/unity/build/Runtime/Export/UnityEvent_1.cs:63) UnityEngine.UI.Toggle.Rebuild (CanvasUpdate executing) (at C:/buildslave/unity/build/Extensions/guisystem/UnityEngine.UI/UI/Core/Toggle.cs:85) UnityEngine.UI.CanvasUpdateRegistry.PerformUpdate () (at C:/buildslave/unity/build/Extensions/guisystem/UnityEngine.UI/UI/Core/CanvasUpdateRegistry.cs:123) UnityEngine.Canvas:SendWillRenderCanvases()

該当のソースコード

UIcontroller.cs

C#

1void Start() { 2 //プレイヤーの取得処理 3 player = GameObject.Find("Player"); 4 //プレイヤーのスクリプトの取得処理 5 playerController = player.GetComponent<PlayerController>(); 6} 7 8 //オート射撃モードを切り替える関数 9 public void AutoShot() 10 { 11 12 //オートモードが実行中でない場合 13 if (isSelecting == false) 14 { 15 //playerContoroller内のオート射撃切り替え処理を実行 16 playerController.setAutoShot(); //←314行目 17 //切り替えフラグをonにして1回しか起動されないように 18 isSelecting = true; 19 } 20 21 22 //切り替えフラグを切る処理を予約 23 StartCoroutine(resetAutoShotFlag()); 24 25 } 26 27 //切り替えフラグをオフにする処理 28 private IEnumerator resetAutoShotFlag() 29 { 30 yield return new WaitForSeconds(0.2f); 31 isSelecting = false; 32 33 }

playerController.cs側の該当部分
既に持っているisAutoShotというフラグを切り替える関数

C#

1 //自動射撃のオンオフを切り替える処理 2 public void setAutoShot() 3 { 4 //オートモードが実行中でない場合 5 if (isAutoShot == false) 6 { 7 isAutoShot = true; 8 } 9 //オートモードが実行中の場合 10 else if (isAutoShot == true) 11 { 12 isAutoShot = false; 13 } 14 }

試したこと

NullReferenceExceptionということでplayerControllerへの参照部分に何か問題があるのかと思い、以下のようにコードを書き替えた場合、エラーが出なくなりました。

C#

1playerController.setAutoShot(); 23GameObject.Find("Player").GetComponent<PlayerController>().setAutoShot();

事前にグローバル変数でクラスを定義して、StartでGetComponentを行い参照を繋いでおけばその後は再度参照せずにアクセスできると考えていたのですが、違うのでしょうか?
また、通常のNullReferenceExceptionと違い実行中ではなく実行終了時、エディタに戻った際にエラーが出るのは何故なのでしょうか?
初歩的な疑問で大変申し訳ないのですが、ご教授頂ければ幸いです。

######追記

ご指摘を受けまして、以下のようにエラー行の直前にデバッグログを追記し参照が切れていないかを確認したところ参照先が表示されました。
(これはエラー時のログではなく正常動作時のログです。(ゲームの実行終了時に発生する)エラー時はエラーの内容のみが表示され、直前のdebug.logは実行されていないようで何も表示されません。)

C#

1Debug.Log(”Player:+ player + "Player Controller: " + playerController);を入れて実行したところ、 2playerController.setAutoShot();

Player: Player (UnityEngine.GameObject)Player Controller: Player (PlayerControllerScript.PlayerController)

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

BluOxy

2019/04/18 03:40

>StartでGetComponentを行い参照を繋いでおけばその後は再度参照せずにアクセスできると考えていたのですが、違うのでしょうか? その通りだと思いますが、そもそもplayerController = player.GetComponent<PlayerController>();でnullが入っていた可能性もあると思います。この処理が実行された時点でnullではないことはデバッグで確認されましたか?
hogefugapiyo

2019/04/18 03:45

参照が切れてないか Debug.Log(”Player: ” + player + "Player Controller: " + playerController); をどこかわかりやすそうなところにいれてチェックしてみてください。
FrostMan889

2019/04/18 03:53 編集

@mts10806様 お返事ありがとうございます。 NullReferenceException: Object reference not set to an instance of an object については比較的よく遭遇するので存じ上げています。 この場合ですと「playerController」の参照先がnull(未指定or外れている)だということですよね? しかし、実行中にはエラーは出ずちゃんと参照を取った動作が行われており、該当行の直前に Debug.Log(playerController.isAutoShot); を入れてみたところboolの値がconsoleにて表示されますので、通常遭遇するNullReferenceExceptionとは違うと考え質問させて頂きました。
FrostMan889

2019/04/18 03:53 編集

@BluOxy様 @hogefugapiyo様 お返事ありがとうございます。 記入中にアドバイスを頂き入れ違いになってしまいまして申し訳ありません。 エラー該当行の上にDebug.Log(”Player: ” + player + "Player Controller: " + playerController);を入れて実行したところ、 Player: Player (UnityEngine.GameObject)Player Controller: Player (PlayerControllerScript.PlayerController) とconsoleにて表示されました。この場合は参照は切れていない…ということで合っていますでしょうか?
hogefugapiyo

2019/04/18 04:55

うーん、参照は取れてるように思います。 Unity自体を再起動、パソコンを再起動などでも再現性のあるエラーですか?
moredeep

2019/04/18 06:27

>とconsoleにて表示されました。 念のため確認しますが、ゲーム中の正常に動く時のものではなく、エラーが出る直前に出た出力内容で合っていますか? もう1点、終了時の処理はどの程度記述されていますか?終了時、色々と破棄された後にその処理に入っていたりしませんか?
FrostMan889

2019/04/18 07:00 編集

@hogefugapiyo様 お返事ありがとうございます。PC、Unityを再起動しても同じように発生し、該当箇所を書き換えると発生しなくなるので再現性はあるようです。
FrostMan889

2019/04/18 07:13

@moredeep様 ご返事ありがとうございます。 debug.logの内容についてはゲーム中の正常に動く時のものです。 実行時には正常に動作し(エラーログは出ない)、ゲームの実行を停止するとエラーが出る、という状態でして、エラー直前(=終了時)には該当行の直前に記述したdebug.logの内容は表示されず、該当行のエラーのみがconsoleに追加されます。 わかりにくい表現で申し訳ありません。 終了時の処理について Unityの実行終了時に処理を追加できることを今知りまして、少なくとも自分では追加しておりません。 しかし、エラーログにEventやUI関連の内容が表示されているのでもしかするとそちらが終了時に実行されてしまっているのかもと思えてきました…。調べてみます。
yzccdefine

2019/04/18 08:12 編集

すみません他の方の助言対応中かとおもいますが 質問させてください。 AutoShot()はどこで使われていますか? コードを見た感じAutoShot()の使いどころによる影響なんじゃないかと思います。
BluOxy

2019/04/18 08:32

新しいプロジェクトにUIcontrollerとPlayerControllerを持って行って、同じ行にNullReferenceが出るかどうか。
FrostMan889

2019/04/18 09:50 編集

@yzccdefine様 ご返事ありがとうございます。AutoShot()はUIのToggleのOnValueChangedでクリック時に呼ばれるという形です。 このご指摘でToggleの箇所を見直した結果、実行条件が「Editor and Runtime」になっていたのでRuntime Onlyに変更したところエラーが表示されなくなりました! ありがとうございます! ご回答を頂きましたBluOxy様、hogefugapiyo様、moredeep様、お三方のご指摘のおかげで参照抜け、実行時と停止時の違いの視点を持てていたので問題の原因に気付くことができました。ありがとうございました。
guest

回答1

0

自己解決

AutoShot()を使用したい際にはuGUIのToggleからOnValueChangedでメソッドを呼び出していたのですがここの設定に問題がありました。
以下のように、実行条件が「Editor And Runtime」になっていたことが問題でした。

イメージ説明

この状態だとEditorからでも処理を受け付けてしまうので
Start関数でGetComponentを行う前にAutoShot()だけが実行され
playerController.setAutoShot();
のplayerControllerの参照が取れずにNullReferenceExceptionとなっていたようです。

実行終了時にエラーが出る問題はToggleでのみ発生するようで、自分も仕様完全には理解していないのですが、Editor上での実行終了時にToggle.isOnの値が初期化されてOnValueChangedが呼ばれてしまったのが原因かと思われます。

アドバイスを下さいました皆様本当にありがとうございました。

投稿2019/04/18 10:01

編集2019/04/18 10:27
FrostMan889

総合スコア20

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yzccdefine

2019/04/19 03:02

解決してよかったです!
FrostMan889

2019/04/19 08:34

昨日はご回答ありがとうございました!アドバイス頂いた内容のおかげ様で解決することができました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問