Введение в GUI — различия между версиями

(Created page with " Для создания GUI (графический интерфейс пользователя) в Core Engine предусмотрены огромные возможнос...")
(нет различий)

Версия 22:12, 29 июня 2017

Для создания GUI (графический интерфейс пользователя) в Core Engine предусмотрены огромные возможности, которые позволяют не только создавать сложный интерфейс в стиле MCPE (и не только), но и эффективно интегрировать его с остальными игровыми элементами, которые добавляются модами с помощью контейнеров.

Единицы измерения

Все размеры и координаты в интерфейсе задаются в юнитах, где 1 юнит это 1/1000 от ширины окна, в котором создается интерфейс. Если юниты используются для задания позиции и размера окна, то 1 юнит составляет 1/1000 от ширины экрана (как и в случае, когда окно открыто на весь экран).

Текстуры и цвет

Текстуры интерфейса, которые находятся в папке gui вашего мода, будут загруженны и доступны под именем файла без расширения: "gui/slot.png" будет загружен как "slot".

Цвет задается с помощью метода класса android api android.graphics.Color.rgb(r, g, b) - где r, g и b - красная, зеленая и синяя составляющие цвета от 0 до 255 каждая.

Фонт текста задается как объект с 3 значениями: {size: ..., color: ..., shadow: ...}, где size - размер текста, color - цвет, shadow - тень со значением от 0 до 1. 

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

Объект описания

Любой интерфейс имеет объект описания, позволяющий задать данный интерфейс и динамично изменять его, меняя этот объект, пока интерфейс открыт. Объект описания любого типа имеет значения drawing (массив) и elements (объект), которые задают отрисовку фона и элементы соответственно. Их изменение из любого места ведет к динамичному изменению интерфейса, если он открыт. Т.е если вы изменените параметры какого-то элемента или команды отрисовки, то интерфейс изменится в соответствии с вашими изменениями. 

Команды рисования

Команды рисования задаются в объекте описания в массиве drawing и отвечают за отрисовку фона интерфейса.

Формат:

drawing: [
     {/* команда 1 */},
     {/* команда 2 */},
     {/* команда 3 */},
     ....
]

