Skip to content

Краткое руководство по началу работы с движком (v0.2.0)

Максимилиан edited this page Jun 16, 2024 · 1 revision

Начало

Данное руководство подходит для версии 0.2.0. Работа с движком в версии 0.3.0 и её патчами (0.2.1 и т.д.) немного изменилась. Изменения будут загружены после 0.2.2 (главно не забыть...)
Внимание! Для работы с движком у вас должна быть видеокарта с поддержкой OpenGL 3.3, иначе окно сборщика и собранной программы будут белыми или в цвет очистки контекста, в версии движка 0.2.0 0.3.0 это планируется исправить.

Подключение

После 0.1.0 подключение к проекту в корне изменилось. Теперь это стало в разы проще, позже ещё улучшу, но пока нет времени.
Для начала надо создать проект. Просто создайте папку и в ней создайте 2 файла, один cpp другой rgset. Названия могут быть любыми, для удобства в статье файл cpp будет назван source (source.cpp), а rgset - config (config.rgset).
Теперь в папке движка ищем программу Rinegine.exe (если вы работаете на 32 битном компьютере используйте Rinegine-x32.exe) Запускаем, видим (лого, после видим) текст, который гласит, что сюда следует переместить файл rgset. Можно переместить уже сейчас, он его прочитает только после того, как вы нажмёте кнопку сборки. Перетаскиваем, видим написан путь к файлу и появилась кнопка сборки. Собирать ещё рано, нам необходимо заполнить наш конфиг. Синтаксис очень прост, и выглядит вот так:

name = example
source = source.cpp
resource = false
bit = 64

(порядок присвоения не важен)

  • name: в него заполняется имя выходного файла, если собираете в 32 бита, то в конец будет приписано -x32.
  • source: имя файла с кодом. Пока нельзя собирать большие проекты с большим кол-во cpp файлов
  • resource: пока не работает, ставьте на false (или вообще не заполняйте и не объявляйте). В будущем будет отвечать за подключение resource.rc к проекту
  • bit: под какую систему собираете. Может быть 32, 64 и all.

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

Первое окно

Обычно я использую ещё один файл source.h для того, чтобы в нём были все функции, заголовки и переменные, чтобы не захламлять cpp, но тут я покажу пример только с одним cpp.
Начнём, для начала нам нужно подключить заголовочный файл движка. К сожалению я пока не реализовал подключение через #include<>, поэтому нам нужно "прийти" к этому файлу. Пишем путь к нему, у меня это #include "../GLOBAL_PROJECT/Rinegine/Rinegine.h" (у вас может быть другой путь). Далее создаём функцию main. Готово, мы можем собрать наш проект. Получается пустая программа, которая ничего не делает. Исправляем. Для работы модулей надо их подключить. Пишем #define RG_GRAPH обязательно перед include(!). Теперь можем создать окно. Для начала работы нам необходимо создать функцию интерфейса (или локации или логики окна, называйте как хотите, данная функция отвечает за логику происходящего в окне). Сделаем функцию, которая рисует в окне фон в градиенте сверху в низ от синего к зелёному. Пишем:

