Использование компонентов из связанного gameObject в скрипте
Извините, если это слишком просто, но я не смог найти ответ на этот вопрос. Обычно либо вопрос слишком сложен для ответа, либо слишком прост, чтобы не знать.
ЭТО ЧАСТИЧНО ПРОБЛЕМА ЕДИНСТВА 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, чтобы я мог использовать его триггеры, чтобы видеоплеер мог делать свое дело. Существует простой bool в прилагаемом скрипте Interactible, который, я думаю, может сработать или, может быть, я могу написать свой собственный, проблема в том, что я не знаю, как ссылаться на компоненты GameObject. Может быть, я просто не понимаю, но я некоторое время искал, и теперь я обращаюсь к вам, коллективу за помощью...
Помогите:(
-Спасибо всем заранее, в проекте есть еще кусочки, но я подумал, что они будут наиболее актуальными. Дайте мне знать, если я пропустил что-то необходимое.
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);
}
}
Таким образом, немного проще зарегистрироваться и вызвать события:
в 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
будет отображаться и настраиваться в Инспекторе! (Вы узнаете это по событию Button onIll пользовательского интерфейса)
Таким образом, вы можете просто ссылаться на любой другой компонент из инспектора и не нужно регистрировать прослушиватели во время выполнения (вы все еще можете сделать это через triggerBahviour.OnTriggered.AddListener()
).
тем не мение UnityEvent
вид ограничен. Например, не так просто иметь разные методы, вызываемые с разными сигнатурами, которые имеют несколько или нестандартные параметры (например, пользовательские ссылки на классы).
Моя цель - настроить триггеры, чтобы мой Canvas мог запускать видеопроигрыватель, включать и отображать его в сцене при поднятии объекта.
Мой подход к этому был бы
- Создайте холст, добавьте пользовательский интерфейс> RawImage GO как дочерний элемент холста
- Добавьте компонент видеопроигрывателя к необработанному изображению и снимите флажок "Play on Awake".
- Создать ресурс RenderTexture, изменить его размер, может быть, 1920 x 1080?
- Подключите свой видеоклип и новый актив текстуры рендеринга к компоненту видео
- отключить необработанное изображение GO [все готово]
псевдокод для объекта
if object is picked up (on collision enter?)
turn on raw image GO (setActive)
rawImage.getComponent<videoPlayer>().Play()