为了账号安全,请及时绑定邮箱和手机立即绑定

如何正确检测游戏对象?

如何正确检测游戏对象?

C#
holdtom 2022-07-10 16:14:16
我的目标是编写一个脚本,我可以在不同的游戏对象上使用它,并且它应该只在该游戏对象上绑定特定的变量,而不影响过程中的其他脚本。例如,如果我把这个脚本放在两个游戏对象上,每个游戏对象在同一个脚本中应该有自己唯一的变量值。如果我的问题不够清楚,我很乐意进一步阐述。我对 Unity 编辑器有很好的理解,但是,我对 C# 还很陌生,所以我认为我在代码的某个地方犯了一个菜鸟错误并不是不合理的。我设置东西的方式是我有两个单独的脚本:Fighting控制像Team, Health, Attack Damage, Cool Down,Cooling down和SnapTrigDetect控制对因敌人进入触发范围而激活的触发器的检测。我目前遇到的问题在于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;                }
查看完整描述

2 回答

?
冉冉说

TA贡献1877条经验 获得超1个赞

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

替换这个:

    GameObject g = GameObject.Find("Detection");
    Fighting fScript = g.GetComponent<Fighting>();

有了这个:

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


查看完整回答
反对 回复 2022-07-10
?
呼唤远方

TA贡献1856条经验 获得超11个赞

对于您的问题标题:


每个 instaced(非静态)值对于相应的组件都是唯一的,因此对于GameObject它所附加的相应组件来说也是唯一的。您可能想重新提出这个问题,因为这实际上不是您的问题。


问题是当你这样做时


GameObject.Find("Detection");

它实际上两次都找到了相同的对象:即层次结构中的第一个对象。因此,在两个组件之一中,您可以找到自己的空对象并跳过其余部分


if(self.Team != FScript.Team) 

..你可以尝试使用


other.Find("Detection");

而是仅在相应的上下文中搜索..但是,您根本不应该使用Find!


这是非常激烈的表现

您应该始终重复使用参考,而不是一遍又一遍地搜索它们

在你的情况下你不需要它


由于您说两个脚本都附加到同一个对象,您可以简单地使用


GetComponent<Fighting>();

你可以这样做Awake并重用参考:


private Fighting myFighting;


private void Awake()

{

    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 this

var 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 

{

    public int Team = 1;

    public int Health = 100;

    public int AttackDamage = 10;

    public float CoolDown = 2;

    public float original = 2;


    // you don't need that flag see below

    //public bool CoolingDown = false;

    public bool Snap = false;


    private void Update()

    {

        // you might also put this in a callback instead of update at some point later

        if(Snap == true)

        {

            Destroy(transform.parent.gameObject);

        }


        // Note: this also makes not muh sense because if you destroyed

        // the parent than you cannot instantiate it again!

        // use a prefab instead

        if (Input.GetKey(KeyCode.N)) Instantiate(transform.parent.gameObject);

    }


    public void TakeDamge(int DamageAmount)

    {

        Health -= DamageAmount;


        if (Health > 0) return;


        Destroy(transform.parent.gameObject);

    }

}

一般的另一个性能问题:即使Start, Updateetc 是空的,如果它们存在于您的脚本中,Unity 也会调用它们。因此,如果您不使用它们,请完全删除它们以避免无用的开销。


所以我会


触发检测


using System.Collections;

using System.Collections.Generic;

using UnityEngine;


public class TrigDetect : MonoBehaviour

{

    bool once = false; 


    private Fighting myFighting;


    private void Awake()

    {

        myFighting = GetComponent<Fighting>();

    }


    void OnTriggerStay(Collider other)

    {

        // if wrong tag do nothing

        if (!other.CompareTag("Troop")) return;


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


        // here you should add a check

        if(!fScript)

        {

            // By using the other.gameObject as context you can find with which object

            // you collided exactly by clicking on the Log

            Debug.LogError("Something went wrong: Could not get the Fighting component of other", other.gameObject);

        }


        if (!once)

        {

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

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

            once = true;

        }


        // if same team do nothing

        if (self.Team == fScript.Team) return;


        // you don't need the CoolingDown bool at all:

        self.CoolDown -= Time.deltaTime;


        // if still cooling down do nothing

        if(self.CoolDown > 0) return;


        fScript.TakeDamage(self.AttackDamage);

        self.CoolDown = self.original;

    }

}



查看完整回答
反对 回复 2022-07-10
  • 2 回答
  • 0 关注
  • 99 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信