Gamedev Константин Ермолаев
2 658

GUI или как перестать страдать (Unity)

Пример GUI
В закладки
Аудио

Всем привет, первая моя игра умерла сразу после того как я закончил геймплей и перешёл к Интерфейсу. Отсутствие опыта в этом разделе геймдева превратило разработку в АД и проект скоропостижно скончался. Но я не отчаивался, ̶я̶ ̶о̶т̶к̶о̶ф̶е̶в̶а̶л̶с̶я̶, поэтому и пишу данный текст.

GUI - это график юзер интерфейс, в простонародье кнопочки, менюшки, иконки и всякое такое, которое должно переключаться, выбираться, тыкаться и всячески взаимодействовать с игроком и игрой. Казалось бы, что может быть проще? Но на поверке выясняется, что даже простейшая игра содержит в себе огромное количество элементов интерфейса и разнообразного взаимодействия этих элементов.

Даже без половины того что задумано это уже содержит несколько сотен объектов, ориентироваться в которых не так уж и просто, особенно когда они все одновременно находятся на экране. Так вот суть данного поста в простом Трюке, который позволяет скрывать все элементы интерфейса не принадлежащие к текущему логическому, то есть, если мы работаем с Меню выбора уровней, то все остальные меню автоматически скрываются. Этот способ работает как в режиме редактора так и в игре.

Пример использования скрипта

Для того чтобы это работало достаточно в каждый логический раздел интерфейса поместить скрипт StateMachine, который и будет переключать "Режимы" игры. Код StateMachine C #

using UnityEngine.UI; using UnityEditor; #if UNITY_EDITOR [InitializeOnLoad] #endif public class StateMachine : MonoBehaviour { [SerializeField] private GameManager.Mode ThisState; [SerializeField] private GameManager.Mode ThisStateSecond= GameManager.Mode.None; private float speed; bool Fade; [SerializeField] CanvasGroup CG; #if UNITY_EDITOR static StateMachine() { Selection.selectionChanged += SelectionChange; } static void SelectionChange() { if (Selection.activeGameObject && !Selection.activeGameObject.GetComponent<StateMachine>()) return; StateMachine[] stateMachines = FindObjectsOfType<StateMachine>(); for (int i = 0; i < stateMachines.Length; i++) { if (stateMachines[i].OnSelectionChange()) break; } for (int i = 0; i < stateMachines.Length; i++) { stateMachines[i].OnSelectionChange(); } } #endif void Awake() { speed = 0; GameManager.EventChangeState += Onchange; Onchange(); } private void OnDestroy() { GameManager.EventChangeState -= Onchange; } void Onchange() { if (GameManager.Mode.None == ThisStateSecond) { if ((GameManager.State == ThisState)) { Fade = true; } else Fade = false; } else { if (GameManager.State == ThisState || GameManager.State == ThisStateSecond) Fade = true; else Fade = false; } CG.interactable = Fade; CG.blocksRaycasts = Fade; speed = 0; } private void Update() { speed += Time.unscaledDeltaTime; if (Fade == false) { CG.alpha = Mathf.Lerp(CG.alpha, 0, speed); } else { CG.alpha = Mathf.Lerp(CG.alpha, 1, speed); } } #if (UNITY_EDITOR) public bool OnSelectionChange() { bool result = false; if (!Application.isPlaying) { if (Selection.activeGameObject == gameObject) { GameManager.State = ThisState; result = true; } if (GameManager.State == ThisState) { CG.alpha = 1; } else { CG.alpha = 0; } } return result; } #endif }

Используется enum, который отвечает за количество режимов игры, благодаря ему и можно использовать выпадающий список режимов в окне редактора. Скрипт GameManager C #

public static event Action EventChangeState; public enum Mode { Play, Lose, Pause, Resume, MainMenu, ChapterSelection ,Settings, AreYouSure, Achievments, Restart, ChangeQualityLow, ChangeQualityMedium, ChangeQualityHigh, ChangeQualityFantastic, SelectChapterOne, SelectChapterTwo, SelectChapterThree, SelectChapterFour, ExitGame, Yes, No, Fade, None, InventoryInInventory, InvestigateItem, LoadLevel, UseBinocular }

Когда я "изобрёл" данную фича моя жизнь изменилась навсегда. Теперь создание игровых менюшек крайне простое занятие и не ведёт в АД :)

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

PS: скрин из текущей игры в разработке Perfect Valley

