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

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

ただいまの
回答率

88.93%

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

解決済

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 158

saba0592

score 3

前提・実現したいこと

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

該当のソースコード

エージェントのソースコード(判定する側)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
public class Agent : MonoBehaviour
{
    public Transform marisa;//魔理沙
    public GameObject reimu;//霊夢
    private GameObject target;//ターゲット
    private GameObject[] towers1;//最初に取得するタワー
    private GameObject[] towers2;//2回目以降に取得するタワー

    private int Mode;//エージェントのモード
    private int defaultTowerNum;//最初に取得するタワーの数
    private int towerNum;//2回目以降に取得するタワーの数
    private int targetNum = 0;//ターゲットナンバー
    private int reimuDeathFlag;//霊夢の死亡フラグ

    private float attackInterval = 1.0f;//攻撃の間隔
    private float lastAttackTime;//最後に攻撃した時間
    private float distance1;//魔理沙とターゲットの距離
    private float distance2;//魔理沙と霊夢の距離

    private NavMeshAgent agent;//エージェント
    private MarisaAttack attack;//攻撃スクリプト
    private MarisaSkillPoint skill;//スキルスクリプト

    List<Action> disabledActions = new List<Action>();

    // Start is called before the first frame update
    void Start()
    {
        //いろいろ取得
        agent = GetComponent<NavMeshAgent>();
        attack = GetComponentInChildren<MarisaAttack>();
        skill = GetComponent<MarisaSkillPoint>();
        reimuDeathFlag = reimu.GetComponent<ReimuHealthScript>().deathFlag;
        TowerSearch1();
    }

