Потратил вчера кучу времени на решение простой маленькой задачки. Так забавно, а решение оказалось совсем не очевидным для меня, не смотря на всю простоту Unity и C#. В общем решил поведать об этом здесь. Авось кому да пригодится.
Ну что же начнем!
Представим: у нас есть разные GameObject'ы на сцене. Все они наследуются от класса, предположим, ClickableObjects, который в свою очередь от MonoBehaviour и интерфейса IClickable. В интерфейсе IClickable есть следующие сигнатуры методов: void Active(), void Down(). Итак задача: получив ссылку на объект имеющий в компонентах класс унаследованный от ClickableObjects или его дочерних классов, необходимо вызвать метод Active() или Down(). Вся сложность в том, что мы не знаем какой и классов висит на данном объекте, а метод GetComponent<T>() возвращает ошибку если мы обращаемся к интерфейсу или родительскому классу.
Так, а теперь для наглядности напишу примерный код данной ситуации.
Ну что же начнем!
Представим: у нас есть разные GameObject'ы на сцене. Все они наследуются от класса, предположим, ClickableObjects, который в свою очередь от MonoBehaviour и интерфейса IClickable. В интерфейсе IClickable есть следующие сигнатуры методов: void Active(), void Down(). Итак задача: получив ссылку на объект имеющий в компонентах класс унаследованный от ClickableObjects или его дочерних классов, необходимо вызвать метод Active() или Down(). Вся сложность в том, что мы не знаем какой и классов висит на данном объекте, а метод GetComponent<T>() возвращает ошибку если мы обращаемся к интерфейсу или родительскому классу.
Так, а теперь для наглядности напишу примерный код данной ситуации.
/*
IClickable.cs
*/
public interface IClickable
{
void Active();
void Down();
}
А теперь напишем наш базовый класс ClickableObjects
/*
ClickableObjects.cs
*/
using UnityEngine;
public class ClickableObjects : MonoBehaviour, IClickable
{
public virtual void Active()
{
Debug.Log("Active() - any actions");
}
public virtual void Down()
{
Debug.Log("Down() - any actions");
}
}
Наследуем от него какой-нибудь гипотетический класс DragWindow
/*
DragWindow.cs
*/
using UnityEngine;
public class DragWindow : ClickableObjects, IDragable
{
public override void Active()
{
base.Active();
Debug.Log("Active() - any more actions");
}
public override void Down()
{
base.Down();
Debug.Log("Down() - any more actions");
Drag();
}
public void Drag() { }
}
И для наглядности еще один какой-нибудь класс:
/*
SimpleButton.cs
*/
using UnityEngine;
public class SimpleButton : ClickableObjects
{
public override void Down()
{
Debug.Log("Down() - new any actions");
}
}
Классы SimpleButton и DragWindow мы вешаем на наши GameObject'ы, к которым мы и будем обращаться. Так, а теперь пишем какой-нибудь гипотетический класс из которого мы и произведем обращение.
/*
GuiCamera.cs
*/
using UnityEngine;
[ExecuteInEditMode]
[RequireComponent (typeof(Camera))]
public class GuiCamera : MonoBehaviour
{
private Ray ray;
private RaycastHit hit;
private IClickable obj;
// code code code
private void FixedUpdate()
{
ray = this.camera.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out hit, 20f))
{
/*
Не стоит вникать в сам алгоритм данного класса,
поскольку он является гипотетическим.
Под комментарием главная конструкция,
ради которой и затевалась эта заметка.
Обращаем внимание: пишем -
GetComponent(typeof(IClickable)), вместо
GetComponent <IClickable>() и далее кастуем объект
к IClickable.
*/
obj = (IClickable)hit.transform.GetComponent(typeof(IClickable));
if(obj != null)
obj.Active();
}
}
}
Наверняка, сразу возникнут вопросы почему не SendMessage, или типа: почему не GetComponent <ClickableObject>() и прочие недопонимания. По поводу SendMessage скажу сразу - я считаю, что использовать отправку сообщений на мой взгляд не безопасно и не очень хорошо, к тому же работает это (очень!) медленно. А по поводу попытки вызвать метод получая компонент по имени базового класса: Unity выплюнет ошибку поскольку поиск компонента будет осуществляться по имени базового класса, которого соответственно нет на нашем объекте. Вот и всё, не думаю, что открыл для кого-то Америку, но думаю кому-нибудь да пригодится моя заметочка.
Комментариев нет:
Отправить комментарий