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

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

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

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

UI

UIはUser Interfaceの略であり、人間がコンピュータとやりとりをするためのシステムです。

Unity

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

Q&A

解決済

3回答

2049閲覧

別スクリプトのメソッドを呼び出すときにNullが返ってしまいます

myta

総合スコア2

C#

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

UI

UIはUser Interfaceの略であり、人間がコンピュータとやりとりをするためのシステムです。

Unity

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

0グッド

0クリップ

投稿2021/09/29 03:17

編集2021/09/29 03:31

初質問、且つプログラミング初心者です。
至らぬ点が多いかと存じますが、何卒ご容赦いただければと思います。

前提・実現したいこと

C#/unity2020.3.13f1 にて2dゲームを作っています。

体力を管理するスクリプトからUI上のアイコンを切り替えるため、別スクリプトで用意したメソッドを呼び出したのですが、
NullReferenceExceptionのエラーが発生してしまいます。

表示するアイコンには呼び出したいメソッド(アイコン切り替えメソッド)を記したスクリプトをアタッチさせているほか、
同じスクリプト内にスプライト型の配列を用意し、インスペクタ上で2種類のスプライトを登録した上でプレハブ化させてあります。

おそらく、メソッドの方で別スクリプトの参照を行き来するときの基本的な決まり事を抜かしてしまっているのだとは思いますが、
メインのスクリプトから呼び出したときに正常に機能するメソッドになるようにはどのように改めればよいか、ご助言をいただきたいです。

該当のソースコード

↓↓呼び出し側のスクリプト

C#

1using System.Collections; 2using System.Collections.Generic; 3using UnityEngine; 4 5//Script Execution Orderで4番目に実行する 6 7public class LifeManager : MonoBehaviour 8{ 9 public PLParameter p_Parameter;//プレイヤーのステータスを記録する別スクリプト(★) 10 public PL_Life _Life;//アイコンのprefabを入れる 11 12 private int playerMaxHP;//★から体力の最大値を入手 13 private int playerCurrentHP;//★から体力の現在値を入手 14 15 public List<PL_Life> life = new List<PL_Life>();//プレハブの実体を入れるリスト 16 17 // ゲーム起動時に呼び出す体力の初期化 18 void Start() 19 { 20 playerMaxHP = p_Parameter.GetMaxHP; 21 playerCurrentHP = p_Parameter.GetCurrentHP; 22 23 for(var i = 0; i < playerMaxHP; i++) 24 { 25 PL_Life plus = Instantiate(_Life, transform, false); 26 life.Add(plus); 27 life[i].full(); //【ここでNullReferenceExceptionが発生】 28 } 29 }

↓↓UI上のアイコン表示を切り替えるためのスクリプト(呼び出されるスクリプト)

C#

1using System.Collections; 2using System.Collections.Generic; 3using UnityEngine; 4using UnityEngine.UI; 5 6//Script Execution Orderで3番目に実行する 7 8public class PL_Life : MonoBehaviour 9{ 10 public Sprite[] _HP = new Sprite[2]; //インスペクタ上で切り替える2種類を登録 11 12 Image img; 13 14 void Start() 15 { 16 img = GetComponent<Image>(); 17 } 18 19 public void less() //ダメージ時のスプライトを登録 20 { 21 img.sprite = _HP[0]; 22 } 23 24 public void full() //ノンダメージ時のスプライトを登録【ここでNullReferenceExceptionが発生】 25 { 26 img.sprite = _HP[1]; 27 } 28}

試したこと

まず、呼び出すスクリプトが参照するメソッドを持つスクリプトの実体がないためにNullが返ってきているのかと思い、
unityの設定からスクリプトの実行順を定め、呼び出すスクリプトより前に呼び出されるスクリプトを読み込むようにしました

解決しなかったので、その後、コメントアウトなどで記述を多少変えて試していたところ、
上述問題とは別の場所ではありますが、呼び出した側と呼び出された側の関連部分でNullReferenceExceptionがいくつか発生しており、
エンジンの仕様や実行順などの込み入ったものではなく、基礎文法で足りないものがあるのではないかと推測しました

それを受け、呼び出されるプレハブ内のメソッドで指定するImageが、存在しない呼び出し側のコンポーネントから取得しようとすることで
Nullが生じているのではないかと考え、呼び出されるスクリプトのStart()内での記述を、

img = this.gamaObject.GetComponent<Image>();

とすることで、このスクリプトが取得するImageはアタッチされているプレハブに限定されるのではないかと考えましたが、
依然としてNullReferenceExceptionのままです

自分でも基礎力の欠如から非常に遠回りしている感が否めませんが、これ以上発想を転換させることが難しい状況です
お力添えのほどよろしくお願いいたします

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

Unity2020.3.13f1
(追記:初心者アイコンを付けました)

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

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

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

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

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

guest

回答3

0

これInstantiateした段階ではStartは呼ばれないのでimgがnullのまま、ってやつじゃないです?
たぶんStartじゃなくてAwakeでGetComponentすれば解決すると思います。

投稿2021/09/29 04:52

S.Percentage

総合スコア283

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

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

myta

2021/09/29 05:29

imgのGetComponentを先に処理させる目的で、unityの設定からスクリプト実行順を定義させてあるんですが、解決はしなかったんですよね… 自分のキャパを超えそうでStart意外の関数を使うのは避けていたんですがこれを機にきちんと学び直そうと思います 回答ありがとうございました!
myta

2021/09/29 05:51

何度もすみません!実際に動かしてみて確認したところ、こちらでも正常な動作を確認できました! スクリプトの読み込み順がどうこうではなく、呼び出し元のStart()内でinstantiateされたときにどのような実行順となっているか、という考え方だったんですね 自分の発想が全く至っていませんでした ひとつレベルアップできました!本当にありがとうございました!
guest

0

ベストアンサー

似たようなコードを作成しバグ再現し確認しました。
なぜ現状のコードで上手くいかないかは今一つ納得できませんが、
PL_Lifeスクリプトに関してpublic Image img;とpublicをつけて、PL_LifeスクリプトがアタッチされているGameObjectのインスペクター上で自身のImageコンポーネントを割り当てることで解決しました。

追記:
S.Percentageさんのおっしゃる通りですね、腑に落ちました。

投稿2021/09/29 04:55

編集2021/09/29 04:57
YOshim

総合スコア1085

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

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

myta

2021/09/29 05:42

回答ありがとうございます! 単純な解決法ですが、言われてみて初めてその手があったかと腑に落ちました ひとまずこれで進めようと思います
guest

0

C#

1life.Add(plus);

ここにブレークポイント置いて、停止したら
・lifeを確認する
たぶん要素は0個のはず
・plusを確認する
Startメソッドが動いていて、imgオブジェクトがちゃんと設定されているか
を確認してみてください

C#

1PL_Life plus = Instantiate(_Life, transform, false); 2plus.full(); 3life.Add(plus);

と変えると問題点がわかるかもね

投稿2021/09/29 04:23

退会済みユーザー

退会済みユーザー

総合スコア0

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

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

myta

2021/09/29 05:37

Addの段階ではリストに追加できていて、リスト内の要素が持ってるメソッド=full()を起動しようとするとNullになってしまうんですよね 複数のスクリプトでのそれぞれのStart()の実行順が不明だったのであらかじめunity側の設定でスクリプトの処理順も決めておいたため、オブジェクトにも中身が入っていると思ったのですが… 別スクリプト上でimgオブジェクトがきちんと実体を持つにはどうしたらよいか、という問題の捉え方をするべきだったかもしれません 迅速な回答ありがとうございました!!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問