int Menu(int LastLoc){
  int NowPlay = -1;
  bool play = true;
  RG_Object background;
  RG_CreateBackground(background,RG_BG_GradientVertical,{0,0,1,1},{0,1,0,1});
  while(play){
    RG_PollEvents();
    if(glfwWindowShouldClose(RG_MainWindow->win())) {play = false;NowPlay = -1;}
    if(RG_KEYS[GLFW_KEY_ESCAPE] == GLFW_PRESS) {play = false;NowPlay = -1;RG_KEYS[GLFW_KEY_ESCAPE] = GLFW_RELEASE;}
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    RG_Draw(background);
    RG_UpdateStates();
  }
  return NowPlay;
}
  • LastLoc в него передаётся позиция локации из которой эта локация была запущена, в первые при запуске всегда равен 0 (тоесть самая первая локация)
  • NowPlay (название может быть любым) отвечает за то, что будет запущено после завершения функции, -1 это выход из программы (в большинстве случаев). В конце выполнения функции return возвращает данную переменную, которая указывает какую локацию открыть следующим, об этом подробнее чуть позже.
  • play я думаю не стоит объяснять.
  • RG_Object это тип данных, который представляет собой объект в движке, подробнее будет в документации (вероятно скоро RG_Object будет считаться устаревшей), создаём объект background, далее меняем его с помощью функции...
  • RG_CreateBackground, есть ещё несколько похожих функций, но об этом подробнее в документации (когда она будет завершена). В данную функцию передаётся объект, тип фона (пока только вертикальный градиент и горизонтальный (RG_BG_GradientHorizontal), первый (верхний) цвет, второй (нижний) цвет. Далее переходим в цикл
  • RG_PollEvents() обновляет всё (не только события), что связано с окном (окна, камеры, курсора, таймера (если передан))
  • RG_KEYS переменная типа int[350], содержит состояния всех клавиш, позиции которых равны позициям из GLFW (например GLFW_KEY_ESCAPE) (их состояния тоже равны тем, что в GLFW)
  • RG_Draw(RG_Object&) рисует объект на экране
  • RG_UpdateStates обновляет все состояния (меняет буфер glfw местами, состояния изменения размера окна меняет на false, скрол колёсиком ставит на 0).

Далее функция возвращает позицию функции или -1 для выхода.
Дальше нам надо заполнить функцию main. Нам необходимо создать экземпляр класса RG_Functions, назовём его funcs. В теле функции main пишем

RG_Functions funcs;
int main(){
  funcs.append(Menu);
  return Rinegine_Start(funcs);
}

Rinegine_Start упрощает инициализацию движка и открытие окна, вы можете изменить настройки окна путём передачи третьим параметром переменную типа RG_SettingWindow (второй параметр - функция, которая выполняется после инициализации окна и движка, используется для загрузки текстур, шрифта и т.п., если вам ничего не из этого нужно передайте вторым параметром функцию RG_MainPrepare) Теперь можно нажать кнопку собрать, нажимаем, ждём до изменения надписи на "Done!"
image
(PS: У вас не будет иконки у окна как на скриншоте, для её добавления вам нужно файл с именем icon.png разместить по пути data/images/other или у переменной класса RG_SettingWindow изменить параметр PathToIcon до вашей иконки (RG_SettingWindow:PathToIcon = "icon.png";))

Текст (v0.0.0 - v0.2.0, в ближайшем будущем может измениться)

Для вывода текста используется метод класса текста RG_Text. Для отрисовки текста для начала нам необходимо загрузить шрифт, пока поддерживаются только сторонние шрифты и нельзя подключить системные. В любую папку закидываем наш шрифт (текст поддерживает только латиницу и кириллицу!). В своём примере я закину шрифт в одну папку с проектом, сам шрифт будет называться Font.ttf. Далее пишем функцию для загрузки. В примере она будет называться prepare.

void prepare(){
  RG_LoadFont("Font.ttf",46);
  RG_EX_PreparationAtlas();
}

RG_LoadFont(string path, uint SizeFont) - функция для загрузки шрифтов (используйте функцию только один раз, при большем использовании возможны неприятные непредвиденные последствия). В ней path - путь до шрифтов и сами шрифты, SizeFont размер загрузки шрифта, лучше поставить больше, размер текста можно менять и потом, размер загружаемого атласа пока изменить нельзя (не загружайте большие шрифты с очень большим SizeFont так как, вероятно, будут проблемы с производительностью, атлас после подготовки сразу отправляется на видеокарту, но и сохраняется в оперативной памяти для быстрого изменения атласа и загрузки нового с заменой на видеокарту в последующем). RG_EX_PreparationAtlas(); подготавливает атлас и загружает на видеокарту, символы при загрузке определяют своё местоположение на атласе и знают заранее, обычные же текстурки не знают, там немного другой процесс загрузки, об этом позже. Теперь изменяем функцию Rinegine_Start в main на Rinegine_Start(funcs,prepare);. Готово, теперь можем выводить текст на экране, для этого изменим функцию Menu, до цикла добавим создание экземпляра класса текста RG_Text. Название экземпляра может быть любым, в примере же будет назван просто text. Далее снизу создаём текст с помощью функции RG_CreateText(). У данной функции много вариаций (3), но мы воспользуемся только одной, вид у которой - void RG_CreateText(RG_Text& txt, wstring text, POINT3D <double> pos,double sc=0,bool gui = false, LINK_GUI_TYPE typeGui = RG_GUI_LINK_NONE,bool center = false)

  • RG_Text& txt - экземпляр класса RG_Text который изменяем.
  • wstring text - широкая строка текста который собираемся писать.
  • POINT3D <double> pos - позиция на окне (подробнее в документации "Прочие типы данных (структуры, классы)")
  • double sc - размер текста (1 - полный размер, 0.5 размер в два раза меньше и так далее)
  • bool gui - если передан true - текст будет вести себя как интерфейс (статичный на экране), иначе будет как отдельный объект в мире (с помощью метода :rotate(POINT3D<double>rot); можно вращать и :update(); обновлять, подробнее в документации когда будет готова).
  • LINK_GUI_TYPE typeGui - тип связи объекта с окном, можно привязать к любому из углов, с центром и углом или центром, подробнее в документации (когда будет готова).
  • bool center = false - центрирует текст по позиции указанной в pos с учётом связи со стороной окна, по умолчанию нет.

Я хочу вывести сверху вверху текст "Hello world!". Для этого пишем: RG_CreateText(text, L"Hello world!", {0,0,0},3,true,RG_GUI_LINK_CENTER_TOP,1); Объект text меняем на то, чтобы он выводил текст "Hello world!" во позиции 0,0,0, сам текст будет размером в 3 раза больше изначального (у меня шрифт маленького разрешения, из-за этого требуется увеличение в 3 раза, скорее всего вам хватит и 1), текст будет связан с центром экрана по Х и сверху по У. В цикле пишем после функции очистки и отрисовки фона: text.draw();. Всё, теперь проверяем. Видим текст где-то сверху, то есть текст рисуется немного смещённым. Для того чтобы это исправить смещаем текст немного в низ, изменяем параметр pos у функции RG_CreateText на {0,-(RG_SIZEFONT*3/RG_MainSizeWindow),0}

  • RG_SIZEFONT - размер загруженного шрифта (символа), пока поддерживается загрузка лишь одного шрифта, в будущем может быть будет возможность загрузки нескольких шрифтов.
  • RG_MainSizeWindow - размер виртуального экрана, он равен 2000, нужен для правильной компоновки экрана

Это уберёт смещение полностью, это будет не очень красиво, ведь красивее будет когда есть хоть какой-то отступ от границы, можете для этого изменить на {0,-((RG_SIZEFONT*3 + 50)/RG_MainSizeWindow),0} где 50 равен размеру отступа в пикселях виртуального экрана. Код который должен быть на данный момент:

#define RG_GRAPH
#define RG_EXPEREMENTAL

#include "../GLOBAL_PROJECT/Rinegine/Rinegine.h"

Rinegine Engine;

int Menu(int LastLoc){
  int NowPlay = -1;
  bool play = true;
  RG_Object background;
  RG_CreateBackground(background,RG_BG_GradientVertical,{0,0,1,1},{0,1,0,1});
  RG_Text text;
  RG_CreateText(text, L"Hello world!", {0,-((RG_SIZEFONT*3 + 50)/RG_MainSizeWindow),0},3,true,RG_GUI_LINK_CENTER_TOP,1);
	while(play){
    RG_PollEvents(); 
    if(glfwWindowShouldClose(RG_MainWindow->win())) {play = false;NowPlay = -1;}
	  if(RG_KEYS[GLFW_KEY_ESCAPE] == GLFW_PRESS) {play = false;NowPlay = -1;RG_KEYS[GLFW_KEY_ESCAPE] = GLFW_RELEASE;}
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    RG_Draw(background);
    text.draw();
		RG_UpdateStates();
  }

  return NowPlay;
}

RG_Functions funcs;
void prepare(){
  RG_LoadFont("Font.ttf",46);
  RG_EX_PreparationAtlas();
}

int main(){  
  funcs.append(Menu);
  return Rinegine_Start(funcs,prepare);
}

У вас должно быть что-то вроде этого:
image
Кстати для переключения режима окна можете нажимать F11, тогда окно будет переходить из оконного в полноэкранный и наоборот. И кстати о событиях, в следующий раз я напишу о том как изменить функции событий или сделать свою собственную.