在脚本中使用链接的gameObject中的组件

时间:2018-10-29 06:12:29

标签: unity3d vrtk unity-components

对不起,如果这太简单了,但是我还没有找到答案。通常,这个问题要么太复杂而无法回答,要么太简单而又不知道。

这部分是一个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脚本中附上一个简单的bool,或者我可以编写自己的脚本,问题是我不知道如何从GameObject组件中进行引用。也许我只是不理解它,但我看了一段时间,现在我向您寻求帮助的集体...

帮助:(

-感谢所有人,该项目还有更多内容,但我认为这些内容最相关。让我知道我是否错过了需要的东西。

2 个答案:

答案 0 :(得分:2)

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

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

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

如果您希望将与相同 GameObect相连的组件作为提供的脚本,请改用

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

或者,如果您想从asset GameObject的使用中获取组件,则

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

比您可以添加一个公共方法来在与GameObject进行“交互”(无论如何)时调用它

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

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

根据您的评论

  

我的主要问题在于尝试访问附加到其他游戏对象的脚本。在编写脚本的脚本中,我将其附加到画布上,但我希望它由与该画布无关的另一个游戏对象内部的组件触发。

我了解您在某处发生“触发事件”,例如在类ObjectA的GameObject TriggeringBehaviour上说

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

,并且您希望在每次调用触发器时在画布上调用方法ReactToInteraction

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

解决方案1:直接致电

如果您“知道”自己的参考文献,则可以在检查器中进行参考,也可以采用某种形式,例如使用Singleton或FindObjectOfTypeFind(按名称)等,您可以直接从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(我个人的最爱)

或者,您也可以在UnityEvent中实现TriggeringBehaviour

public event Action OnTriggered;

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

    OnTriggered.Invoke();
}

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

答案 1 :(得分:2)

  

我的目标是为Canvas设置触发器以能够启动   视频播放器并启用它并在对象出现在场景中时   正在被捡起。

我的解决方法是

  • 创建画布,添加UI> RawImage GO作为画布的子代
  • 将视频播放器组件添加到原始图像,然后取消选中“在 醒来
  • 创建一个RenderTexture资产,将其大小更改为1920 x 1080吗?
  • 将视频剪辑和新的渲染纹理资源插入视频 组件
  • 关闭原始图像[已设置]

对象的伪代码

 if object is picked up (on collision enter?)
   turn on raw image GO (setActive)
   rawImage.getComponent<videoPlayer>().Play()