猿问

如何正确检测游戏对象?

我的目标是编写一个脚本,我可以在不同的游戏对象上使用它,并且它应该只在该游戏对象上绑定特定的变量,而不影响过程中的其他脚本。

例如,如果我把这个脚本放在两个游戏对象上,每个游戏对象在同一个脚本中应该有自己唯一的变量值。

如果我的问题不够清楚,我很乐意进一步阐述。

我对 Unity 编辑器有很好的理解,但是,我对 C# 还很陌生,所以我认为我在代码的某个地方犯了一个菜鸟错误并不是不合理的。

我设置东西的方式是我有两个单独的脚本:

  • Fighting控制像TeamHealthAttack DamageCool Down,Cooling downSnap

  • TrigDetect控制对因敌人进入触发范围而激活的触发器的检测。

我目前遇到的问题在于TrigDetect我猜的脚本。

还应注意,附加到每个相关游戏对象的空文件包含这两个脚本并标记为“部队”。

触发检测

using System.Collections;

using System.Collections.Generic;

using UnityEngine;


public class TrigDetect : MonoBehaviour

{

    //public GameObject[] Enemy;

    bool once = false; 


    void OnTriggerEnter(Collider other)

    {

        if (other.CompareTag("Troop"))

        {

            //Debug.Log("Entered");

        }

    }


    void OnTriggerExit(Collider other)

    {

        if (other.CompareTag("Troop"))

        {

            //Debug.Log("Exitted");

        }

    }


    void OnTriggerStay(Collider other)

