首页 > 解决方案 > 在脚本中使用来自链接游戏对象的组件

问题描述

抱歉,如果这太简单了,但我无法找到答案。通常,问题要么太复杂而无法回答,要么太简单以至于不知道。

这部分是 UNITY VR/VRTK 问题(也许......)

无论如何,我的目标是为我的 Canvas 设置触发器,以便能够启动视频播放器并使其启用并在拾取对象时出现在场景中。到目前为止,除了我能够在玩家与游戏对象交互时触发这两个动作之外,一切都已就绪。

在我的脚本中,我有:

public VideoPlayer videoPlayer;
public Canvas canvas;
public GameObject asset;
    void Awake ()
{
    videoPlayer.GetComponent<VideoPlayer>();
    canvas.GetComponent<Canvas>();

}

private void Start()
{
    videoPlayer.Pause();
    canvas.enabled = !canvas.enabled;


}

很简单,但一切都在统一中联系在一起,而且很有趣。我的问题是我试图引用 GameObject 上的脚本,以便我可以使用它的触发器来使视频播放器能够执行它的操作。在附加的 Interactible 脚本中有一个简单的布尔值,我认为它可能有效,或者我可以自己编写,问题是我不知道如何从 GameObject 组件中引用。也许我只是不理解它,但我看了一段时间,现在我转向你,集体寻求帮助......

帮助 :(

-在此先感谢大家,该项目还有更多内容,但我认为这些将是最相关的。如果我错过了需要的东西,请告诉我。

标签: unity3dvrtkunity-components

解决方案


我真的不明白你的最终目标是什么,但这两行

videoPlayer = videoPlayer.GetComponent<VideoPlayer>();
canvas = canvas.GetComponent<Canvas>();

没有多大意义。您要么已经拥有引用(例如来自检查器)而不是您不需要再次获取组件,或者您想从 GameObject 获取它们

如果您希望将组件附加到与提供的脚本相同的GameObect,请使用

videoPlayer = GetComponent<VideoPlayer>();
canvas = GetComponent<Canvas>();

或者,如果您更想从assetGameObject 中获取组件,请使用

videoPlayer = asset.GetComponent<VideoPlayer>();
canvas = asset.GetComponent<Canvas>();

比你可以添加一个公共方法来调用它每当与游戏对象“交互”(无论看起来如何)

public void ReactToInteraction()
{
    // E.g.

    canvas.enabled = true;
    videoPlayer.Play();
}

从你的评论

我的主要问题围绕着尝试访问附加到不同游戏对象的脚本。在我正在编写的脚本中,我将它附加到画布上,但我希望它由位于与此画布无关的不同游戏对象内部的组件触发。

ObjectA我知道你在某个地方有一个“触发事件”让我们在一个类中的 GameObject 上说,TriggeringBehaviour例如

void OnTriggerEnter(Collider col)
{
    //...
}

并且您希望ReactToInteraction在调用触发器时在画布上调用一个方法。

有很多方法可以做到这一点,但我个人更喜欢以下方法之一:

解决方案一:直接调用

如果您“知道”您的引用,无论是在检查器中引用还是使用 Singleton 或FindObjectOfType, Find(按名称)等以某种形式找到它们,您都可以直接从以下位置调用该方法TriggeringBehaviour

// todo get this somehow with the known methods
public CanvasBehaviour ReferenceToYourCanvasScript;

void OnTriggerEnter(Collider col)
{
    //...

    ReferenceToYourCanvasScript.ReactToInteraction;
}

解决方案2:事件动作

TriggeringBehaviour您可以使用例如实现自定义事件

public event Action OnTriggered;

void OnTriggerEnter(Collider col)
{
    //...

    if(OnTriggered!=null)
    {
        OnTriggered.Invoke();
    }
}

比你必须在你的CanvasBahviour

private void Start()
{
    //TODO somehow get the according reference e.g.
    var triggerBahviour = FindObjectOfType<TriggeringBahviour>();

    // and add the listener
    // it is save to remove the listener first -> makes sure it is only registered once
    triggerBahviour.OnTriggered -= ReactToInteraction;
    triggerBahviour.OnTriggered += ReactToInteraction;

    // after that whenever OnTriggered is invoked, ReactToInteraction will be executed
}

或者,您也可以创建一个静态类来处理这些事件

public static class TriggerEvents
{
    // I leave this as example on how to give it parameters
    public static event Action<TriggerBehaviour> OnTriggeredBy;

    public static event Action OnTriggered;

    public static void InvokeOnTriggered()
    {
        if(OnTriggered!=null) OnTriggered.Invoke();
    }

    public static void InvokeOnTriggeredBy(TriggeringBehavior by)
    {
        if(OnTriggeredBy!=null) OnTriggeredBy.Invoke(by);
    }
}

通过这种方式,注册和调用事件会更容易一些:
TriggerBehaviour

void OnTriggerEnter(Collider col)
{
    //...
    TriggerEvents.InvokeOnTriggered();

    // or if you want to also check who triggered
    // TriggerEvents.InvokeOnTriggeredBy(this);
}

并且在CanvasBehaviour

void Start()
{
    TriggerEvents.OnTriggered -= ReactToInteraction;
    TriggerEvents.OnTriggered += ReactToInteraction;

    // or if you want to checl who triggered
    // TriggerEvents.OnTriggeredBy -= ReactToInteractionBy;
    // TriggerEvents.OnTriggeredBy += ReactToInteractionBy;
}

// In case you need the ReactToInteractionBy
// has to have the same signature as defined by the Action
void ReactToInteractionBy(TriggeringBehaviour triggerer)
{
    // ...
}

这非常灵活,还可以传递您想要/需要的任意数量的参数(在这种情况下无论如何都没有)。但是,您仍然必须以某种方式获得对正确组件的相应引用。
一个很大的缺陷是注册,尤其是在不取消注册的情况下销毁某些东西会导致错误并且非常令人沮丧。

解决方案3:UnityEvent(我个人最喜欢的)

或者,您也可以实现一个UnityEventinTriggeringBehaviour

public event Action OnTriggered;

void OnTriggerEnter(Collider col)
{
    // ...

    OnTriggered.Invoke();
}

最大的优点是这UnityEvent将在 Inspector 中显示和配置!(您会从 UI Button onClick 事件中识别它)
因此您可以从检查器中引用任何其他组件,而不必在运行时注册侦听器(您仍然可以通过 来注册triggerBahviour.OnTriggered.AddListener())。
但是UnityEvent有点有限。例如,使用具有多个或非标准参数(例如自定义类引用)的不同签名调用不同的方法并不是那么简单。


推荐阅读