Материал опубликован пользователем. Нажмите кнопку «Написать», чтобы поделиться мнением или рассказать о своём проекте.

Написать
{ "author_name": "Константин Ермолаев", "author_type": "self", "tags": ["if","endif"], "comments": 50, "likes": 54, "favorites": 125, "is_advertisement": false, "subsite_label": "gamedev", "id": 56299, "is_wide": false, "is_ugc": true, "date": "Wed, 26 Jun 2019 19:27:37 +0300" }
{ "id": 56299, "author_id": 20106, "diff_limit": 1000, "urls": {"diff":"\/comments\/56299\/get","add":"\/comments\/56299\/add","edit":"\/comments\/edit","remove":"\/admin\/comments\/remove","pin":"\/admin\/comments\/pin","get4edit":"\/comments\/get4edit","complain":"\/comments\/complain","load_more":"\/comments\/loading\/56299"}, "attach_limit": 2, "max_comment_text_length": 5000, "subsite_id": 64954, "last_count_and_date": null }
50 комментариев

Популярные

По порядку

Написать комментарий...
11

GUI это Graphical User Interface, а не Game. Ну и да, fuck GUI. CLI <3

Ответить
9

Всегда удивляюсь понимаю того как понимают машину состояний.
Как я понял из кода вы проходитесь по всем менюхам отключая все и включая только одну.

Тогда причём здесь машина состояний?

Машина состояний работает так, при старте все меню выключены кроме "стартового меню".
Далее, при клике на какую нибудь кнопку выключается открытое "стартовое меню" и включается другое, например "опции" и т д

Если вам приходится в цикле отключать уже отключенное то это не машина состояний.

Идея игры с подземными червями очень понравилась!

Ответить
0

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

Ответить
1

"не в цикле" лучше бы вы этого не писали.

Ответить
2

суть поста не в этом, а в том что есть способ скрывать ненужные объекты интерфейса, в том как это реализовать у всех свои вкусы, о которых спорить не имеет особого смысла

Ответить
3

Так расскажите людям, как еще это можно реализовать, и чем именно этот способ так хорош - может, удобством использования, или высокой оптимизацией?

Пока что за весьма монументальным заголовком скрывается "мои первые шаги в использовании observer, platform-dependent compilation и вводящих в заблуждение именований".
А покуда это так, "спорить не имеет смысла" выглядит, как "не хочу слушать критику"

Ответить
–1

я не для этого писал, повторюсь, обучение программированию на юнити где то в другом месте.

Ответить
2

А что вы будете делать, если глав будет 20?

Ответить
1

Когда будет, тогда и будем решать проблему. Мой способ подходит мне больше всего, это результат моих страданий, если у вас есть более простой и эффективный метод: Welcome в GameDev раздел в качестве автора :)

Ответить
10

Когда будет, тогда и будем решать проблему.

О, классический русский подход

Ответить
4

это классический подход в отсутствии ресурсов на проектирование и называется спиральная разработка:
Спира́льная модель, предложенная Барри Боэмом в 1986 году, стала существенным прорывом в понимании природы разработки ПО. Она представляет собой процесс разработки программного обеспечения, сочетающий в себе как итеративность, так и этапность.
https://ru.wikipedia.org/wiki/%D0%A1%D0%BF%D0%B8%D1%80%D0%B0%D0%BB%D1%8C%D0%BD%D0%B0%D1%8F_%D0%BC%D0%BE%D0%B4%D0%B5%D0%BB%D1%8C

Ответить
3

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

Ответить
2

но сейчас смещение методологий идёт в совершенно другую сторону не просто так.

Разве? Сейчас наоборот фокус на "запуститься как можно раньше с минимальным функционалом", "feature-first", "просто развернем пару виртуалок" итд

Ответить
1

В этом есть смысл. Никогда не рассматривал MVP как Спиральную модель, но выглядит похоже

Ответить
0

MVP

Точно, все никак не мог вспомнить нужный термин.

Ответить
2

это уже демагогия, лично мне этот метод подходит больше всего и он наиболее эффективен

Ответить
0

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

Константин, как ты сделал деформацию земли червем? Бугор и яма после. Идея огонь и графическая сторона реализации тоже хороша! то что код говно - это не главное. лишь бы не тормозила игра и не крашилась.

Ответить
0

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

Ответить
0

