Использование компонентов из связанного игрового объекта в скрипте

Извините, если это слишком просто, но я не смог найти ответ на этот вопрос. Обычно вопрос либо слишком сложен, чтобы на него ответить, либо слишком прост, чтобы его не знать.

ЭТО ЧАСТИЧНО ПРОБЛЕМА 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, чтобы я мог использовать его триггеры, чтобы видеоплеер мог делать свое дело. В прикрепленном к нему интерактивном скрипте есть простое логическое значение, которое, я думаю, может сработать, или, может быть, я могу написать свой собственный, проблема в том, что я понятия не имею, как ссылаться на компоненты GameObject. Может быть, я просто не понимаю, но я искал некоторое время, и теперь я обращаюсь к вам, коллективу за помощью...

помощь :(

- Заранее всем спасибо, в проекте есть и другие части, но я подумал, что эти будут наиболее актуальными. Дайте мне знать, если я пропустил что-то нужное.


person Alex Dauenhauer    schedule 29.10.2018    source источник
comment
THIS IS PARTIALLY A UNITY VR/VRTK ISSUE (maybe...) что ты имеешь в виду?   -  person derHugo    schedule 29.10.2018


Ответы (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();
}

Из вашего комментария

Моя основная проблема связана с попыткой получить доступ к скрипту, прикрепленному к другому игровому объекту. В сценарии, который я пишу, он прикреплен к холсту, но я хочу, чтобы он запускался компонентом, который находится внутри другого игрового объекта, не связанного с этим холстом.

Насколько я понимаю, у вас где-то есть «инициирующее событие», скажем, для GameObject ObjectA в классе TriggeringBehaviour, например.

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

и вы хотите, чтобы метод ReactToInteraction вызывался на вашем холсте всякий раз, когда вызывается триггер.

Есть много способов сделать это, но я лично предпочел бы один из следующих:

Решение 1: прямой вызов

Если вы «знаете» свои ссылки, либо ссылаетесь на инспектора, либо имеете какую-либо форму их поиска, например. 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);
    }
}

Таким образом немного проще регистрировать и вызывать события:
in 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 будет отображаться и настраиваться в Инспекторе! (Вы узнаете это по событию onClick кнопки пользовательского интерфейса)
Таким образом, вы можете просто ссылаться на любой другой компонент из инспектора и не должны регистрировать прослушиватели во время выполнения (вы все еще можете сделать это через triggerBahviour.OnTriggered.AddListener()).
Однако UnityEvent немного ограничен. Например. не так просто иметь разные методы, вызываемые с разными сигнатурами, которые имеют несколько или нестандартные параметры (например, ссылки на пользовательские классы).

person derHugo    schedule 29.10.2018
comment
Моя основная проблема связана с попыткой получить доступ к скрипту, прикрепленному к другому игровому объекту. В сценарии, который я пишу, он прикреплен к холсту, но я хочу, чтобы он запускался компонентом, который находится внутри другого игрового объекта, который не связан с этим холстом. - person Alex Dauenhauer; 30.10.2018
comment
Спасибо. Вы дали мне много работы. Я работаю медленно, но плохо вернусь, как только выясню, как мне лучше всего справиться с этим. Обратитесь за помощью. - person Alex Dauenhauer; 02.11.2018

моя цель — настроить триггеры для моего холста, чтобы он мог запускать видеоплеер и включать его и отображать на сцене, когда объект поднимается.

Мой подход к этому будет

  • Создайте холст, добавьте UI> RawImage GO в качестве дочернего элемента холста.
  • Добавьте компонент видеопроигрывателя к необработанному изображению и снимите флажок «Воспроизвести при пробуждении».
  • Создайте актив RenderTexture, измените его размер, может быть, 1920 x 1080?
  • Подключите свой видеоклип и новый ресурс текстуры рендеринга к видеокомпоненту.
  • отключите необработанное изображение GO [вы настроены]

псевдокод объекта

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