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

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

ただいまの
回答率

90.53%

  • C#

    8774questions

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

  • Unity

    5286questions

    Unityは、ユニティテクノロジーが開発したゲームエンジンです。 主にモバイルやブラウザ向けのゲーム製作に利用されていましたが、3Dの重力付きゲームが簡単に作成できることから需要が増え、現在はマルチプラットフォームに対応しています。 言語はC言語/C++で書かれていますが、C#、JavaScript、Booで書かれたコードにも対応しています。

Unityにて"NullReferenceException" Update()では参照が確認できたのだが...

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 552

Sado

score 47

 【まとめ】【解決後の追記】

解決まで非常に遠回りをしてしまいましたので、簡潔にまとめさせていただきます。
今回NullReferenceExceptionが出たのですが、エラーとして示された行に存在するメソッド・クラス型変数(?)に焦点をあててしまったことから見逃してしまった凡ミスです。
空参照エラーの行に存在するスクリプトやメソッドとは少し別の箇所で定義したものが原因でした。

というのも、あるゲームオブジェクトにアタッチしたスクリプトから別のゲームオブジェクトのスクリプトのメソッドを呼び出していたのですが、この時に別のオブジェクトの参照を得るべき箇所で無理やりスクリプトそのものをねじ込もうとしていました。

スクリプト冒頭で[SerializeField] private GameObject gmObj;と書きStart()内でスクリプトコンポーネントの参照を得るべきところで、[SerialzeField] private Script-Name scObj;と書いてしまっていました。インスペクター側の項目もわけのわからないものを参照していました。

初心者あるあるとでも思わないとやってられない凡ミスです。基礎といいますか、扱うデータ型を疎かにしすぎです。Java勉強中とは口が裂けても言えません。

 前提・実現したいこと

特別なアイテム、通常のアイテム(それぞれGameObject)を確立で生成するプログラムを作成しています。
今回、特別なアイテムを参照するtargetItem.GetGameObject()で空参照エラーが頻発しました。

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

特定の箇所でのみInstantiate()を実行しようとすると"NullReferenceException: Object reference not set to an instance of an object"が表示されます。

NullReferenceException: Object reference not set to an instance of an object
ItemManager.makeItems (Int32 n, Vector3 vec3) (at Assets/Scripts/ItemManager.cs:71)
Box.Update () (at Assets/Scripts/Box.cs:55)

 該当のソースコード

//Assets/Scripts/ItemManager.cs
public void makeItems(int n,Vector3 vec3)
    {
        //Debug.Log("メソッド内デバッグ : " + targetItem.GetGameObject().name); // コメント外すとエラー
        if (canMakeTargetItem())
        {
            if (true)//(Random.Range(0, 100) < targetIncidence) // 【Line68】
            {
                Debug.Log("チェックポインツB");
                Instantiate(targetItem.GetGameObject(), vec3, Quaternion.identity); //【Line71】
                return;
                // 特別アイテムを生成したら, 即時終了.
            }
        }

        if (!canMakeItems()) return;
        // 通常アイテム数が上限なら, 終了.

        // 通常アイテムをn個生成【この処理は上手く働く】
        if (n < 1) n = 1;
        for (int i = 0; i < n; i++)
        {
            int shift = (i * 20) - (n*10) ;
            Instantiate(randomItem().GetGameObject(), vec3 + new Vector3(shift,0,0), Quaternion.identity);
        }
    }
//Assets/Scripts/Box.cs
void Update () {

        Objects = GameObject.FindGameObjectsWithTag("StageObject");
        //Debug.Log("オブジェクトの数は" + Objects.Length);

        int StageSt = Stage.StageState;
        //Debug.Log(StageSt);

        if(StageSt == 1){
             BoxHP = 0;
        }

        if (BoxHP <= 0)
        {
            //Debug.Log("破壊");
            adse.Play();
            itemMng.makeItems(itemMakeNum, transform.position); //【Line55】
            Destroy(gameObject);
        }

    }

 試したこと

「NullReferenceException」はよくあるnull参照エラーですから、ItemManagerクラスのtargetItem.GetGameObject()が何も示せていない事を疑いました。
同クラスのUpdate()にDebug.Log("デバッグ : " + targetItem.GetGameObject().name);を記入したところ、オブジェクトの名前が返ってきました。しかし、同クラスのmakeItems()に上記のデバッグ文を挿入したところ、表題のようなエラーが発生しました。
makeItems()メソッド内で空参照エラーが発生する理由が思い当たりません。

デバッグ用に比較文を(true)にしてある【Line68】を本来の式に戻し、「確立で特別なアイテムを生成する」という処理にした上で問題のブロックが実行されなかった場合……「通常アイテムをn個生成」とコメントされた箇所の処理、Instantiate()は正常に動作しました。

また、Box.cs内で宝箱破壊時に効果音を再生adse.Play();しているのですが、今回のエラー発生時、Destroy(gameObject);されずに残っているのかSEが無限再生されるように暴走します。
特別なアイテムを生成しない、通常アイテムを生成する時はSEやDestroyに異常は感じられませんでした。

 デバッグ状況1(追記)

