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

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

新規登録して質問してみよう
ただいま回答率
85.50%
Unity

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

Q&A

解決済

1回答

3780閲覧

プレハブの参照について

4423

総合スコア16

Unity

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

0グッド

0クリップ

投稿2018/09/14 14:22

編集2018/09/15 03:59

プレハブに付属しているスクリプトを取得したいです

現在、3Dゲームを制作しています。
Canvas内にあるHPのイメージをプレーヤーのHPを参照して
FillAmountで縮小させたいのですが、プレーヤーにアタッチされているスクリプト情報を取得しようとすると再生時に参照が外れてしまいます。

取得する方法、またはなにか間違いなどがあれば
お教えいただきたく存じます。

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

NullReferenceException: Object reference not set to an instance of an object

該当のソースコード

Cここに言語名を入力C#

1 2 3・GUIスクリプト 4 5using System.Collections.Generic; 6using UnityEngine; 7using UnityEngine.UI; 8 9public class HpGauge : MonoBehaviour 10{ 11 [SerializeField] 12 private GameObject m_Player; 13 private PlayerMove m_PlayerScript; 14 private Image m_HPimage; 15 16 private void Start() 17 { 18 19 m_Player = GetComponent<GameObject>(); 20 m_PlayerScript = m_PlayerScript.GetComponent<PlayerMove>(); 21 m_HPimage = gameObject.GetComponent<Image>(); 22 m_HPimage.fillAmount = 1.0f; 23 } 24 25 // Update is called once per frame 26 void Update() 27 { 28 29 if (m_PlayerScript.HP <= 0) ←エラーが起きる箇所 30 { 31 m_HPimage.fillAmount = 0; 32 } 33
・参照先 プレーヤースクリプト using System.Collections; using System.Collections.Generic; using UnityEngine; public class PlayerMove : MonoBehaviour { private JudgeToAvoid m_Judge; // 敵の攻撃判定 private Controller m_Control; // プレーヤー入力 private int m_attackPoint; // 攻撃力 private int m_hp; // 体力 public int AttackPoint { get { return m_attackPoint; } set { m_attackPoint = value; } } public int HP { get { return m_hp; } set { m_hp = value;} } //Use this for initialization void Start() { AttackPoint = 10; HP = 100; m_Control = GetComponent<Controller>(); m_Judge = gameObject.transform.Find("Avoid_area").GetComponent<JudgeToAvoid>(); }
***追加分 HPイメージスクリプト**** using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; public class HpGauge : MonoBehaviour { [SerializeField] private GameObject m_Player; private PlayerMove m_PlayerScript; private Image m_HPimage; private void Start() { m_PlayerScript = m_Player.GetComponent<PlayerMove>(); m_HPimage = gameObject.GetComponent<Image>(); m_HPimage.fillAmount = 1.0f; } // Update is called once per frame void Update() { if (m_PlayerScript.HP <= 0) { m_HPimage.fillAmount = 0; } while (m_PlayerScript.HP > 0) { m_HPimage.fillAmount -= 1.0f / m_PlayerScript.HP; if (m_PlayerScript.HP <= 10) { // 10以下になったら点滅する Flashing(m_HPimage.color); } } }

イメージ説明
イメージ説明

試したこと

シリアライズ化して、インスペクター上で紐付け。 ⇒ 結果 NULL
タグでオブジェクトを検索し、スクリプト内で参照 ⇒ 結果 プレーヤーの子オブジェクトまで取得しようとしているのか、画面が固まりました…

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

Unity2017.2

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

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

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

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

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

guest

回答1

0

ベストアンサー

まず、HpGaugeStart内にあるm_Player = GetComponent<GameObject>();が余計ではないでしょうか?
GetComponent<GameObject>()は、「このHpGaugeがアタッチされているゲームオブジェクト(つまり「HP」)からGameObjectコンポーネントを取得」しようとしています。しかし、GameObjectComponentではないので失敗し、nullが返されるはずです。
プレイ開始時点ではm_Playerにプレイヤーへの参照が入っているものの、ここでm_Playernullに上書きされてしまっているものと思われます。この部分でm_Playerに何か代入する必要はないはずですので、この行は削除してしまっていいでしょう。

次に、その下の行のm_PlayerScript = m_PlayerScript.GetComponent<PlayerMove>();m_PlayerScript = m_Player.GetComponent<PlayerMove>();の打ち間違いでしょうか。
ここを修正すればm_PlayerからPlayerMoveスクリプトコンポーネントが取得され、m_PlayerScriptにちゃんと代入されるようになるかと思います。

追記

固まってしまう原因は、高確率でUpdate内のwhileブロック部分でしょうね...

Unityのスクリプトは、特殊なことをしない限りシングルスレッドで動作するはずです。たとえばシーン内にA、B、Cの3つのスクリプトがあったとすると、こういうイメージよりも...
並列
こういうイメージの方が実際の動作に近いでしょう。
直列
一つのスレッドで各メソッドが順番に実行されるので、どこかで不用意に無限ループを使ってしまうと、全体が応答不能になってしまうと思われます。

ご提示のコード中のwhileループは消してしまってもよさそうです。こんな感じではいかがでしょうか?

C#

1 // Update is called once per frame 2 void Update() 3 { 4 if (m_PlayerScript.HP <= 0) 5 { 6 m_HPimage.fillAmount = 0; 7 } 8 else 9 { 10 // m_HPimage.fillAmount -= 1.0f / m_PlayerScript.HP; 11 // お節介かもしれませんが、HPゲージらしい伸縮をさせるなら、伸縮率を「現在HP / 最大HP」に 12 // 設定すればそれっぽくなるのではないでしょうか? 13 // 最大HPも、本当ならHpGaugeのコード中に直接書き込むよりも、PlayerMoveあたりに 14 // プロパティを追加して、それを参照するのが常套手段かと思います 15 m_HPimage.fillAmount += ((m_PlayerScript.HP / 100.0f) - m_HPimage.fillAmount) * 0.1f; 16 17 if (m_PlayerScript.HP <= 10) 18 { 19 // 10以下になったら点滅する 20 Flashing(m_HPimage.color); 21 } 22 23 // まさか上記Flashingメソッドにも無限ループが入っていたりはしないでしょうか? 24 // このままでうまく動けば問題ないですが、さもなくばここも代替手段を 25 // 用意する必要があるでしょう 26 // 一案として、時刻をもとに色を決定するようにしてみました 27 /* 28 if (m_PlayerScript.HP <= 10) 29 { 30 // 1秒周期で0.0~1.0を繰り返す 31 var blendingRatio = (Mathf.Sin(Time.time * 2.0f * Mathf.PI) * 0.5f) + 0.5f; 32 // 時刻に応じたブレンド比で白と赤を混ぜ、それを乗算色とする 33 m_HPimage.color = Color.Lerp(Color.white, Color.red, blendingRatio); 34 } 35 else 36 { 37 // HPが回復したら平常時の色に戻す 38 m_HPimage.color = Color.white; 39 } 40 */ 41 } 42 }

投稿2018/09/14 20:40

編集2018/09/15 07:10
Bongo

総合スコア10807

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

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

4423

2018/09/15 03:53

ご回答いただきありがとうございます。 私がGetComponentをきちんと理解しておらず、 参照されていないことがわかりました。 仰る通り、訂正いたしましたところ きちんと代入されていることが確認できました。 この度は、ありがとうございました。 また、重ねてお聞きして申し訳ないのですが プレーヤーを参照できた再に、画面が固まってしまいます。 パニックボタンというアセットを使っており、 どこで停止したか確認をすると、プレーヤースクリプトのプロパティを指しました。 HPスクリプトの続きでwhile文があるので そこの条件が正しくなかったのか、いろいろ変えてみましたが やはり固まってしまいます。 HPイメージのスクリプトを追加致します。 誤っている箇所があれば、お教えいただけますでしょうか。
Bongo

2018/09/15 06:53

書き換え案を検討してみましたが、いかがでしょうか?
4423

2018/09/15 10:19 編集

お忙しい中、ご対応頂きありがとうございます。 一から分かりやすく お教え頂き、大変助かります。 イベント関数の挙動につきましては、ご提示頂いた画像の仕組みになっているとは知らず(1枚目の並列のような挙動と認識しておりました) 新たな勉強になりました。 スクリプトまで、添えて頂き 本当にありがとうございます。 一度挙動を確認して、固まらないことが確認できました。 すぐに、お返事出来ず大変申し訳ありません。 いま、バイト中でして また自宅に戻って改めて作り直します。 本当にありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問