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

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

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

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

Q&A

解決済

1回答

3027閲覧

検知したオブジェクトが現在生きているか死んでいるかを判定できるようにしたい

saba0592

総合スコア3

Unity

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

0グッド

0クリップ

投稿2020/07/18 07:40

前提・実現したいこと

 タイトル通りです。検知したオブジェクトが現在生きているか死んでいるかを判定できるようにしたい。
判定される側にdeathFlagの変数を追加してプレイヤーが死んだかどうか判定できる材料を用意しました。判定する側はStartメソッド内でそれを取得しているのですが、この方法だとゲーム開始時にしか取得しないためずっとdeathFlagが0のままです。
Updateメソッド内で取得すれば実現できるのは分かっていますが、GetComponentをUpdateメソッド内に書きたくないので他の方法を教えてほしいです。

該当のソースコード

#####エージェントのソースコード(判定する側)

C#

1using System.Collections; 2using System.Collections.Generic; 3using UnityEngine; 4using UnityEngine.AI; 5public class Agent : MonoBehaviour 6{ 7 public Transform marisa;//魔理沙 8 public GameObject reimu;//霊夢 9 private GameObject target;//ターゲット 10 private GameObject[] towers1;//最初に取得するタワー 11 private GameObject[] towers2;//2回目以降に取得するタワー 12 13 private int Mode;//エージェントのモード 14 private int defaultTowerNum;//最初に取得するタワーの数 15 private int towerNum;//2回目以降に取得するタワーの数 16 private int targetNum = 0;//ターゲットナンバー 17 private int reimuDeathFlag;//霊夢の死亡フラグ 18 19 private float attackInterval = 1.0f;//攻撃の間隔 20 private float lastAttackTime;//最後に攻撃した時間 21 private float distance1;//魔理沙とターゲットの距離 22 private float distance2;//魔理沙と霊夢の距離 23 24 private NavMeshAgent agent;//エージェント 25 private MarisaAttack attack;//攻撃スクリプト 26 private MarisaSkillPoint skill;//スキルスクリプト 27 28 List<Action> disabledActions = new List<Action>(); 29 30 // Start is called before the first frame update 31 void Start() 32 { 33 //いろいろ取得 34 agent = GetComponent<NavMeshAgent>(); 35 attack = GetComponentInChildren<MarisaAttack>(); 36 skill = GetComponent<MarisaSkillPoint>(); 37 reimuDeathFlag = reimu.GetComponent<ReimuHealthScript>().deathFlag; 38 TowerSearch1(); 39 } 40 41 // Update is called once per frame 42 void Update() 43 { 44 //タワーの数の変動を検知 45 if (!disabledActions.Contains(Action.Search)) 46 { 47 DisableAction(Action.Search, 10.0f); 48 TowerSearch2(); 49 } 50 51 if (target) 52 { 53 //タワーが存在する場合、タワーの距離を算出 54 distance1 = Vector3.Distance(marisa.position, target.transform.position); 55 } 56 else if (targetNum < towers1.Length - 1) 57 { 58 //タワーが存在せず、次のターゲットがある場合、次のターゲットを探す 59 targetNum++; 60 target = towers1[targetNum]; 61 } 62 else 63 { 64 //タワーが存在しない場合、霊夢をターゲットにする 65 target = reimu; 66 } 67 68 //魔理沙と霊夢の距離 69 distance2 = Vector3.Distance(marisa.position, reimu.transform.position); 70 71 if (10 < distance1 && targetNum < 5)//ターゲットとの距離が10より大きく、かつターゲットナンバーが5未満の時 72 { 73 Mode = 0; 74 } 75 76 if ((5 < distance2 || reimuDeathFlag == 1) && distance1 <= 10)//霊夢との距離が5より大きいか霊夢が死んでいる、かつターゲットとの距離が10以下の時 77 { 78 Mode = 1; 79 } 80 81 if (distance2 <= 5 && reimuDeathFlag == 0)//霊夢との距離が5以下、かつ霊夢が生きている時 82 { 83 Mode = 2; 84 } 85 86 Debug.Log(Mode); 87 Debug.Log(reimuDeathFlag); 88 89 switch (Mode) 90 { 91 92 case 0: 93 94 //ターゲットに向かう 95 agent.destination = target.transform.position; 96 break; 97 98 case 1: 99 100 //ターゲットの方を向く 101 Quaternion targetRotation = Quaternion.LookRotation(target.transform.position - transform.position); 102 transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, Time.deltaTime * 1f); 103 104 //ターゲットに向かう 105 agent.destination = target.transform.position; 106 107 //ターゲットとの距離が2以下、且つ最後に攻撃した時間から1秒以上経っている時 108 if (distance1 <= 2 && Time.time > lastAttackTime + attackInterval) 109 { 110 if (skill.skillPoint >= 50) 111 { 112 attack.Attack2();//スキル攻撃 113 } 114 else 115 { 116 attack.Attack1();//通常攻撃 117 } 118 lastAttackTime = Time.time;//最後に攻撃した時間を更新 119 } 120 break; 121 122 case 2: 123 //霊夢の方を向く 124 Quaternion reimuRotation = Quaternion.LookRotation(reimu.transform.position - transform.position); 125 transform.rotation = Quaternion.Slerp(transform.rotation, reimuRotation, Time.deltaTime * 1f); 126 127 //霊夢に向かう 128 agent.destination = reimu.transform.position; 129 130 //霊夢との距離が2以下、且つ最後に攻撃した時間から1秒以上経っている時 131 if (distance2 <= 2 && Time.time > lastAttackTime + attackInterval) 132 { 133 if (skill.skillPoint >= 50) 134 { 135 attack.Attack2();//スキル攻撃 136 } 137 else 138 { 139 attack.Attack1();//通常攻撃 140 } 141 lastAttackTime = Time.time;//最後に攻撃した時間を更新 142 } 143 break; 144 } 145 } 146 147 //タワーを検知してターゲットに設定 148 public void TowerSearch1() 149 { 150 towers1 = GameObject.FindGameObjectsWithTag("ReimuTower"); 151 defaultTowerNum = towers1.Length; 152 Shuffle(); 153 target = towers1[targetNum]; 154 } 155 156 //タワーの数の変動を検知 157 public void TowerSearch2() 158 { 159 towers2 = GameObject.FindGameObjectsWithTag("ReimuTower"); 160 towerNum = towers2.Length; 161 162 if (!(defaultTowerNum == towerNum)) 163 { 164 TowerSearch1(); 165 } 166 } 167 168 //タワーの配列をシャッフル 169 public void Shuffle() 170 { 171 for (int i = 0; i < towers1.Length; i++) 172 { 173 GameObject tmp = towers1[i]; 174 int randomIndex = Random.Range(i, towers1.Length); 175 towers1[i] = towers1[randomIndex]; 176 towers1[randomIndex] = tmp; 177 } 178 } 179 180 //行動不能用コルーチン 181 IEnumerator DisableAction(Action action, float duration) 182 { 183 disabledActions.Add(action); 184 yield return new WaitForSeconds(duration); 185 disabledActions.Remove(action); 186 } 187 188 //アクション 189 public enum Action 190 { 191 Search 192 } 193} 194

#####プレイヤーのソースコード(判定される側)

C#

1using System.Collections; 2using System.Collections.Generic; 3using UnityEngine; 4using UnityEngine.UI; 5 6public class ReimuHealthScript : MonoBehaviour 7{ 8 [SerializeField] private float maxHealth = 1000.0f;//最大HP 9 public float health;//今のHP 10 private float respawnTime;//リスポーンをした時間 11 public int deathFlag = 0;//死亡フラグ 12 13 public Slider slider;//HPバー 14 15 private Vector3 respawnPosition;//リスポーン位置 16 private ReimuController controller;//コントローラー 17 private AttackScript attack;//攻撃スクリプト 18 private Animator anim;//アニメーター 19 private ReimuSkillPoint skillPoint;//スキルスクリプト 20 21 private void Awake() 22 { 23 //リスポーン位置を設定 24 respawnPosition = transform.root.gameObject.transform.position; 25 } 26 27 // Start is called before the first frame update 28 void Start() 29 { 30 //HPバーの初期化 31 slider.value = 1; 32 33 //HPの初期化 34 health = maxHealth; 35 36 //色々取得 37 controller = GetComponent<ReimuController>(); 38 attack = GetComponentInChildren<AttackScript>(); 39 anim = GetComponentInChildren<Animator>(); 40 skillPoint = GetComponent<ReimuSkillPoint>(); 41 } 42 43 // Update is called once per frame 44 void Update() 45 { 46 //HPバーに数値を割当 47 slider.value = (float)health / (float)maxHealth; 48 49 //死んだときの処理 50 if (health <= 0) 51 { 52 deathFlag = 1; 53 controller.enabled = false; 54 attack.enabled = false; 55 anim.SetBool("death", true); 56 if (Time.time > respawnTime) 57 { 58 StartCoroutine("Respawn"); 59 respawnTime = Time.time + 5.5f; 60 } 61 } 62 } 63 64 //水没時の処理 65 void OnTriggerStay(Collider other) 66 { 67 if (other.CompareTag("Water") && health > 0) 68 { 69 health -= 5; 70 } 71 } 72 73 //リスポーン処理 74 IEnumerator Respawn() 75 { 76 yield return new WaitForSeconds(5.0f); 77 transform.root.gameObject.transform.position = respawnPosition; 78 health = maxHealth; 79 deathFlag = 0; 80 controller.enabled = true; 81 attack.enabled = true; 82 anim.SetBool("death", false); 83 skillPoint.skillPoint -= 25; 84 } 85} 86

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

Unity Version 2019.4.1f1 Personal
Mac macOS Catalina ver.10.15.5

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

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

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

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

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

guest

回答1

0

ベストアンサー

GetComponentをUpdateメソッド内に書きたくないので他の方法を教えてほしいです。

Agent クラスのメンバとして ReimuHealthScript 型の変数を用意し、Agent.Start() で GetComponent して参照を取得しておく。
それを Agent.Update() で使えば目的は達成できます。

別に Update() でオブジェクトから GetComponent するくらいかまわないと思いますけどね。そのオブジェクトにコンポーネントが 100 個とかついているわけでもないでしょうし。teratail での質問で他にも 「Update() で GetComponent したくない」って人を見たんですけど、その話ってどこから出てるんでしょうね。

投稿2020/07/18 07:58

bboydaisuke

総合スコア5275

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

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

saba0592

2020/07/18 08:11

GetComponentは重い処理だからUpdateで使うなという記事をいくつか見かけてから使わないようにしています。 いつどこから言われ出したのかというのは知らないですし、自分もへーそうなんだくらいにしか思ってません。火のないところに煙は立たないって言いますし、誰かが検証したのかなと思ってます。
bboydaisuke

2020/07/18 08:16

Unity を使い続けて熟練してくれば自然と Update() で GetComponent() はしなくなります。しかし、初心者の内からそれを徹底的に避けようとする必要はないと思います。
bboydaisuke

2020/07/18 08:19

GetComponent が重い重いと言っている人の内、結構な割合の人が GameObject.Find() と混同しているようにも思います。
saba0592

2020/07/18 08:36

できました。ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問