targetItem.GetGameObject()の補足をしますと、targetItemはItem型の変数でアイテムの各種情報(名前や属性,説明,GameObjectなど)をprivate typeで格納しています。この中にGameObjectがあり、GetGameObject()で取得できるようになっています。
ここで、Item型のGetGameObjectは他の場所でも頻繁に利用していて問題が起きていないために見落としていましたが、問題の箇所でtargetItemのみで確認してみたところヌルリファレンスエラーは発生しませんでした。
問題のメソッド内で<Item>.GetGameObject()を須いたときのみエラーが発生するらしいことまでが分かりました。

しかし、「targetItemの中身はどの時点でも空ではない」「GetGameObject()はprivateな変数を返すだけのメソッド」「Item型の実体の方も問題のメソッド以外では参照が確認できる」「Item型の実体の方でGameObjectの参照を格納する変数に変更を加える(代入する)処理は一切書き込んでいない」
となると、余計に分かりません。
何かちょっとしたヒントでもいいので、突破口に成るような何かが見つかるといいのですが......

 デバッグ状況2(追記)

Item型のインスタンスを、ItemManagerクラスのtargetItemに参照を格納し、壊れるとアイテムを出現させるBoxクラスからItemManagerクラスのmakeItems()を実行するとエラーが発生することがわかりました。
ItemクラスのGetGameObject()だけでなく、Itemクラス内の全メソッドにおいて同様のエラーが発生します。
その条件は恐らくですが、「BoxクラスからItemManagerクラスのメソッドを呼び出す。そのメソッドがまたItemクラスのメソッドを呼び出す」といった構造をしていることだと思いましたが、それをどのように解決させるか検討もつきません。
「BoxクラスからItemManagerクラスのメソッドを呼び出す。そのメソッドがItemクラスのインスタンスの参照そのものを表示する」という先よりも一段階少ない工程でデバッグしてみると、ヌルにはなりませんでした。

HSP言語のループのように、C#のメソッドを呼び出す深さ(ネスト)が3つくらいと言った、Unity C#特有の制限があるのでしょうか。

 補足情報(FW/ツールのバージョンなど)

Unity2018 2.0f2、VS2017、Windows 10 home 64bit。

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 3

check解決した方法

+1

とてもしょうもない話でした。
アイテム管理ゲームオブジェクトが持つItemManager.csの参照を得るための手順を誤っていただけで、作ったクラスやメソッド等に特段問題は見つかりませんでした。

強いて言えば、Box.cs内でAudioSourceを鳴らす処理がDestroyすることで無駄になっており、PlayClipToPointメソッドに変更する程度の修正点があるのみでした。(今回のエラーと関係なし)

対象のGameObjectの参照を取るべくインスペクタでD&Dし、Start()でGetCompornent()する。
たったこれだけの工程を間違えるのはとても情けない。
これに多くの時間を割いた自分が情けない。
視野が狭すぎます......イベント直前で徹夜気味に弄るものじゃないですね。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

+1

targetItem.GetGameObject()がnullを返すことがあるようです。
そこのソースをデバッグするといいです。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2018/11/03 01:14

    回答ありがとうございます。返信遅れてしまい申し訳ありません。
    `targetItem.GetGameObject()`が直接的なエラーの原因なのは理解していましたので、怪しい箇所でDebug.Log()を用いて中身を覗いていたのですが、どうやら不十分でした。
    中身があるときとないときがあるので、現在、意図しない箇所で余計にtargetItemに変更を加えている箇所がありそうだと当たりを付けてデバッグしている状況です。

    targetItemはItem型なのですが、質問文の「該当のソースコード」にも載っている`randomItem().GetGameObject()`はnullを返さないことから、randomItem()の返り値でもある「Item型」及びItem型の「GetGameObject()」に問題は無いと判断しています。

    キャンセル

+1

VisualStudioを使ってるなら、任意の行にブレークポイントを設定し、そこで実行を止めて変数の値を確認できます。
また、そこから1行づつ実行したりできますんで、それでデバッグしていきましょう

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2018/11/03 01:07

    回答ありがとうございます。返信遅れてしまい申し訳ありません。
    Unityでの実行ですので、VSのブレークポイントを利用したデバッグが有効なのか分かりませんでした。(どのように適用するのか分からなかった)
    引き続き、Debug.Log()を利用して`targetItem.GetGameObject()`とその周辺を調査していきます。

    キャンセル

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

  • C#

    8774questions

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

  • Unity

    5286questions

    Unityは、ユニティテクノロジーが開発したゲームエンジンです。 主にモバイルやブラウザ向けのゲーム製作に利用されていましたが、3Dの重力付きゲームが簡単に作成できることから需要が増え、現在はマルチプラットフォームに対応しています。 言語はC言語/C++で書かれていますが、C#、JavaScript、Booで書かれたコードにも対応しています。