Разделы:
- UI с помощью XML файла
- GUI, отображенный поверх окна приложения
- GUI на GUI-объектах
UI с помощью XML файла
1. Создание изображения
Изображения необходимо создавать в png формате. Для создание макета можно воспользоваться figma.
Создадим небольшой пример меню. Он состоит и заднего фона, и 3 кнопок. Следовательно у нас должно быть 4 изображения.
Как видно изображение двух кнопок содержит в себе 2 изображения (обычный вид, вид при наведении). При этом изображения должны быть одинакового размера. Это будет использоваться, чтобы реализовать изменение кнопки при наведение.
2. Создание xml файла
Прописывать расположение элементов Интерфейса мы будет в ручную. С помощью файла расширения Menu.ui, на языке xml. Создадим файл с именем menu.ui. В нем мы будем прописывать расположение элементов интерфейса.
<!--КОД-->
<?xml version="1.0" encoding="utf-8"?>
<ui version="1.0">
<vbox name="menu" width="350" height="600">
<sprite align="overlap" pos_x="0" pos_y="0" width="350" height="550"
texture="./data/ui/sourceUI/back_menu.png"></sprite>
<sprite name="exit" width="26" heigh="26" align="overlap" pos_x="8" pos_y="20"
texture="./data/ui/sourceUI/exit.png"></sprite>
<sprite name="mainWorld" align="overlap" width="120" pos_x="36" pos_y="88" scale_y="0.5"
texcoord_w="0.5" texture="./data/ui/sourceUI/btn_main.png"></sprite>
<sprite name="museumWorld" align="overlap" width="120" pos_x="193" pos_y="88" scale_y="0.5"
texcoord_w="0.5" texture="./data/ui/sourceUI/btn_museum2.png"></sprite>
</vbox>
</ui>
Все элементы будут находится в контейнере vbox, с именем name. Имя необходимо, по нему будет искать widget, который нужно вывести на экран. Это же относится и к sprite.
В контейнер помещаем sprite. Это будущие кнопки, на которые мы повесим CallBack.
scale_y="0.5" texcoord_w="0.5" - для того чтобы отображалась только первая половина изображения.
Прошу заметить что пути до файлов начинаются с папки data.
Подробнее о имеющихся виджетах
3. Создание Компонента C#
Создадим компонент C# и назовем его MyGui.cs. Создадим необходимые на переменные. В поле File будет храниться наш .ui файл.
[ShowInEditor]
[ParameterFile (Filter = ".ui")]
public string file = "null";
UserInterface ui;
Widget pWorldLoaderMenu;
WidgetSprite pWButtonExit, pWButtonMain, pWButtonMuseum;
В функции Init получаем файлик и находим контейнер vbox с именем menu. Также меняем местоположение в центр экрана. Делаем его наследником нашего текущего интерфейса.
ui = new UserInterface(Gui.GetCurrent(), file);
System.Console.WriteLine(ui.FindWidget("menu"));
pWorldLoaderMenu = ui.GetWidget(ui.FindWidget("menu"));
ivec2 mainWindowSize = Unigine.WindowManager.MainWindow.Size;
int px = pWorldLoaderMenu.Width;
int py = pWorldLoaderMenu.Height;
pWorldLoaderMenu.SetPosition(mainWindowSize.x/2-px/2,mainWindowSize.y/2-py/2);
Gui.GetCurrent().AddChild(pWorldLoaderMenu, Gui.ALIGN_OVERLAP | Gui.ALIGN_CENTER);
По отдельности находим спрайты наших кнопок и добавляем им Callback с вызовом функции. В параметр функции передает widget, на которое было наведение. На ENTER мы должны сменить изображение на более светлое, имитирую выделение. На LEAVE должны вернуть начальное положение.
pWButtonExit = (WidgetSprite)ui.GetWidget(ui.FindWidget("exit"));
pWButtonExit.AddCallback(Gui.CALLBACK_INDEX.CLICKED, () => exit());
pWButtonMain = (WidgetSprite)ui.GetWidget(ui.FindWidget("mainWorld"));
pWButtonMain.AddCallback(Gui.CALLBACK_INDEX.ENTER, () => changeCoverButtonEnter(pWButtonMain));
pWButtonMain.AddCallback(Gui.CALLBACK_INDEX.LEAVE, () => changeCoverButtonLeave(pWButtonMain));
pWButtonMuseum = (WidgetSprite)ui.GetWidget(ui.FindWidget("museumWorld"));
pWButtonMuseum.AddCallback(Gui.CALLBACK_INDEX.ENTER, () => changeCoverButtonEnter(pWButtonMuseum));
pWButtonMuseum.AddCallback(Gui.CALLBACK_INDEX.LEAVE, () => changeCoverButtonLeave(pWButtonMuseum));
Функции exit, changeCoverButtonEnter, changeCoverButtonLeave. Изменяем TexCoord (Сделано методом подбора, желательно получше изучить как оно работает)
private void exit()
{
Engine.Quit();
}
private void changeCoverButtonEnter(WidgetSprite widget)
{
widget.SetLayerTexCoord(0, new vec4(0.0f,0.5f,1.0f,1f));
}
private void changeCoverButtonLeave(WidgetSprite widget)
{
widget.SetLayerTexCoord(0, new vec4(0.0f, 0f,1.0f,0.5f));
}
Создаем объект NodeDummy и назовем его menu. Нажимаем "Add New Component or Property" и в поле перетаскиваем наш C# компонент, затем в поле File перетаскиваем наш ui. файл.
GUI, отображенный поверх окна приложения
Просто добавление текста на экран приложения. Так же можно добавить любой из виджетов.
Подробнее о имеющихся виджетах
WidgetLabel text;
Gui gui;
private void Init()
{
gui = Gui.GetCurrent();
text =new WidgetLabel(gui, "ESC - открыть/закрыть меню");
text.FontColor = vec4.BLACK;
text.FontSize = 20;
gui.AddChild(text);
}
Создаем объект NodeDummy. Нажимаем "Add New Component or Property" и в поле перетаскиваем наш C# компонент.
GUI на GUI-объектах
1. Создание сцены
Добавляем на сцену GUI-объект. Изменяем его параметры.
- Billboard - экран всегда смотрит на игрока
- Background - отображение заднего фона
- Control Distance - расстояние, на котором можно взаимодействовать с GUI-объектом
- Physical Width и Height - ширина и высота GUI-объекта
Добавим основную камеру игрока, назовем ее "player". Сделаем ее дочерней для "first_person_controller". Нажмем Edit у "first_person_controller" и изменить раздел "Camera". В "Camera Mode" выберем "USE_EXTERNAL", а в поле "Camera" перенесем камеру "player" из древа объектов.
Добавляем на сцену камеру для меню, назовем ее "cameraGUI". Размещаем ее так, чтобы она смотрела на наш GUI-объект. Поставим галочку в параметре "Main Player", если хотим, чтобы приложение запускалось с меню.
В итоге должны получить что-то подобное.
2. Создание Компонента C#
Создадим компонент C# и назовем его ObjectGui. Создадим необходимые переменные. menuShow будет отвечать за то, показывается ли наше меню или нет.
Gui gui;
WidgetButton btStart, btExit;
bool menuShow;
В функции Init будет создавать кнопки. Для этого сначала получить ноду ObjectGui, к которой добавим данный скрипт. Создадим две кнопки "Start" и "Exit". Для этого будет использовать WidgetButton. Определим их местоположение и добавим дочерними к нашему gui. Добавим CallBack для кнопок. При нажатии на кнопку "Start" будет вызываться функция start, а при нажатии на кнопку "Exit" будет вызываться функция exit. Так же отметим что показывает наше меню.
gui = (node as ObjectGui).GetGui();
int width = gui.Width, height = gui.Height;
btStart = new WidgetButton(gui, "START");
btStart.Width = 200;
btStart.Height = 70;
btStart.ButtonColor = new vec4(1, 0, 0, 1);
btStart.FontSize = 20;
btExit = new WidgetButton(gui, "EXIT");
btExit.Width = 200;
btExit.Height = 70;
btExit.ButtonColor = new vec4(1, 0, 0,1 );
btExit.FontSize = 20;
btStart.SetPosition(width / 2 - btStart.Width / 2, height / 2 - 5 - btStart.Height);
btExit.SetPosition(width / 2 - btExit.Width / 2, height / 2 + 5);
gui.AddChild(btStart, Gui.ALIGN_OVERLAP | Gui.ALIGN_FIXED);
gui.AddChild(btExit, Gui.ALIGN_OVERLAP | Gui.ALIGN_FIXED);
btStart.AddCallback(Gui.CALLBACK_INDEX.CLICKED, gameStart);
btExit.AddCallback(Gui.CALLBACK_INDEX.CLICKED, exit);
menuShow = true;
В функцию Update опишем то, когда вызывается наше меню. Будет по кнопке ESC.
if (Input.IsKeyDown(Input.KEY.ESC) && menuShow){
gameStart();
}
else if (Input.IsKeyDown(Input.KEY.ESC)){
menuStart();
}
Опиши функции gameStart и menuStart, также exit. Они вызываются при нажатие кнопки ESC, так же при нажатие кнопок на меня "Start" и "Exit"
В GetNode пишем id нужных камер.
ControlsApp.MouseHandle - передает управление курсору мышью или "захвату" (USER or GRAB).
void gameStart(){
Game.Player = (Player)Node.GetNode(1948974963);
menuShow = false;
ControlsApp.MouseHandle = Input.MOUSE_HANDLE.GRAB;
gui.RemoveFocus();
}
void menuStart(){
Game.Player = (Player)Node.GetNode(1976348130);
menuShow = true;
ControlsApp.MouseHandle = Input.MOUSE_HANDLE.USER;
gui.RemoveFocus();
}
void exit(){
Engine.Quit();
}
Добавляем данный C# компонент к GUI-объекту.