а я подумал, что это целиком сделано шейдером. Получается, только цвет менятся. Код можно глянуть? =)
а про оптимизацию - в данном случае и не нужно. И даже, на 20 уровнях тупить врятли будет в момент переключения, тем более, это переходные моменты в которые небольшой лаг не отзовется на игровом процессе.
Со временем сам прийдешь к моменту когда и что лучше оптимизировать, иначе если оптимизировать все подряд, то процесс разработки уйдет в постоянное рекурсивное оптимизирование и надоест. Код должен работать и не меншать пользоваться продуктом, а то что под капотом - какая разница, если никак себя не проявляет.

Ответить
0

код на 1000 строк показывать мало смысла )) там ещё генерация мира вплетена

Ответить
0

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

Ответить
3

лол ты это еще не страдал. Вот, когда не было еще Unity UI, а был только GUI, вот там реально было адово и больно, или плагины юзай или страдай и все через код делай )

Ответить
0

я начинал с NGui :)

Ответить
2

я по хардкору с легаси системой работал)

Ответить
3

Неправильный подход. Делаешь базовый ХУД, все остальные окна и панели - префабами, которые подгружаются динамически. Так даже реадктировать потом легче каждый из них

Ответить
0

Хммммм

Ответить
0

Я наоборот против динамической подгрузки. Все это не так много занимает памяти, что бы не грузить сразу. Отзывчивый интерфейс - он и в африке - отзывчивый интерфейс.

Ответить
0

Поверь. он будет таким же отзывчивым и при подгрузке. Зато сцена, на которой расположен основной префаб UI будет весить мало, либо сам этот префаб.
И во вторых, как я уже говорил, удобство редактирования-изменения. Когда работаешь в команде, нужно сводить количество конфликтов в гите к минимуму.
Еще можно упомянуть. что запихивая все в одну кучу ты нарушаешь всякие заумные принципы ООП, что не есть хорошо

Ответить
0

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

Ответить
0

Не будет ничего лагать, на крайняк делайте пул. Остальные минусы кстати останутся. Как только окон и меню станет много - вы проклянете этот единый префаб

Ответить
0

Господи, мы не в 80 живём. Инстантиэйт небольшого префаба с кусочком интерфейса - это вообще ничего по сравнению с тем, что сцена с этим огромным префабом будет загружаться на несколько секунд дольше. Ни на одном смартфоне выпущенном за последние лет 10 это не будет лагать
Серьёзно, почитайте best practice от разработчиков unity. Сейчас вы сделали корявый костыль, о котором вы неоднократно пожалеете в будущем.
Лучше сделать сразу правильно (а на это не так много времени уйдёт), чем потом матерясь перелопачивать всю систему

Ответить
–3

В хорошей игре должно быть минимум интерфейса

Ответить
7

Симуляторофаги сейчас соком подавились

Ответить
0

А потом посодют за скупку инструкций к ф16

Ответить
0

Хороший симулятор — это не игра а именно симулятор конкретной машины.

И да на самом деле я имел ввиду нечто вроде Dead space -где интерфейс грамотно вплетён в тело игры

Ответить
0

Ну мы не телепаты тут, чтоб понять что ты имел ввиду.

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

Ответить
0

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

Ответить
2

* Paradox Interactive присоединяется к комнате *

Ответить
0

Кхм. Aurora 4X. Кхм-кхм.

Ответить
–7

Хорошие игры на unity и не делают

Ответить
2

Какой же это недальновидный костыль

Ответить
0

Учитывая что Unity очень неплохо реализует принципы ООП и можно сделать по - разному комментарии аля "костыль" и "неверный подход", как мне кажется, не уместны. Каждой задаче свое решение. Автору спасибо, статью в закладки.

Ответить
0

Для начинающих можно пользоваться разными решениями, но все таки лучше сразу учиться делать правильно

Ответить
0

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

Ответить
0

ну примерно так и есть у нас, только ещё есть сюжетка сингловая

Ответить
0

Это что, игра по вселенной франшизы "Дрож земли" ? Смотри как ты на тебя в суд не подали =)

Ответить
0

От конечного автомата тут мало что есть. Кроме того, код автомата привязан к изменению свойств объекта - меняется только прозрачность. Лучше было сделать что-то наподобие такого: https://pastebin.com/PqYM9ngS. Это во-первых. Во-вторых, при таком количестве состояний я бы задумался о выделении подавтоматов. И небольшая придирка: почему бы не менять прозрачность объектов в корутине?