    // Update is called once per frame
    void Update()
    {
        //タワーの数の変動を検知
        if (!disabledActions.Contains(Action.Search))
        {
            DisableAction(Action.Search, 10.0f);
            TowerSearch2();
        }

        if (target)
        {
            //タワーが存在する場合、タワーの距離を算出
            distance1 = Vector3.Distance(marisa.position, target.transform.position);
        }
        else if (targetNum < towers1.Length - 1)
        {
            //タワーが存在せず、次のターゲットがある場合、次のターゲットを探す
            targetNum++;
            target = towers1[targetNum];
        }
        else
        {
            //タワーが存在しない場合、霊夢をターゲットにする
            target = reimu;
        }

        //魔理沙と霊夢の距離
        distance2 = Vector3.Distance(marisa.position, reimu.transform.position);

        if (10 < distance1 && targetNum < 5)//ターゲットとの距離が10より大きく、かつターゲットナンバーが5未満の時
        {
            Mode = 0;
        }

        if ((5 < distance2 || reimuDeathFlag == 1) && distance1 <= 10)//霊夢との距離が5より大きいか霊夢が死んでいる、かつターゲットとの距離が10以下の時
        {
            Mode = 1;
        }

        if (distance2 <= 5 && reimuDeathFlag == 0)//霊夢との距離が5以下、かつ霊夢が生きている時
        {
            Mode = 2;
        }

        Debug.Log(Mode);
        Debug.Log(reimuDeathFlag);

        switch (Mode)
        {

            case 0:

                //ターゲットに向かう
                agent.destination = target.transform.position;
                break;

            case 1:

                //ターゲットの方を向く
                Quaternion targetRotation = Quaternion.LookRotation(target.transform.position - transform.position);
                transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, Time.deltaTime * 1f);

                //ターゲットに向かう
                agent.destination = target.transform.position;

                //ターゲットとの距離が2以下、且つ最後に攻撃した時間から1秒以上経っている時
                if (distance1 <= 2 && Time.time > lastAttackTime + attackInterval)
                {
                    if (skill.skillPoint >= 50)
                    {
                        attack.Attack2();//スキル攻撃
                    }
                    else
                    {
                        attack.Attack1();//通常攻撃
                    }
                    lastAttackTime = Time.time;//最後に攻撃した時間を更新
                }
                break;

            case 2:
                //霊夢の方を向く
                Quaternion reimuRotation = Quaternion.LookRotation(reimu.transform.position - transform.position);
                transform.rotation = Quaternion.Slerp(transform.rotation, reimuRotation, Time.deltaTime * 1f);

                //霊夢に向かう
                agent.destination = reimu.transform.position;

                //霊夢との距離が2以下、且つ最後に攻撃した時間から1秒以上経っている時
                if (distance2 <= 2 && Time.time > lastAttackTime + attackInterval)
                {
                    if (skill.skillPoint >= 50)
                    {
                        attack.Attack2();//スキル攻撃
                    }
                    else
                    {
                        attack.Attack1();//通常攻撃
                    }
                    lastAttackTime = Time.time;//最後に攻撃した時間を更新
                }
                break;
        }
    }

    //タワーを検知してターゲットに設定
    public void TowerSearch1()
    {
        towers1 = GameObject.FindGameObjectsWithTag("ReimuTower");
        defaultTowerNum = towers1.Length;
        Shuffle();
        target = towers1[targetNum];
    }

    //タワーの数の変動を検知
    public void TowerSearch2()
    {
        towers2 = GameObject.FindGameObjectsWithTag("ReimuTower");
        towerNum = towers2.Length;

        if (!(defaultTowerNum == towerNum))
        {
            TowerSearch1();
        }
    }

    //タワーの配列をシャッフル
    public void Shuffle()
    {
        for (int i = 0; i < towers1.Length; i++)
        {
            GameObject tmp = towers1[i];
            int randomIndex = Random.Range(i, towers1.Length);
            towers1[i] = towers1[randomIndex];
            towers1[randomIndex] = tmp;
        }
    }

    //行動不能用コルーチン
    IEnumerator DisableAction(Action action, float duration)
    {
        disabledActions.Add(action);
        yield return new WaitForSeconds(duration);
        disabledActions.Remove(action);
    }

    //アクション
    public enum Action
    {
        Search
    }
}
プレイヤーのソースコード(判定される側)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class ReimuHealthScript : MonoBehaviour
{
    [SerializeField] private float maxHealth = 1000.0f;//最大HP
    public float health;//今のHP
    private float respawnTime;//リスポーンをした時間
    public int deathFlag = 0;//死亡フラグ

    public Slider slider;//HPバー

    private Vector3 respawnPosition;//リスポーン位置
    private ReimuController controller;//コントローラー
    private AttackScript attack;//攻撃スクリプト
    private Animator anim;//アニメーター
    private ReimuSkillPoint skillPoint;//スキルスクリプト

    private void Awake()
    {
        //リスポーン位置を設定
        respawnPosition = transform.root.gameObject.transform.position;
    }

    // Start is called before the first frame update
    void Start()
    {
        //HPバーの初期化
        slider.value = 1;

        //HPの初期化
        health = maxHealth;

        //色々取得
        controller = GetComponent<ReimuController>();
        attack = GetComponentInChildren<AttackScript>();
        anim = GetComponentInChildren<Animator>();
        skillPoint = GetComponent<ReimuSkillPoint>();
    }

    // Update is called once per frame
    void Update()
    {
        //HPバーに数値を割当
        slider.value = (float)health / (float)maxHealth;

        //死んだときの処理
        if (health <= 0)
        {
            deathFlag = 1;
            controller.enabled = false;
            attack.enabled = false;
            anim.SetBool("death", true);
            if (Time.time > respawnTime)
            {
                StartCoroutine("Respawn");
                respawnTime = Time.time + 5.5f;
            }
        }
    }

    //水没時の処理
    void OnTriggerStay(Collider other)
    {
        if (other.CompareTag("Water") && health > 0)
        {
            health -= 5;
        }
    }

    //リスポーン処理
    IEnumerator Respawn()
    {
        yield return new WaitForSeconds(5.0f);
        transform.root.gameObject.transform.position = respawnPosition;
        health = maxHealth;
        deathFlag = 0;
        controller.enabled = true;
        attack.enabled = true;
        anim.SetBool("death", false);
        skillPoint.skillPoint -= 25;
    }
}

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

Unity Version 2019.4.1f1 Personal
Mac macOS Catalina ver.10.15.5

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 1

checkベストアンサー

+1

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

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

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

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2020/07/18 17:11

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

    キャンセル

  • 2020/07/18 17:16

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

    キャンセル

  • 2020/07/18 17:19

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

    キャンセル

  • 2020/07/18 17:36

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

    キャンセル

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

  • ただいまの回答率 88.93%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

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