    {

        if (other.CompareTag("Troop"))

        {


            Fighting self = GetComponent<Fighting>();


            GameObject g = GameObject.Find("Detection");


            Fighting fScript = g.GetComponent<Fighting>();


            //Enemy = GameObject.FindGameObjectsWithTag("Troop");

            //Debug.Log("Staying");

            //Debug.Log(Enemy);

            //Debug.Log(self.Health);

            //Debug.Log(fScript.Health);


            if (once == false)

            {

                Debug.Log("I am the team:" + self.Team);

                Debug.Log("I have detected the team:" + fScript.Team);

                once = true;

            }


            if (self.Team != fScript.Team)

            {


                if (self.CoolingDown == false)

                {

                    self.CoolingDown = true;

                    fScript.Health -= self.AttackDamage;

                }


holdtom
浏览 100回答 2
2回答

冉冉说

基本上,Find(name)只返回该名称的任何内容的第一个实例,因此您g = Find(name)几乎可以保证永远不会成为与您的触发/碰撞条件相关的对象。OnTriggerStay(Collider other)已经为您提供了触发区域中的“其他”对撞机,因此请使用它。:)替换这个:&nbsp;&nbsp;&nbsp;&nbsp;GameObject&nbsp;g&nbsp;=&nbsp;GameObject.Find("Detection"); &nbsp;&nbsp;&nbsp;&nbsp;Fighting&nbsp;fScript&nbsp;=&nbsp;g.GetComponent<Fighting>();有了这个:&nbsp;&nbsp;&nbsp;&nbsp;Fighting&nbsp;fScript&nbsp;=&nbsp;other.GetComponent<Fighting>();

呼唤远方

对于您的问题标题:每个 instaced(非静态)值对于相应的组件都是唯一的,因此对于GameObject它所附加的相应组件来说也是唯一的。您可能想重新提出这个问题,因为这实际上不是您的问题。问题是当你这样做时GameObject.Find("Detection");它实际上两次都找到了相同的对象:即层次结构中的第一个对象。因此,在两个组件之一中,您可以找到自己的空对象并跳过其余部分if(self.Team != FScript.Team)&nbsp;..你可以尝试使用other.Find("Detection");而是仅在相应的上下文中搜索..但是,您根本不应该使用Find!这是非常激烈的表现您应该始终重复使用参考,而不是一遍又一遍地搜索它们在你的情况下你不需要它由于您说两个脚本都附加到同一个对象,您可以简单地使用GetComponent<Fighting>();你可以这样做Awake并重用参考:private Fighting myFighting;private void Awake(){&nbsp; &nbsp; myFighting = GetComponent<Fighting>();}与碰撞相比,您不必使用Find任何一种,因为您已经拥有与碰撞的对象的引用:other.gameObject。我不知道您的整个设置,但您可以在层次结构中向下搜索组件// the flag true is sued to also find inactive gameObjects and components// leave it without parameters if you don't want thisvar otherFighting = other.GetComponentInChildren<Fighting>(true);或在层次结构中向上搜索var otherFighting = other.GetComponentInParent<Fighting>(true);或者如果你已经知道你与正确的游戏对象完全碰撞,只需使用var otherFighting = other.GetComponent<Fighting>();我将在我的示例中使用后者。比一直检查健康Update是一个巨大的性能问题。您应该有一个方法,例如TakeDamage,只有在您的健康状况实际发生变化时才进行检查:斗争using System.Collections;using System.Collections.Generic;using UnityEngine;public class Fighting : MonoBehaviour&nbsp;{&nbsp; &nbsp; public int Team = 1;&nbsp; &nbsp; public int Health = 100;&nbsp; &nbsp; public int AttackDamage = 10;&nbsp; &nbsp; public float CoolDown = 2;&nbsp; &nbsp; public float original = 2;&nbsp; &nbsp; // you don't need that flag see below&nbsp; &nbsp; //public bool CoolingDown = false;&nbsp; &nbsp; public bool Snap = false;&nbsp; &nbsp; private void Update()&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; // you might also put this in a callback instead of update at some point later&nbsp; &nbsp; &nbsp; &nbsp; if(Snap == true)&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Destroy(transform.parent.gameObject);&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; // Note: this also makes not muh sense because if you destroyed&nbsp; &nbsp; &nbsp; &nbsp; // the parent than you cannot instantiate it again!&nbsp; &nbsp; &nbsp; &nbsp; // use a prefab instead&nbsp; &nbsp; &nbsp; &nbsp; if (Input.GetKey(KeyCode.N)) Instantiate(transform.parent.gameObject);&nbsp; &nbsp; }&nbsp; &nbsp; public void TakeDamge(int DamageAmount)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; Health -= DamageAmount;&nbsp; &nbsp; &nbsp; &nbsp; if (Health > 0) return;&nbsp; &nbsp; &nbsp; &nbsp; Destroy(transform.parent.gameObject);&nbsp; &nbsp; }}一般的另一个性能问题:即使Start, Updateetc 是空的,如果它们存在于您的脚本中,Unity 也会调用它们。因此,如果您不使用它们,请完全删除它们以避免无用的开销。所以我会触发检测using System.Collections;using System.Collections.Generic;using UnityEngine;public class TrigDetect : MonoBehaviour{&nbsp; &nbsp; bool once = false;&nbsp;&nbsp; &nbsp; private Fighting myFighting;&nbsp; &nbsp; private void Awake()&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; myFighting = GetComponent<Fighting>();&nbsp; &nbsp; }&nbsp; &nbsp; void OnTriggerStay(Collider other)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; // if wrong tag do nothing&nbsp; &nbsp; &nbsp; &nbsp; if (!other.CompareTag("Troop")) return;&nbsp; &nbsp; &nbsp; &nbsp; Fighting fScript = other.GetComponent<Fighting>();&nbsp; &nbsp; &nbsp; &nbsp; // here you should add a check&nbsp; &nbsp; &nbsp; &nbsp; if(!fScript)&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // By using the other.gameObject as context you can find with which object&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // you collided exactly by clicking on the Log&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Debug.LogError("Something went wrong: Could not get the Fighting component of other", other.gameObject);&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; if (!once)&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Debug.Log("I am the team:" + self.Team);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Debug.Log("I have detected the team:" + fScript.Team);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; once = true;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; // if same team do nothing&nbsp; &nbsp; &nbsp; &nbsp; if (self.Team == fScript.Team) return;&nbsp; &nbsp; &nbsp; &nbsp; // you don't need the CoolingDown bool at all:&nbsp; &nbsp; &nbsp; &nbsp; self.CoolDown -= Time.deltaTime;&nbsp; &nbsp; &nbsp; &nbsp; // if still cooling down do nothing&nbsp; &nbsp; &nbsp; &nbsp; if(self.CoolDown > 0) return;&nbsp; &nbsp; &nbsp; &nbsp; fScript.TakeDamage(self.AttackDamage);&nbsp; &nbsp; &nbsp; &nbsp; self.CoolDown = self.original;&nbsp; &nbsp; }}
随时随地看视频慕课网APP
我要回答