Ответить
0

А я canvas flow использую. Очень удобно и быстро. А контроллер машинки сами писали?

Ответить
0

для другого проекта писали, а сейчас стандартный с некоторыми твиками

Ответить
0

Понятно, а чего не смотрели на сторонее решение? Они не так дорого стоит а ощущается отлично. ИМХО Хотел еще спросить чем делаете гифки

Ответить
0

Прямой эфир

{ "remaining": "WzAsMSwyLDMsNCw1LDYsNyw4LDld" } [ { "id": 1, "label": "100%×150_Branding_desktop", "provider": "adfox", "adaptive": [ "desktop" ], "adfox_method": "createAdaptive", "auto_reload": true, "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "clmf", "p2": "ezfl" } } }, { "id": 2, "label": "1200х400", "provider": "adfox", "adaptive": [ "phone" ], "auto_reload": true, "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "clmf", "p2": "ezfn" } } }, { "id": 3, "label": "240х200 _ТГБ_desktop", "provider": "adfox", "adaptive": [ "desktop" ], "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "clmf", "p2": "fizc" } } }, { "id": 4, "label": "240х200_mobile", "provider": "adfox", "adaptive": [ "phone" ], "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "clmf", "p2": "flbq" } } }, { "id": 5, "label": "300x500_desktop", "provider": "adfox", "adaptive": [ "desktop" ], "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "clmf", "p2": "ezfk" } } }, { "id": 6, "label": "1180х250_Interpool_баннер над комментариями_Desktop", "provider": "adfox", "adaptive": [ "desktop" ], "adfox": { "ownerId": 228129, "params": { "pp": "h", "ps": "clmf", "p2": "ffyh" } } }, { "id": 7, "label": "Article Footer 100%_desktop_mobile", "provider": "adfox", "adaptive": [ "desktop", "tablet", "phone" ], "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "clmf", "p2": "fjxb" } } }, { "id": 8, "label": "Fullscreen Desktop", "provider": "adfox", "adaptive": [ "desktop", "tablet" ], "auto_reload": true, "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "clmf", "p2": "fjoh" } } }, { "id": 9, "label": "Fullscreen Mobile", "provider": "adfox", "adaptive": [ "phone" ], "auto_reload": true, "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "clmf", "p2": "fjog" } } }, { "id": 10, "label": "Native Partner Desktop", "provider": "adfox", "adaptive": [ "desktop", "tablet" ], "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "clmf", "p2": "fmyb" } } }, { "id": 11, "label": "Native Partner Mobile", "provider": "adfox", "adaptive": [ "phone" ], "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "clmf", "p2": "fmyc" } } }, { "id": 12, "label": "Кнопка в шапке", "provider": "adfox", "adaptive": [ "desktop", "tablet" ], "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "clmf", "p2": "fdhx" } } }, { "id": 13, "label": "DM InPage Video PartnerCode", "provider": "adfox", "adaptive": [ "desktop", "tablet", "phone" ], "adfox_method": "createAdaptive", "adfox": { "ownerId": 228129, "params": { "pp": "h", "ps": "clmf", "p2": "flvn" } } }, { "id": 14, "label": "Yandex context video banner", "provider": "yandex", "yandex": { "block_id": "VI-250597-0", "render_to": "inpage_VI-250597-0-1134314964", "adfox_url": "//ads.adfox.ru/228129/getCode?pp=h&ps=clmf&p2=fpjw&puid1=&puid2=&puid3=&puid4=&puid8=&puid9=&puid10=&puid21=&puid22=&puid31=&puid32=&puid33=&fmt=1&dl={REFERER}&pr=" } }, { "id": 15, "label": "Плашка на главной", "provider": "adfox", "adaptive": [ "desktop", "tablet", "phone" ], "adfox": { "ownerId": 228129, "params": { "p1": "byudo", "p2": "ftjf" } } }, { "id": 17, "label": "Stratum Desktop", "provider": "adfox", "adaptive": [ "desktop" ], "auto_reload": true, "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "clmf", "p2": "fzvb" } } }, { "id": 18, "label": "Stratum Mobile", "provider": "adfox", "adaptive": [ "tablet", "phone" ], "auto_reload": true, "adfox": { "ownerId": 228129, "params": { "pp": "g", "ps": "clmf", "p2": "fzvc" } } } ]
Уве Болл вернулся в кино
и начал экранизировать flash-игры
Подписаться на push-уведомления