Стардартные команды:

  • {type: "background", color: цвет} - заполняет весь фон указанным цветом.
  • {type: "bitmap", bitmap: "текстура", x: число, y: число, scale: число} - отрисовывает данную текстуру на данных координатах. Параметр scale отвечает за то, сколько юнитов приходится на 1 пиксель текстуры, если этот параметр не указан, он будет равен 1.
  • {type: "frame", x: число, y: число, width: число, height: число, bitmap: "текстура рамки", bg: цвет, scale: число} - отрисовывает рамку данного размера на данных координатах, bitmap - текстура рамки, если не указана, будет использовать стандартная, bg - определите, если хотите, чтобы у рамки был фон какого-то цвета, scale - во сколько раз будет увеличена текстура рамки (толщина рамки), если не указана, то принята за 1.
  • {type: "text", text: "текст", x: число, y: число, font: фонт текста} - отрисовывает данный текст на данных координатах с данным фонтом.
  • {type: "line, x1: число, y1: число, x2: число, y2: число, width: число, color: цвет} - отрисовывает линию между заданными координатами. width - толщина линии в юнитах, по-умолчанию 1, color - цвет линии, по-умолчанию черный.

Элементы

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

Формат:

elements: {
     "name1": {/* элемент 1 */},
     "name2": {/* элемент 2 */},
     "name3": {/* элемент 3 */},
     ....
}

Объект функций клика

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

Формат объекта:

{
     onClick: function(position, container, tileEntity, window, canvas, scale){ // если определен, задает функцию короткого нажатия
          // container - контейнер, для которого открыт данный интерфейс
          // tileEntity - если интерфейс открыт для какого то tile entity, то передаст его, иначе null
          // остальные параметры будут рассмотрены в других уроках
     },

     onLongClick: function(position, container, tileEntity, window, canvas, scale){ // если определен, задает функцию долгого нажатия
          // container - контейнер, для которого открыт данный интерфейс
          // tileEntity - если интерфейс открыт для какого то tile entity, то передаст его, иначе null
          // остальные параметры будут рассмотрены в других уроках
     }
}

Стардартные элементы:

  • {type: "slot", x: число, y: число, size: число, visual: лог.значение, bitmap: "текстура", clicker: объект функций клика} - создает слот на данных координатах данного размера в юнитах, если параметр visual опреден и равен true, то слот не может быть выделен и из него ничего нельзя забрать, если bitmap определена, то стандартная текстура слота будет изменена на данную, если clicker определен, то стандартные функции клика будут заменены на определенные в нем.
  • {type: "invSlot", x: число, y: число, size: число, index: число, bitmap: "текстура"} - создает частный случай слота - слот инвентаря на данных координатах данного размера в юнитах, синхронизированный со слотом инвентаря с индексом index (от 0 до 45, слоты 0-8 - хотбар), если bitmap определена, то стандартная текстура слота будет изменена на данную.
  • {type: "button", x: число, y: число, bitmap: "текстура", bitmap2: "текстура", scale: число, clicker: объект функций клика} - создает кнопку на данных координатах с данной текстурой bitmap, функции клика будут вызываться при нажатии на кнопку, если bitmap2 определена, то при нажатии кнопку изменит текстуру на нее. Параметр scale отвечает за то, сколько юнитов приходится на 1 пиксель текстуры, если этот параметр не указан, он будет равен 1. 
    Параметры функций объекта клика имеют тут другой порядок:
{
     onClick: function(container, tileEntity, position,  window, canvas, scale){/* ... */},
     onLongClick: function(container, tileEntity, position, window, canvas, scale){/* ... */}
}
  • {type: "closeButton", x: число, y: число, global: лог.значение, bitmap: "текстура", bitmap2: "текстура", scale: число} - создает кнопку закрытия окна на данных координатах, если bitmap и bitmap2 не определены, кнопка имеет стандартную текстуру, если параметр global определен и равен true, то кнопка закроет всю группу окон, а не только данное окно. Параметр scale отвечает за то, сколько юнитов приходится на 1 пиксель текстуры, если этот параметр не указан, он будет равен 1.
  • {type: "scale", x: число, y: число, direction: число, bitmap: "текстура", scale: число, invert: лог.значение, overlay: "текстура", overlayScale: число, overlayOffset: {x: число, y: число}} - создает шкалу на данных координатах с текстурой bitmap и в направлении direction. Параметр scale отвечает за то, сколько юнитов приходится на 1 пиксель текстуры, если этот параметр не указан, он будет равен 1.
    Направления:
    • 0 - право
    • 1 - верх
    • 2 - лево
    • 3 - низ

Если invert определен и равен true, то позиция вырезки из текстуры будет инвертирована, что создаст видимость того, что шкала как бы выдвигается, а не заполняется.
overlay - если определен, накладывает на шкалу дополнительную текстуру, которая перекрывает шкалу.
overlayScale - параметр scale для перекрытия.
overlayOffset: {x: , y: } - если определен, задает позицию перекрытия, относительно позиции шкалы в юнитах.

  • {type: "text", x: число, y: число, width: число, height: число, text: "текст", font: фонт текста} - создает динамичный текст на заданных координатах, width и height задают длину и ширину области, которая будет очищаться перед отрисовкой текста. text задает начальный текст, font - фонт текста.
  • {type: "image", x: число, y: число, bitmap: "текстура", scale: число, overlay: "текстура", overlayScale: число, overlayOffset: {x: число, y: число}, clicker: объект функций клика} - создает динамичную картинку на заданых координатах с текстурой bitmap. Параметр scale отвечает за то, сколько юнитов приходится на 1 пиксель текстуры, если этот параметр не указан, он будет равен 1.
    Если clicker определен, то функции клика из него будут вызываться при нажатии на элемент.
    overlay - если определен, накладывает на шкалу дополнительную текстуру, которая перекрывает шкалу.
    overlayScale - параметр scale для перекрытия.
    overlayOffset: {x: , y: } - если определен, задает позицию перекрытия, относительно позиции шкалы в юнитах.

Стилизация 

Кроме drawing и elements в объекте описания можно определить объект стилизации интерфейса для изменения стандартных текстур элементов.

Если какое-то из нижеприведённых значений будет указано в объекте стилизации, оно заменит стандартый параметр.

params: {
     slot: "текстура слота",
     invSlot: "текстура слота инвентаря",
     frame: "текстура обычной рамки",
     selection: "текстура выделения слота",
     closeButton: "текстура кнопки закрытия",
     closeButton2: "текстура нажатой кнопки закрытия",
}

Типы интерфейса

Интерфейс бывает 3 типов: однооконный, многооконный и стандартный. В данной главе будет рассмотрен только последний, как самый простой в использовании и при этом эффективный и применимый в большинстве случаев. Объект интерфейса во всех этих случаев создается как объект класса одного из типов, после создания такой объект класса может быть настроен и открыт для любого контейнера.

Любой интерфейс может быть протестирован с помощью функции UI.testUI(объект интерфейса);

Стандартный интерфейс

Создается как объект класса UI.StandartWindow, которому может быть передан объект описания. 

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

var testUiScreen = UI.StandartWindow({/* ... пустой объект описания ... */});
​​​​​​​UI.testUI(testUiScreen); // откроет полностью пустой интерфейс

 

Формат объекта описания стандартного типа интерфейса:

{
     standart: { // стандартные параметы, поддерживаемые данным типом интерфейса, позволяют быстро задавать базовые элементы, такие как заголовок, фон и инвентарь
          // если хотите определить какой то стандартный элемент, но оставить его без изменений, то пропишите там единственное значение - standart: true, например inventory: {standart: true} 
          header: { // определите, если вам нужен заголовок, заголовок содержит кнопку закрытия
               text: { // обязательный параметр, если заголовок определен
                    text: "текст заголовка", // содержание текста, обязательный параметр
               },
​​​​​​​               font: {...}, // фонт текста, определите, если хотите изменить стандартный
               color: цвет, // нужен только, если вы хотите изменить цвет заголовка
               frame: "текстура рамки", // нужно только, если вы хотите изменить текстуру рамки заголовка
               width: 80, // высота заголовка в юнитах,
               hideButton: true, // определите и установите значение на true, чтобы убрать кнопку закрытия
          },
          inventory: { // для определения стандартного инвентаря используйте inventory: {standart: true} 
               width: 300, // ширина окна инвентаря 
               padding: 20, // паддинг окна инвентаря
          },
          background: { // для определения стандартного фона используйте background: {standart: true} 
               color: цвет, // определите, если хотите изменить цвет фона
               bitmap: "текстура фона", // определите, если хотите добавить текстуру фона
               frame: "текстура рамки" // определите, если хотите добавить рамку
          },
          minHeight: 650, // если высота окна в юнитах меньше этого параметра, окно будет прокручиваться так, чтобы его внутренний размер составлял по высоте minHeight юнитов
     },
     params: {
          // стилизация (изменение стандартных текстур)
     },
     drawing: [/* команды отрисовки фона */],
     elements: {/* описание элементов */}
}

Пример

Как пример использован реальный интерфейс из таумкрафта (реактор аспектов).

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

var aspectReactorGui = new UI.StandartWindow({
     standart: {
          header: {
               text: {
                    text: "Aspect reactor"
               },
               color: android.graphics.Color.rgb(0x47, 0x26, 0x0c),
               frame: "thaum_frame_header"
          },
          inventory: {
               standart: true
          },
          background: {
               bitmap: "thaum_background"
          },
          minHeight: 600
     },
     params: {
          textures: {
               slot: "thaum_slot",
               invSlot: "thaum_inv_slot",
               selection: "thaum_selection",
               closeButton: "thaum_close_button_up",
               closeButton2: "thaum_close_button_down",
               frame: "thaum_frame_default"
          }
     },
     drawing: [
          {type: "bitmap", x: 842, y: 104, bitmap: "aspect_scale_background", scale: 4},
          {type: "bitmap", x: 560, y: 100, bitmap: "aspect_reactor_background", scale: 360 / 128},
     ],
     elements: {
          "slot1": {type: "slot", x: 400, y: 100, size: 160},
          "slot2": {type: "slot", x: 400, y: 300, size: 160},
          "aspectScale": {type: "scale", x: 850, y: 120, direction: 1, scale: 8, value: 1, bitmap: "aspectScale_nitor", overlay: "aspect_scale_overlay_1", overlayScale: 4},
          "stateText": {type: "text", x: 625, y: 227, width: 90, height: 100, text: "", font: {color: android.graphics.Color.WHITE, shadow: .6, size: 25}}
     }
});
UI.testUI(aspectReactorGui); // тестовое открытие после создания
// добавляем созданный интерфейс нашему tile entity из прошлых глав
IDRegistry.genBlockID("testBlock");

// ...
// создаем блок
TileEntity.registerPrototype(BlockID.testBlock, {
     defaultValues: {
          someValue: 0 // сохраняемое значение someValue, по умолчанию 0
     },

     tick: function(){
          // что то сделать каждый тик, к примеру выводим someValue
          Debug.message(this.data.someValue);
     },

     click: function(id, count, data, coords){
          this.data.someValue = 1; // установить значение someValue на 1
     },
    
     getGuiScreen: function(){
          return aspectReactorGui; // при попытке открыть интерфейс, возвращаем наш объект интерфейса
     }
    
     // остальные события не трогаем
});