Graff46 598 Опубликовано 3 Февраля 2019 (изменено) Тема посвещена аспектам работы и построению GUI Интерфейсов (оконные классы) в играх серии "Сталкер" Описание методов создания GUI интерфейсов от @Malandrinus Скрытый текст Начнём с того, что все задачи по работе с интерфейсом сводятся к двум: вывод и ввод. Сразу разделим наши задачи на два принципиально разных режима, в которых может находиться игра. Первый режим назовём игровым. В этом режиме игрок управляет персонажем в трехмерном мире. При этом ввод от мыши и клавиатуры полностью работает на управление пресонажем. Соответственно, вопрос о задаче ввода в этом режиме не стоит вообще. К сожалению, разработчики не оставили возможности добавить в этом режиме скриптовую реакцию на свои кнопки. Как-то этот вопрос решается, но сейчас об этом не будем. Итак, в игровом режиме можно только создавать на экране поверх трёхмерного изображения свои элементы. Взаимодействовать с ними будет невозможно. Второй режим назовём диалоговым. Это режим для главного меню, встроенных диалогов вроде инвентаря и пользовательских диалогов. В этом режиме открывается окно, которое полностью перехватывает управление мышью и клавиатурой. Соответственно, в этом режиме можно организовать ввод своих данных и реагировать на действия с мышой. События в игровом мире при этом могут остановиться (в главном меню) или продолжаться своим чередом (во всех остальных случаях). Начнём с игрового режима и для начала определимся с терминологией. В этом режиме игрок видит перед собой трёхмерную картинку происходящего и так называемый худ (HUD = heads-up display, ведет происхождение от интерфейса военных самолетов, при котором информация отображается на стекле обзора, что позволяет не опускать голову на приборы, т.е. голова остается поднятой (англ. "head up")). Причём, элементами худа являются в том числе руки и предмет, который актор крутит в руках. Эти объекты по своей природе трёхмерны и в этом движке на них влиять нельзя (а было бы неплохо на самом-то деле управлять, скажем, изображением на экране детектора, который находится в руках у актора в ЧН и ЗП). Так что в дальнейшем мы будем говорить о худе, имея в виду только плоские элементы интерфейса: индикаторы здоровья, оружия, слотов, миникарта и прочее в этом роде. Если точнее, будем называть худом ту прозрачную плоскость на которой все эти элементы расположены. Если это движковые элементы, то управлять ими можно только в плане скрыть/показать, и только все разом. Однако, при этом можно добавить своих элементов и уже с ними делать что угодно. Так можно создавать всякие хитрые индикаторы, движущиеся прицельные метки и прочее в этом роде. Все такие (плоские) элементы создаются с помощью окон, описанных ранее. Создав окно как объект, его нужно разместить на худе. Для управления худом имеется класс CUIGameCustom. Подобно некоторым другим классам существует всего один глобальный объект такого класса и получить его можно с помощью глобальной функции get_hud() (см. описание пространтв имён). Описание класса CUIGameCustom : class CUIGameCustom { void AddCustomMessage(string id, float x, float y, float font_sz, CGameFont *font, unsigned short alignment, DWORD color); // только ТЧ void AddCustomMessage(string id, float x, float y, float font_sz, CGameFont *font, unsigned short alignment, DWORD color, float flicker); // только ТЧ void CustomMessageOut(string id, string msg, DWORD color); // только ТЧ void RemoveCustomMessage(string id); // только ТЧ SDrawStaticStruct* AddCustomStatic(string id, bool single_instance); SDrawStaticStruct* GetCustomStatic(string id); void RemoveCustomStatic(string id); void AddDialogToRender(CUIWindow* wnd); void RemoveDialogToRender(CUIWindow* wnd); void HidePdaMenu(); // только ЗП void HideActorMenu(); // только ЗП void show_messages(); // только ЗП void hide_messages(); // только ЗП }; Этот класс даёт два метода для размешения на худе своих элементов. Метод первый и исторически самый распространённый. Используются функции AddCustomStatic, RemoveCustomStatic и GetCustomStatic. Теперь по порядку: Имеется файл xml с описаниями создаваемых элементов. Это файл configs\ui\ui_custom_msgs.xml, имя которого прописано прямо в движке. Необходимо внести в этот файл описание своего элемента и дать ему имя. Смотрите там, как это делается. Вкратце, создаётся новый узел XML с атрибутами и подузлами, содержашими все необходимые описания. Имя тега и будет именем нашего элемента. Можно использовать включаемые файлы (с помощью #include <имя файла>), чтобы минимально менять оригинальный файл. теперь во время выполнения получаем объект худа так local hud = get_hud() и создаём наш элемент так local st = hud:AddCustomStatic(<имя элемента>, true) при этом создаётся окно типа CUIStatic по описанию из XML и автоматически размещается на худе. Возвращаемый объект имеет тип SDrawStaticStruct. Его описание: class SDrawStaticStruct { float m_endTime; CUIStatic* wnd(); }; Здесь нам в основном интересен метод wnd, который возвращает указатель на созданный CUIStatic. Внимательно изучите возможности этого контрола, они довольно немаленькие. Удалить элемент можно так hud:RemoveCustomStatic(<имя элемента>) получить в любой момент можно так local st = hud:GetCustomStatic(<имя элемента>) хотя можно и просто запомнить ссылку на элемент, полученную при создании. Собственно всё. С помощью описания в XML можно изобразить что-то простое, но если вам нужна динамика или сложные элементы, то ничто не мешает разместить на созданном окне дополнительные дочерние окна с помощью AttachChild. При этом можно сделать описание в XML минимальным, фактически определив только координаты окна и более ничего, а всё, что требуется, сделать позже с помощью дочерних окон. Данный способ почти всем неплох, но у него есть один маленький недостаток. Все созданные таким образом элементы будут расположены под стандартными элементами худа. А иногда нужно создать элемент, который перекрывает стандартные индикаторы и диалоги. Для этого есть второй метод с использованием функций AddDialogToRender и RemoveDialogToRender. Последовательность работы такая: создаём любым методом окно любого типа wnd = <любое окно> размещаем его на худе так get_hud():AddDialogToRender(wnd) когда захотим, убираем с худа так get_hud():RemoveDialogToRender(wnd) Важное замечание: После помещения окна на худ таким способом обязательно надо как-то сохранить ссылку на объект окна вплоть до его удаления с худа. Если потерять ссылку, то сборщик мусора удалит окно, и игра рухнет. Ещё замечание: и первым и вторым способом можно размещать на худе сколь угодно сложные окна, в том числе с кнопками, полями ввода и прочим в этом роде. Но естественно, они не будут реагировать на пользователя, т.е. работать будут только на вывод. Теперь о диалоговом режиме. Здесь всё вертится вокруг класса CUIScriptWnd. Основная идея заключается в создании на основе этого класса своего скриптового. Не буду в подробностях это описывать (может потом как-нибудь). Есть масса примеров, то же главное меню сделано именно так (файл ui_main_menu.script). В качестве наиболее простого и наглядного примера рекомендую ui_numpad.script. Это - диалоговое окно с панелью ввода кода двери. Оно простое и вместе с тем имеет все необходимые элементы: кнопки, поле ввода, обработку мышиных событий и нажатий клавиатуры. В общем, стоит его для начала внимательно изучить. Я сейчас только рассмотрю вывод созданного окна на экран. В случае с главным меню его запускает сам движок. Прописывание пользовательского класса в этом случае делается через регистрацию клиентского класса в class_registrator.script. Это там всегда уже сделано и это единственное окно, которое открывается таким образом. Все остальные пользовательские окна надо открывать самому. Это делается по-разному в разных версиях движка. В ТЧ Допустим у вас есть скриптовый класс CMyDialog, сделанный на основе CUIScriptWnd. Сначала вы создаёте объект такого класса local dlg = CMyDialog() -- конструктор может быть и с параметрами, поскольку вы его сами написали затем запускаем диалог level.start_stop_menu(dlg, true/false) или так dlg:GetHolder():start_stop_menu(dlg, true/false) разницы никакой, это фактически одна и та же функция. Второй аргумент определяет, будут ли убраны стандратные элементы худа: индикаторы и прочее. закрыть диалог можно вызвав ту же функцию второй раз, второй булевский аргумент при этом значения не имеет. ЧН я не рассматриваю, но там вроде похоже на ТЧ В ЗП всё ещё проще, у самого диалога есть нужные методы ShowDialog и HideDialog. Сначала как обычно создаём объект диалога local dlg = CMyDialog() затем запускаем его dlg:ShowDialog(true/false) -- аргумент как и раньше позволяет скрыть индикаторы закрываем диалог dlg:HideDialog() Вот и всё. Остальные подробности про диалоги смотри в примерах. В неохваченном осталась тема о создании окон на основе XML описания. Для этого есть класс CScriptXmlInit. Он сам по себе несложен, но к нему надо ещё и описывать форматы XML файлов для разных окон, а к этому я сейчас морально не готов =) Также есть ещё достаточно сложная тема о модификации стандартных окон: торговли, PDA и прочего. Здесь на помощь может прийти функция level.main_input_receiver(), которая возвращает текущее активное окно. Приемы работы в этом случае достаточно нетривиальны. Кроме того, в ЗП этой функции нет. В ТЧ и ЧН были глобальные функции GetTextureInfo, GetTextureName и GetTextureRect. Это значит по имени текстуры получить ее файл (вроде как это еще полотном называют) и координаты прямоугольника. Напоминаю, что в таком понимании текстура это то, что обычно указывается в XML описаниях разных окошек. Там как правило прописывается имя, которое ссылается на отдельное описание (в другом XML файле), где уже и задается имя файла и координаты прямоугольника. Эти функции как раз и позволяют получить эту информацию. Особой пользы от этих функций не было, поскольку не было ни одной функции, которая возвращала бы имя текстуры. И вот в ЧН такая функция появилась! Для онлайновых объектов сталкеров стало возможно получить иконку персонажа с помощью функции character_icon. Это очень нужная функция, поскольку дает информацию о реальном профиле сталкера. Так и что вы думаете! В ЗП разрабы взяли и убрали функции получения информации о текстурах. И какой теперь толк от той функции получения иконки? XML прочитать нельзя, а иначе логическое имя ни о чем не говорит. Нет слов, одни междометья. Описание GUI классов от @Malandrinus: Скрытый текст CUIWindow - базовый класс для всех остальных оконных классов, в связи с чем описан наиболее подробно. class CUIWindow { CUIWindow (); // конструктор, как всегда доступен в виде глобальной функции void SetPPMode(); // включение события двойного клика void ResetPPMode(); // выключение события двойного клика void AttachChild(CUIWindow*); // присоединение дочернего окна void DetachChild(CUIWindow*); // отсоединение дочернего окна void SetWindowName(string); // установка имени окна, тег "window_name" string WindowName(); // получение имени окна void SetFont(CGameFont*); // только ТЧ, атрибут "font" CGameFont* GetFont(); // только ТЧ void Enable(bool); // включить/выключить возможность взаимодействовать с пользователем bool IsEnabled(); // получить статус активности void SetAutoDelete(bool); bool IsAutoDelete(); void Show(bool); // показать/скрыть окно bool IsShown(); // получить статус видимости void Init(float x, float y, float width, float height); // только ТЧ void Init(Frect*); // только ТЧ // установить положение верхнего левого угла окна относительно родительского void SetWndPos(float x, float y); // вариант ТЧ void SetWndPos(vector2*); // вариант ЗП vector2* GetWndPos(CUIWindow*); // только ЗП, получить положение окна // установить размеры окна void SetWndSize(float w, float h); // вариант ТЧ void SetWndSize(vector2); // вариант ЗП // установить положение и размеры окна void SetWndRect(Frect); void SetWndRect(float x, float y, float width, float height); // только ТЧ void SetHeight(float h); // только ТЧ, установить высоту окна float GetHeight(); // получить высоту окна void SetWidth(float w); // только ТЧ, установить ширину окна float GetWidth(); // получить ширину окна }; Производные от CUIWindow : CServerList список игровых серверов. Очевидно, для синглового режима мало применим. class CServerList : CUIWindow { CServerList (); void SetPlayerName(string); void SetFilters(SServerFilters&); void RefreshList(bool); void SetSortFunc(string, bool); void NetRadioChanged(bool); void ShowServerInfo(); void RefreshQuick(); void ConnectToSelected(); }; К нему (CServerList) прилагается служебный класс SServerFilters class SServerFilters { SServerFilters (); bool empty; bool full; bool listen_servers; bool with_pass; bool without_ff; bool without_pass; bool without_pb; // только ТЧ }; CUIComboBox - выпадающий список. В ТЧ есть, но недоэкспортирован, в связи с чем применять его можно только в ЗП class CUIComboBox : CUIWindow { CUIComboBox (); void Init(float x, float y, float width); // только ТЧ void Init(float x, float y, float width, float height); // только ТЧ void ClearList(); // только ЗП void SetListLength(int length); void SetVertScroll(bool v); void SetText(string s); // только ЗП string GetText(); // только ЗП void enable_id(int id); // только ЗП void disable_id(int id); // только ЗП CUIListBoxItem* AddItem(string s, int value); // только ЗП void SetCurrentID(int id); int CurrentID(); string GetTextOf(int id); // только ЗП void SetCurrentValue(); // только ЗП }; CUICustomEdit - поле редактирования текста : class CUICustomEdit : CUIWindow { void SetNumbersOnly(bool v); // только ТЧ void SetTextPosX(float x); // только ТЧ void SetTextPosY(float y); // только ТЧ void SetTextAlignment(enum CGameFont::EAligment); // только ТЧ CGameFont::EAligment GetTextAlignment(); // только ТЧ void SetTextColor(DWORD color); // только ТЧ DWORD GetTextColor(); // только ТЧ void SetText(string); string GetText(); void SetNextFocusCapturer(CUICustomEdit*); // только ЗП void CaptureFocus(bool v); // только ЗП }; От него (CUICustomEdit) унаследованы: class CUIEditBox : CUICustomEdit { CUIEditBox (); void InitTexture(string texture); }; class CUIEditBoxEx : CUICustomEdit { CUIEditBoxEx (); void InitTexture(string texture); }; CUICustomSpin - поле прокрутки значений. Не совсем понятно, можно ли его полноценно использовать по причине крайне скудного набора собственных свойств: class CUICustomSpin : CUIWindow { string GetText(); }; От CUICustomSpin наследуются несколько классов, которые к нему вообще ничего не добавляют: class CUISpinFlt : CUICustomSpin class CUISpinNum : CUICustomSpin class CUISpinText : CUICustomSpin CUIDialogWnd - класс диалогового окна. Сам по себе редко используется, но является базовым для чрезвычайно важного класса CUIScriptWnd: lass CUIDialogWnd : CUIWindow { void SetHolder(CDialogHolder*); // только ТЧ CDialogHolder* GetHolder(); void HideDialog(); // только ЗП void ShowDialog(bool <скрывать индикаторы>); // только ЗП // вместо этих функций в ТЧ надо использовать глобальную функцию level.start_stop_menu }; Классы, наследуемые от CUIDialogWnd: **************************************************************** CUIMessageBoxEx **************************************************************** CUIMessageBoxEx - диалоговое окно по функциональности схожее с CUIMessageBox: class CUIMessageBoxEx : CUIDialogWnd { CUIMessageBoxEx (); void Init(string template); // только ТЧ void InitMessageBox(string template); // только ЗП void SetText(string text); // только ЗП string GetPassword(); string GetHost(); }; Описание применения: Окно создаётся наподобие обычного контрола в процессе инициализации главного окна (как правило в типовом методе InitControls) self.msg_box = CUIMessageBoxEx() и регистрируется для возможности обрабатывать события нажатия на кнопки self:Register(self.msg_box, "msg_box") затем в методе InitCallBacks на кнопки этого окна устанавливают колбеки self:AddCallback("msg_box", ui_events.MESSAGE_BOX_OK_CLICKED, self.OnMsgOk, self) Все возможные коллбеки для CUIMessageBoxEx: MESSAGE_BOX_CANCEL_CLICKED MESSAGE_BOX_COPY_CLICKED MESSAGE_BOX_NO_CLICKED MESSAGE_BOX_OK_CLICKED MESSAGE_BOX_QUIT_GAME_CLICKED MESSAGE_BOX_QUIT_WIN_CLICKED MESSAGE_BOX_YES_CLICKED в нужный момент окно можно вызывать так: для ТЧ self.msg_box:Init(<строка_инициализации_окна>) self:GetHolder():start_stop_menu(self.msg_box, true) для ЗП self.msg_box:InitMessageBox(<строка_инициализации_окна>) self.msg_box:SetText(<сообщение>) // необязательное действие self.msg_box:ShowDialog(true) <строка_инициализации_окна> ссылается на одно из описаний диалогов из файла config\ui\message_box.xml примеры и подробности смотри там. Только несколько комментариев. Там можно создать своё окно, но требуется придерживаться шаблонных имён частей этого окна. Можно менять текстуры собственно окна, добавлять типовые кнопки "да, нет, ок, отмена", можно менять иконку окна. Также можно добавлять строки ввода. После выхода из окна, что можно отследить колбеками, введённые значения можно получить с помощью методов GetPassword и GetHost. **************************************************************** CUIMessageBoxEx **************************************************************** CUIScriptWnd - скриптовый диалог. Необычайно важный класс, основа для построения всего пользовательского интерфейса. Это единственный из всех оконных классов, позволяющий скриптовое наследование от себя. Это даёт возможность создавать окна с реакцией на события мыши и клавиатуры. class CUIScriptWnd : CUIDialogWnd,DLL_Pure { CUIScriptWnd (); DLL_Pure* _construct(); // от DLL_Pure, назначение неизвестно bool Load(string xml); // непонятно зачем - нет ни одного примера использования. Возможно, колбек на загрузку void Register(CUIWindow*, string name); // регистрация контрола для возможности обработки событий void Register(CUIWindow*); // делает тоже самое, но не устанавливает имя, в ЗП убрана void AddCallback(string name, int event, const function<void>&, object); // установка колбека на действия пользователя // event - константа из класса-перечисления ui_events void AddCallback(string name, int event, const function<void>&); // в ЗП убрана bool OnKeyboard(int dic, enum EUIMessages); // обработка событий от клавиатуры bool Dispatch(int cmd, int param); // ещё какой-то обработчик function Update(); // похоже на обновление окна в смысле обновления полей ввода, надо разбираться // перечисленные далее функции на практике не нужны и в ЗП удалены совсем CUIFrameLineWnd* GetFrameLineWnd(string); CUICheckButton* GetCheckButton(string); //function GetListWndEx(string); // этой возможно и в ТЧ нет CUIPropertiesBox* GetPropertiesBox(string); CUIButton* GetButton(string); CUIListWnd* GetListWnd(string); CUIStatic* GetStatic(string); CUITabControl* GetTabControl(string); CUIRadioButton* GetRadioButton(string); CUIFrameWindow* GetFrameWindow(string); CUIDialogWnd* GetDialogWnd(string); CUIEditBox* GetEditBox(string); CUIProgressBar* GetProgressBar(string); CUIMessageBox* GetMessageBox(string); }; CUIFrameLineWnd - вроде как окно с рамкой. Сам по себе (вероятно) не интересен, но порождает несколько практически важных классов: class CUIFrameLineWnd : CUIWindow { CUIFrameLineWnd (); void Init(string base_name, float x, float y, float w, float h, bool horiz = true); // только ТЧ void SetOrientation(bool horiz); // только ТЧ CUIStatic* GetTitleStatic(); // только ТЧ // SetWidth и SetHeight имеются и в ТЧ и в ЗП, но в ТЧ они унаследованы от родительского // окна, а в ЗП введены дополнительно void SetWidth(float w); void SetHeight(float h); void SetColor(DWORD color); }; от него (CUIFrameLineWnd) наследуются: // только ТЧ class CUILabel : CUIFrameLineWnd { CUILabel (); string GetText(); void SetText(string); } // только ЗП class CUIListBoxItem : CUIFrameLineWnd { CUIListBoxItem(float heght); CUITextWnd* GetTextItem(); void SetTextColor(DWORD color); void AddIconField(float width); void AddTextField(string text, float width); }; // от него (CUIListBoxItem ? ) в свою очередь (тоже только ЗП): class CUIListBoxItemMsgChain : CUIListBoxItem { CUIListBoxItemMsgChain(float heght); }; CUIFrameWindow - тоже что-то с рамкой: CUIFrameWindow : CUIWindow { CUIFrameWindow (); void Init(string name, int x, int y, int w, int h); // только ТЧ CUIStatic* GetTitleStatic(); // только ТЧ // как и в CUIFrameLineWnd SetWidth и SetHeight имеются и в ТЧ и в ЗП, но в ТЧ // они унаследованы от родительского окна, а в ЗП введены дополнительно void SetWidth(float w); void SetHeight(float h); void SetColor(DWORD color); }; от него (CUIFrameWindow) унаследован: class CUIPropertiesBox : CUIFrameWindow { CUIPropertiesBox (); bool AddItem(string); void AutoUpdateSize(); void RemoveAll(); void RemoveItem(DWORD); void Hide(); void Show(int, int); //(Frect, vector2) ?????????? }; CUIListWnd - список. Класс имеется только в ТЧ и активно там используется. В ЗП вместо него используется CUIListBox, который унаследован от CUIScrollView, который в ТЧ есть, но выглядит неработоспособным.: class CUIListWnd : CUIWindow { CUIListWnd (); void SetTextColor(DWORD); void ActivateList(bool); bool IsListActive(); void EnableScrollBar(bool); bool IsScrollBarEnabled(); void ShowSelectedItem(bool); void ResetFocusCapture(); void ScrollToBegin(); void ScrollToEnd(); void ScrollToPos(int); void SetItemHeight(int); int GetLongestSignWidth(); int GetSize(); // количество элементов void SetVertFlip(bool); bool GetVertFlip(); int GetItemPos(CUIListItem*); CUIListItem* GetItem(int); bool AddItem(CUIListItem*); // всегда возвращает true int GetSelectedItem(); void SetFocusedItem(int); int GetFocusedItem(); void RemoveAll(); void RemoveItem(int); }; к этому классу (CUIListWnd) прилагаются два служебных CUIListItem и CUIListItemEx, которые будут описаны далее в разделе наследования от CUIStatic CUIMMShniaga - этот контрол представляет собой комплексную конструкцию со списком элементов и ползунком с увеличительным стеклом. Это часть главного меню, если не забыли ещё. Одним словом это как-то не назвать, вот и у разработчиков видимо фантазии не хватило. Отсюда и такое имечко =) class CUIMMShniaga : CUIWindow { // enum CUIMMShniaga::enum_page_id // только ЗП const epi_main = 0; const epi_new_game = 1; const epi_new_network_game = 2; void ShowPage(enum CUIMMShniaga::enum_page_id); // только ЗП void SetPage(enum CUIMMShniaga::enum_page_id, string xml_file, string xml_path); // только ЗП void SetVisibleMagnifier(bool); }; CUIMapList , CUIMapInfo - видимо, список мультиплеерных карт. Как и в случае со списком серверов для сингла интереса не представляет: lass CUIMapList : CUIWindow { CUIMapList (); void LoadMapList(); viud SaveMapList(); bool IsEmpty(); void ClearList(); // только ЗП string GetCommandLine(string player); EGameTypes GetCurGameType(); void SetServerParams(string); void SetWeatherSelector(CUIComboBox*); void SetModeSelector(CUISpinText*); void SetMapPic(CUIStatic*); void SetMapInfo(CUIMapInfo*); void StartDedicatedServer(); void OnModeChange(); }; //к нему прилагается дополнительный класс class CUIMapInfo : CUIWindow { CUIMapInfo(); void InitMap(string name); // вариант ТЧ void InitMap(string name, string version); // вариант ЗП void Init(vector2 pos, vector2 sz); // только ЗП }; CUIProgressBar - ползунок прогресса. В ТЧ недоэкспортирован, в связи с чем практический интерес представляет только под ЗП: class CUIProgressBar : CUIWindow { CUIProgressBar (); float GetRange_max(); float GetRange_min(); void SetRange(float min, float max); // только ТЧ void SetProgressPos(float); // только ЗП float GetProgressPos(); // только ЗП }; CUIScrollView - класс имеется во всех версиях движка, но под ТЧ нигде не задействован. В ЗП напротив - заменяет класс CUIListWnd (если точнее, заменяет не он сам, а унаследованный от него): class CUIScrollView : CUIWindow { CUIScrollView (); void AddWindow(CUIWindow*, bool auto_delete); void RemoveWindow(CUIWindow*); void Clear(); void ScrollToBegin(); void ScrollToEnd(); int GetMinScrollPos(); int GetMaxScrollPos(); void SetScrollPos(int); int GetCurrentScrollPos(); }; в ЗП от него (CUIScrollView) наследуется: class CUIListBox : CUIScrollView { CUIListBox(); void AddExistingItem(CUIListBoxItem*); CUIListBoxItem* AddTextItem(string text); void RemoveItem(CUIWindow*); CUIListBoxItem* GetItemByIndex(int); int GetSelectedIndex(); CUIListBoxItem* GetSelectedItem(); int GetSize(); void RemoveAll(); void ShowSelectedItem(bool); CUIWindow* GetItem(int); }; к этому (CUIScrollView) классу прилагаются служебные классы CUIListBoxItem и CUIListBoxItemMsgChain, описанные ранее. CUIStatic - очень важный класс. В ТЧ его возможности огромны. В ЗП - существенно меньше (это один из классов, пострадавших от изменений в наибольшей степени), однако по-прежнему остаётся очень важным. В связи с большой разницей версий описание приводится по отдельности для ТЧ и ЗП Для ТЧ: CUIStatic : CUIWindow { CUIStatic (); void Init(float x, float y, float w, float h); void Init(string texture, float x, float y, float w, float h); void InitTexture(string texture); void SetColor(DWORD color); // фон DWORD GetColor() const; void SetOriginalRect(float x, float y, float w, float h); void SetTextureOffset(float x, float y); void SetStretchTexture(bool); bool GetStretchTexture(); void ClipperOn(); void ClipperOff(); bool GetClipperState(); void SetHeading(float angle); float GetHeading(); void SetText(string text); void SetTextST(string text); // дополнительно транслирует строку string GetText(); void SetTextX(float x); float GetTextX(); void SetTextY(float y); float GetTextY(); void SetTextColor(int a, int r, int g, int b); void SetTextAlign(CGameFont::EAligment ); CGameFont::EAligment GetTextAlign(); }; Для ЗП: CUIStatic : CUIWindow { CUIStatic (); void InitTexture(string texture); void SetTextureRect(Frect*); Frect* GetTextureRect(); void SetStretchTexture(bool); CUILines* TextControl(); }; Частично потерянная функциональность класса для ТЧ вынесена в дополнительный класс (только ЗП): class CUILines { void SetText(string); void SetTextST(string); // с трансляцией string GetText(); void SetTextColor(DWORD color); void SetFont(CGameFont*); void SetElipsis(bool); }; CUIStatic важен не только сам по себе. От него ещё и наследуется много практически важных специализированных классов: Классы, унаследованные от CUIStatic : CUIButton кнопка: class CUIButton : CUIStatic { CUIButton (); void SetHighlightColor(DWORD color); // только ТЧ void EnableTextHighlighting(bool); // только ТЧ }; от него унаследованы: специальная кнопка для работы с контролом управления закладками: class CUITabButton : CUIButton // ничего не добавляет кнопка с тремя состояними (нет наведения курсора, наведение курсора, нажатие): class CUI3tButton : CUIButton // ничего не добавляет от неё в свою очередь унаследован переключатель: class CUICheckButton : CUI3tButton { CUICheckButton (); void SetCheck(boolean); bool GetCheck(); void SetDependControl(CUIWindow*); }; CUITabControl - класс для управления закладками: CUITabControl : CUIWindow { CUITabControl (); void AddItem(CUITabButton*); void AddItem(string item, string texture, float x, float y, float h, float w); // вариант ТЧ void AddItem(string item, string texture, vector2 pos, vector2 size); // вариант ЗП void RemoveAll(); int GetTabsCount() const; CUIButton* GetButtonByIndex(int i); // только ТЧ void SetNewActiveTab(int i); // только ТЧ int GetActiveIndex(); // только ТЧ void RemoveItem(int i); // только ТЧ string GetActiveId(); // только ЗП void SetActiveTab(string tab); // только ЗП CUITabButton* GetButtonById(string id); // только ЗП }; CUIMessageBox Окно сообщения. Представляет собой фактически не контрол, а почти полноценный диалог с полем ввода: class CUIMessageBox : CUIStatic { CUIMessageBox (); void Init(string template); // только ТЧ void InitMessageBox(string template); // только ЗП void SetText(string text); // только ЗП string GetPassword(); string GetHost(); }; окно управления сном (только ЗП): class CUISleepStatic : CUIStatic // нет новых методов элемент списка (только ТЧ) class CUIListItem : CUIButton // нет новых методов продвинутый элемент списка (только ТЧ) class CUIListItemEx : CUIListItem { CUIListItemEx (); void SetSelectionColor(DWORD color); }; класс CUIListItemPair, упоминутый в lua_help и унаследованный от CUIListItemEx похоже не существует. Может когда-то и был... CUITrackBar - ползунок. Как и некоторые другие классы в ТЧ недоэкспортирован до применябельного состояния: CUITrackBar : CUIWindow { CUITrackBar (); void SetCheck(bool); bool GetCheck(); float GetFValue(); // только ЗП int GetIValue(); // только ЗП void SetCurrentValue(); // только ЗП }; CUITextWnd - какое-то текстовое поле. Есть только под ЗП. Видимо, частично компенсирует потерю аналогичных методов из других классов. class CUITextWnd : CUIWindow { CUITextWnd (); void SetText(string); void SetTextST(string); string GetText(); void SetTextColor(DWORD color); DWORD GetTextColor(); void SetFont(CGameFont*); CGameFont* GetFont(); void SetTextComplexMode(bool); void SetTextOffset(float x, float y); void SetTextAlignment(enum CGameFont::EAligment); void SetVTextAlignment(enum EVTextAlignment); void AdjustHeightToText(); void AdjustWidthToText(); void SetEllipsis(bool); // установка обрезания текста (используя троеточие) }; * Не плохо было бы разделить классы элементов простого вывода статиков и диалогового режима.... Описание XML тегов для GUI от @Desertir отсюда Скрытый текст stretch - как раз таки растягивание текстуры по величине окна, для ш\ф это действует как сужение complex_mode - многострочный текст, если у нас длина строки больше ширины окна, слова перенесутся на следующую строку параметры с префиксом la_ не имеют смысла, без параметра light_anim light_anim - задает тип анимации (например при ui_btn_hint будет плавное появление, при ui_pda_contacts - мигание) la_cyclic - повторение анимации la_texture - задействовать текстуру в анимации la_alpha - использовать альфа канал (???) la_text - задействовать текст в анимации aligment и align - выравнивание текста, возможные параметры l - по левому краю, c - по центру, r - по правому краю, возможно align новый вариант, т.к. используется во много раз чаще первого heading - разрешает поворот (???) используется для текстур стрелок (синяя стрелка вокруг ГГ на глобальной карте и стрелка, указывающая на текущее задание) На счет значений light_anim, скорее всего они записаны в движок, и определять экспериментально, какой параметр какую анимацию задает, достаточно муторная работа. Примеры, что я привел, это количество контактов (на худе около мини карты) - число мигает при появлении новых контактов, и подсказка снизу экрана (типа "Подобрать предмет", "Говорить" и т.п.) - она плавно появляется. Больше информации по XML, тегам и тд, от @Comador тут Программа для создания скриптовых окон Stalker UI Creator от @Stalk15 Изменено 25 Июня 2020 пользователем Graff46 4 2 12 Поделиться этим сообщением Ссылка на сообщение
Graff46 598 Опубликовано 5 Февраля 2019 Кто опишет создание окон на основе XML и все атрибуты тегов? Поделиться этим сообщением Ссылка на сообщение
Graff46 598 Опубликовано 11 Января 2020 @karavan, Я пока без пк, код нормально не посмотрел, но наверное кнопку надо приаттачить к окну инвенторя Поделиться этим сообщением Ссылка на сообщение
Graff46 598 Опубликовано 22 Апреля 2020 В шапку добавлено: Описание XML тегов для GUI от @Desertir отсюда 2 Поделиться этим сообщением Ссылка на сообщение