【问题标题】:How to: Get instance of gameObject如何:获取游戏对象的实例
【发布时间】:2019-05-07 16:06:39
【问题描述】:

希望获得此游戏对象的实例,以便成功使用 .enabled 将其隐藏在场景中。

PlayPortalLoginButton loginButton = gameObject.GetComponent<PlayPortalLoginButton>();

对 C# 相当陌生,我相信我已经接近实现上述目标的目标。什么需求变了?想了解如何正确执行此操作。

【问题讨论】:

  • 上面那行表明你已经拥有了游戏对象。
  • @Eddge 我引用了游戏对象,但我需要引用上面游戏对象的实例。不是原来的游戏对象
  • 我觉得这里有误会。所有 MonoBehavior 都使用 gameObject 变量引用其游戏对象。所以,在这种情况下,你说GetComponent&lt;T&gt;() 使用gameObject。组件 gameObject 将是相同的。现在,如果您的意思是要获取另一个 GameObject 上的 PlayPortalLoginButton 的 MonoBehavior,您可能需要使用 FindObjectOfType,或者甚至为该脚本提供对该对象的公共引用。
  • GetComponent 仅获取此游戏对象上该类型的组件,而不获取场景中其他对象上该类型的组件。这就是您使用 FindObjectOfType 的原因。
  • 或 GameObject.Find 或其中的各种组合。

标签: c# unity3d gameobject


【解决方案1】:

这是您可以在场景中的GameObject 上找到组件的一种方法,其中“PortalLoginButton”是编辑器中看到的GameObject 的名称:

var loginButton = GameObject.Find("PortalLoginButton");
loginButton.enabled = false;

但是,GameObject.Find("...") 会搜索场景中每个 GameObject 的名称,这通常不是引用 GameObject 的最佳方式,因为它效率不高。 所以请确保不要在 Update() 函数中使用 GameObject.Find("...") 或类似的函数调用,因为它会执行每一帧并减慢您的游戏速度。如果在游戏运行时GameObject 未实例化,通常最好对您在脚本中使用的任何GameObjectComponent 进行全局引用,然后将GameObject 拖放到Component 您正在编辑器中的字段中查找。或者,您可以在 Start()Awake() 函数中使用 GameObject.Find("...") 来存储对您正在查找的 GameObject 的引用,这样搜索只会在游戏开始时发生一次。

这是一个如何在全局字段中存储引用的示例(它将显示在编辑器中,您可以将 GameObject 拖放到其中)。 cmets 中解释了使用公共字段与私有字段之间的区别(您可以决定使用公共字段还是私有字段):

// By default, private fields are not viewable in the editor,
// but the [SerializeField] attribute, placed before
// the field declaration, allows them to be visible.
[SerializeField]
private GameObject loginButtonPrivateReference;
// If you need to access loginButton from another script, 
// you can make it a public field.
// Public fields are viewable in the editor by default.
public GameObject loginButtonPublicReference;

以下是如何在Awake() 函数中使用 GameObject.Find("...") 的示例:

private GameObject loginButton;

private void Awake() {
    loginButton = GameObject.Find("PortalLoginButton");
}

如果您需要在场景中按类型或标签名称搜索GameObjects,请参阅GameObject 文档here 了解更多信息。按类型搜索效率较低,而按标签搜索比按名称搜索效率更高,因为类型搜索会检查每个 GameObject 上的每个组件,而标签搜索仅搜索有组织的 GameObject 子集。

【讨论】:

    【解决方案2】:
    GameObject button;
    void Start() {
        button = GameObject.Find ("yourButtom");
    }
    void SomeEvent() {
        button.SetActive(false);   
    }
    

    我认为你必须帮助你

    【讨论】:

    • 这克隆了一个预制件,按钮可能已经存在于场景中
    【解决方案3】:

    有几种方法可以访问脚本中的游戏对象,具体取决于您尝试获取的游戏对象。

    如果您尝试在行为脚本中访问某个行为的游戏对象,那么只需使用gameObject 就足够了,因为那是行为所附加到的游戏对象。

    访问附加到另一个游戏对象的脚本可能会很棘手。对于MainMenu这样的场景,给它一个公共引用作为例子并没有错:

    public PlayPortalLoginButton loginButton;
    
    void setLoginState(bool activate) {
        loginButton.enabled = activate;
    }
    

    在此示例中,您只需将带有 PlayPortalLoginButton 脚本的游戏对象拖放到管理器脚本上,该脚本将控制是否启用它。

    如果您需要更模块化的方法,例如在运行时填充对象的游戏场景中,您可以采用的方法是:

    PlayPortalLoginButton loginButton;
    
    void setLoginState(bool activate) {
        if(loginButton == null)
        {
            loginButton = FindObjectOfType<PlayPortalLoginButton>();
        }
        // Requires the correct version of .net otherwise you can reuse the check above...
        loginButton?.enabled = activate;
    }
    

    以上脚本中如果需要loginButton的gameObject,现在可以通过loginButton.gameObject来访问。

    还有一些您可以使用的示例和其他方法,但我认为如果用于菜单,以上内容就足够了。

    我还要提到我正在避免使用GameObject.FindGameObject.FindGameObjectsWithTag 的示例,因为它们更容易出错。它们仅在正确标记您的名称或标签时才有效,如果您出于任何原因重命名它们,那么您的脚本将无法找到对象,这可能会导致故障排除问题。

    使用 FindObjectOfType,您不太可能出现错误,如果您删除该脚本类型,这些脚本将填充错误,指示该脚本不再存在。重构时,如果您右键单击行为名称并使用重命名选项,它将自动更新整个代码中对脚本的引用。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-20
      • 1970-01-01
      • 2022-01-14
      • 2016-02-16
      相关资源
      最近更新 更多