Как стать автором
Обновить

Когда в Unity нужно MVC, как сделать Binding визуальных контроллов с методом

Время на прочтение4 мин
Количество просмотров4.6K

В прошлой статье в частности я критиковал, что при создании игр неумело используют технологию MVC. Нет, я не заядлый критик чего бы то не было, просто я не люблю когда подход или технологию применяют тогда, когда она не нужна. В этой статье, я расскажу один пример, когда эта технология просто необходима. Но внимание - для её реализации вам не нужен никакой фреймфорк, если вы еще не верите в свои силы - я научу вас создавать элегантные решения с минимумом трудозатрат, и тогда когда это нужно :)

По ссылке "Когда нужно MVC, как сделать Binding визуальных контроллов с методом (UNITY, C#, Разработка игр)" вы можете послушать меня, а кто хочет почитать прошу подкат.

Первое условие: у вас в игре хотя бы две сцены: главное меню и собственно игра.

Второе условие: вы не хотите в сценах дублировать какую-то часть своего GUI (графического интерфейса пользователя). Наверно, вы захотите, чтобы выбор настроек, возможность локализации (смены языка), управление сохранениями, может быть какие-то диалоги были бы доступны из любой из этих двух сцен.

Третье условие: вы хотите разгрузить сцены от не нужной логики. Возможно, у вас в главном меню будет кат-сцена, или сложный сценарный диалог, а в игровой сцене это все не нужно. Вам просто, когда потребуется нужно вернутся обратно в главное меню.

Где здесь проблемка? По умолчанию, при смене сцены, все что там было удаляется. Но есть возможность, использовать метод юнити DontDestroyOnLoad (о нем можно найти в документации или на моем же канале), но я думаю все кто читает более сложные темы об этом знают и мы идем дальше.

Но вы же не хотите (согласно третьему условию) всю сцену переносить внутрь второй, вы, наоборот, хотите переносить только необходимое. Но это означает, что на новой сцене о атрефактах с прошлой сцены никто не знает (с этим еще можно жить), а оставшиеся артефакты не знают, кто им заменит функциональность, которая была в прошлой сцене. Например, в главном меню, настройки вызывались по какой то "эпичной" кнопке, а в игровой сцене по "простой" кнопке меню паузы. Или если какую фоновую музыку сейчас проигрывать в главном меню решал сценарий диалога, то в игровой сцене, будут решать другие геймплейные объекты. Но они должны друг друга найти. И в случае большего количества сцен это может быть еще больше нелинейно.

MVC как таковой, выполненный без биндинга, на уровне поддержки фреймворка, совершенно устарел, может быть лишь теорией. Если вы попробуете реализовать MVC согласно Фаулеру (у него есть пример для языка Java), то на это без слез не взглянешь. Он приводил его в качестве теоретического примера, а не как руководство к действию. Фреймворки с биндингом из известных - это WPF и ASP.NET (о качестве их разговор отдельный, но он есть).

Но так ли сложно реализовать этот биндинг самому? А ведь он нужен в Юнити. Оказывается, это сравнительно просто. Проще, чем реализовывать в ручную MVC для 3 классов.

Для этого мы возьмем UnityEvent

[System.Serializable]
public class BindingEvent
{
	public string Name;
	public UnityEvent Event;
}

исключительно, чтобы из редактора было легко задать единственный метод (нам не нужна функциональность событий в реальности, тем более для событий удобнее использовать реальные события event).

И создадим класс, описывающий с кем же мы будем связываться. А связывать нам поведение нужно с визуальным контроллом. И еще раз напомню, что технология MVC нужна только для связи визуального представления с бизнес-логикой.

[System.Serializable]
public class BindingBehavior
{ 
	public string Name;
	public Button Button;
}

Намерено упрощаю здесь код, чтобы он был элементарен и не содержал сложностей имеющихся в реальности. Все нюансы, показаны в ролике.

Теперь нам нужно создать класс ответственный за биндинг:

public class BindingUI : MonoBehaviour
{
	// Список визуальных элементов
	public List<BindingBehavior> BindingBehavior;
	// Список методов
  public List<BindingEvent> BindingEvent;
	// Партнер для связывания
	private BindingUI Related;

	// Найти партнера в зависимости от сцены
	public BindingUI GetRelated()
	{
		BindingUI ret = null;
    ...
		return ret;
	}
}

Все, что нам нужно связать, мы дадим возможность разработчику настроить без кода, тягая лишь ссылки в редакторе юнити.

И для фреймворка останется реализовать собственно лишь связывание:

	private void Bind()
	{
    // Для каждого визуального контрола поищем метод, с которым его надо связать
		for (int i = 0; i < BindingBehavior.Count; i++)
		{
			BindingEvent eventContainer = null;
      if (Related != null)
      {
        if (IsDoneBinding(BindingBehavior[i].Name) == false)
        {
          eventContainer = Related.GetBindingEvent(BindingBehavior[i].Name);
          AddDoneBinding(BindingBehavior[i].Name);
        }
      }
			if (eventContainer != null)
			{
				BindEvent(BindingBehavior[i], eventContainer);
			}
		}
		if (Related != null)
		{
      // Для каждого метода, поищем визуальный контрол, который не знает как себя вести
			for (int i = 0; i < BindingEvent.Count; i++)
			{
				if (IsDoneBinding(BindingEvent[i].Name) == false)
				{
					BindingBehavior behaviorContainer;
					behaviorContainer = Related.GetBindingBehavior(BindingEvent[i].Name);
					if (behaviorContainer != null)
					{
						BindEvent(behaviorContainer, BindingEvent[i]);
						AddDoneBinding(BindingEvent[i].Name);
					}
				}
			}
		}
	}

	// собственно связывание
	private void BindEvent(BindingBehavior argBehavior, BindingEvent argEvent)
	{
		if (argBehavior.Button != null && argEvent.Event != null)
		{
			UnityEvent locEvent = argEvent.Event;
			argBehavior.Button.onClick.AddListener(argEvent.Event.Invoke);
		}
	}

Здесь я опускаю реализацию методов IsDoneBinding и AddDoneBinding, их легко реализовать как вам захочется. Просто нужно помнить, что реализация биндинга должна быть устойчива к многократным вызовам и не создавать лишних связываний. А поэтому надо следить был ли биндинг уже выполнен и не нужно ли его обновить, например, после смены сцены.

Вот и все сложности. Надеюсь, хоть на день упростил вам программирование :)

Теги:
Хабы:
Всего голосов 6: ↑2 и ↓4-2
Комментарии17

Публикации

Истории

Работа

Ближайшие события

One day offer от ВСК
Дата16 – 17 мая
Время09:00 – 18:00
Место
Онлайн
Конференция «Я.Железо»
Дата18 мая
Время14:00 – 23:59
Место
МоскваОнлайн
Антиконференция X5 Future Night
Дата30 мая
Время11:00 – 23:00
Место
Онлайн
Конференция «IT IS CONF 2024»
Дата20 июня
Время09:00 – 19:00
Место
Екатеринбург
Summer Merge
Дата28 – 30 июня
Время11:00
Место
Ульяновская область