从另一个组件访问变量/函数

3

我试图通过触碰一个立方体来改变另一个脚本中的变量。

当前设置:

  • 1个玩家
  • 1个敌人

每个角色都有自己的脚本Enemy_StatsCharacter_Stats
正如您在这个小片段中看到的,从另一个脚本访问变量需要相当大的工作量。

void OnCollisionEnter(Collision collision)
{
    if (collision.gameObject.tag == "Enemy")
    {
        collision.gameObject.GetComponent<Enemy_Stats>().Health = 
            collision.gameObject.GetComponent<Enemy_Stats>().Health 
            - gameObject.GetComponent<Character_Stats>().AttackDamage;

        if (collision.gameObject.GetComponent<Enemy_Stats>().Health <= 0)
        {
            Destroy(collision.gameObject);
        }
    }
}

我刚接触Unity,但是难道没有可以像这样引用它的方法吗:
collision.Health

不,因为这是一个碰撞而不是敌人的统计数据。你也不会期望苹果的味道像橙子一样。 - yes
你不能使用Character_Stats作为名称,应该改为CharacterStats。其他情况也是一样的。 - Fattie
即使它不符合语言标准,也不会导致错误。 - yes
4个回答

7

如何从另一个类访问变量/函数。您想要访问或调用的变量或函数必须是public而不是private

public class ScriptA : MonoBehaviour{

    public int playerScore = 0;

    void Start()
    {

    }

    public void doSomething()
    {

    }
}

ScriptB 访问在 ScriptA 中的变量 playerScore。首先,使用 GameObject.Find 函数找到脚本或组件所附加的游戏对象,然后使用 GetComponent 函数检索该脚本或组件。

public class ScriptB : MonoBehaviour{

    ScriptA scriptInstance = null;  

    void Start()
    {
      GameObject tempObj = GameObject.Find("NameOfGameObjectScriptAIsAttachedTo");
      scriptInstance = tempObj.GetComponent<ScriptA>();

      //Access playerScore variable from ScriptA
      scriptInstance.playerScore = 5;

     //Call doSomething() function from ScriptA
      scriptInstance.doSomething();
    }
}

比经常使用 FindGetComponent 更好的方法是简单地创建 [SerializeField] ScriptA scriptInstance; 并通过 Unity 检查器进行拖放引用。 - derHugo

2
由于健康不是碰撞对象的一部分,而是敌人统计数据组件(Enemy_Stats)的一部分,因此不能进行碰撞检测。如果您需要多次使用Enemy_Stats,则可以缓存该组件(这就是Enemy_Stats的作用)。您还可以缓存“已知”组件,例如Player_Stats。您可以在Start函数中或使用公共变量和检查器来实现。虽然对于此示例而言,性能上的提升相对较小,但可以节省不少时间和精力。
不过,您应该让敌人负责自己的生命,而不是由玩家控制,所以请将Destroy部分移动到Enemy_Stats(确切地说是移动到Health属性中)。

正确。Simon,你必须做的是这样的:collision.gameObject.GetComponent<EnemyStats>().TakeDamage(stats.doesDamage) - Fattie
请根据您的需要编写 TakeDamage 程序。 - Fattie
你必须将Enemy_Stats更改为EnemyStats。请注意,你有带大写字母的"AttackDamage"等内容。除非你实际上在使用属性,否则它们必须是小写的。 - Fattie

0

让这段代码更短(最终也会更快)的第一步是在Start()中将gameObject.GetComponent<Character_Stats>()存储在一个私有变量中(如果可以避免,应该避免频繁调用GetComponent)。

对于Health变量,避免使用GetComponent的方法可以是缓存:创建一个Dictionary<GameObject, Enemy_Stats>,并在此游戏对象发生碰撞后立即从其中读取。


最后一部分:在游戏中你不能真正以那种方式进行缓存...因为变化太多了,组件来去匆匆等等。你只需要进行查找,这并不是什么大问题。 - Fattie

0

一开始,在Awake()方法中,你可以找到一个带标记的游戏对象,并获取它的生命值。之后,在Collision()方法中,你只需要减少生命值。但是这里有一个条件,那就是只有一个敌人和一个玩家。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接