Предисловие
В этом пособие я использовал версию:
https://github.com/britzl/extension-imgui/archive/refs/tags/2.6.1.zip
В этом уроке мы познакомимся с графическим интерфейсом Dear ImGUI в Defold.
Он идеально подходит для быстрого создания отладочного интерфейса или создания внутриигровых инструментов и настроек.
Я настоятельно рекомендую его использовать в своей работе, т.к освоив его, вы сэкономите время на разработку инструментов отладки/тестирования вашей игры.
Кстати, сейчас я его использую в нашей игре с ребятами: https://defolder.com/t/arnulf-protiv-vseh/93
Что советую и вам, по крайней мере, других альтернатив я не знаю.
Это урок прежде всего нацелен на тех, кто знаком с основами Defold: умеет создавать игровые объекты, компоненты, понимает как работает скрипт и из чего он состоит, что такое коллекция и т.д, и т.п.
Если не знакомы с Defold, рекомендую ознакомиться с материалы по Defold на официальном сайте: Defold manuals and other learning resources
Несмотря на все вышеперечисленное, вы можете повторить все действия и увидеть результат в этом уроке.
Подключаем библиотеку и добавляем input_bindings
Добавим Dear ImGui в качестве зависимости в ваш проект:
После того, как вы добавили imgui в ваш проект и подтянули зависимости, в вашем проекте должна появиться папка imgui:

Файл imgui.input_binding скопируем (ctrl + C) перенесём в нашу папку input (ctrl + V):
В
game.project, в Runtime input, в Game Binding изменим файл с привязками ввода:Вы можете удалить game.input_binding, а также сменить название для вашего input_binding.
Создаём игровой объект, добавляем скрипты
Создадим main.script:

В main.collection создаём игровой объект и добавляем компоненты:
Скрипт imgui появился в результате добавления Dear ImGUI в наш проект.
Этот скрипт — это обработчик ввода, написанный за нас.
Перейдите в скрипт main и вставьте этот код:
-- Пример данных: таблица с заголовками и строками
local headers = { "ID", "Name", "Value" }
local rows = {
{ 1, "Alpha", 10 },
{ 2, "Bravo", 20 },
{ 3, "Charlie", 30 },
}
-- Функция инициализации
function init(self)
msg.post(".", "acquire_input_focus")
imgui.set_ini_filename()
end
-- Отрисовка панели
function update(self, dt)
-- Начало окна с авторазмером
imgui.begin_window("Simple Table", nil, imgui.WINDOWFLAGS_ALWAYS_AUTO_RESIZE)
-- Начало таблицы: 3 столбца
if imgui.begin_table("table1", #headers) then
-- Установка заголовков
for _, h in ipairs(headers) do
imgui.table_setup_column(h)
end
imgui.table_headers_row()
-- Заполнение строк
for _, row in ipairs(rows) do
imgui.table_next_row()
for i, cell in ipairs(row) do
imgui.table_next_column()
imgui.text(tostring(cell))
end
end
imgui.end_table()
end
imgui.end_window()
end
Сохраните проект (ctrl + S), соберите и запустите его (ctrl + B):
Справочник
В ImGui каждый контейнер (окно, таблица, вкладка и т. д.) открывается явным вызовом begin_* и должен «закрываться» соответствующим end_*. Это нужно, чтобы:
- Синхронизировать стек состояний
ImGui хранит внутренний стек активных контейнеров. Приbegin_windowилиbegin_tableв этот стек добавляется новая запись с параметрами (позиция, размер, стиль, колонки и т. д.). Если не вызватьend_windowилиend_table, контейнер останется «незакрытым», что приводит к рассинхронизации стека и, как следствие, к артефактам рендеринга или даже крашу. - Завершить сборку содержимого
—end_table()говорит ImGui: «все ячейки добавлены — можешь вычислить итоговые размеры, нарисовать бордюры, обработать возможный скроллинг и т. д.».
—end_window()сигнализирует о том, что в это окно больше ничего не рисуется, и его можно «слить» с остальным интерфейсом. - Оптимизация
Только после полного закрытия контейнера ImGui может оптимизировать отрисовку (отсечь невидимые элементы, свернуть колонки, рассчитать прокрутку), исходя из полного набора виджетов внутри.
Поэтому всегда:
imgui.begin_window("Title", ...)
-- содержимое окна
imgui.end_window()
-- и для таблицы:
if imgui.begin_table("id", column_count) then
-- настройка и наполнение таблицы
imgui.end_table()
end
imgui.set_ini_filename(filename)
imgui.set_ini_filename(filename)
Функция imgui.set_ini_filename(filename) задаёт имя файла, в который ImGui будет сохранять и из которого загружать свою конфигурацию окна (позиции, размеры, состояния свёрнутости и т. д.) при старте/выходе.
Если вызвать imgui.set_ini_filename() без аргумента или с nil, то ImGui отключит автоматическую загрузку и сохранение настроек в .ini файл. То есть:
- Без вызова — ImGui по умолчанию создаст и будет использовать файл
imgui.iniрядом с бинарником. - С
imgui.set_ini_filename("custom.ini")— будет использоватьcustom.ini. - С
imgui.set_ini_filename()(илиnil) — отключает работу с.iniвовсе, окно всегда рисуется в месте и размере, заданном в коде.
imgui.begin_table()
imgui.begin_table("table1", #headers)
Выполняет следующие действия:
- Создаёт новую таблицу с уникальным идентификатором
"table1". - Устанавливает число колонок равным значению
#headers(длине массиваheaders). - Инициализирует внутренние структуры ImGui для управления разметкой ячеек, заголовков и прокрутки (если позже указаны соответствующие флаги).
- Возвращает
true, если таблица готова к заполнению (например, при наличии достаточного места для рендеринга). Если возвращаетсяfalse, значит таблица не может быть отрисована на текущем кадре, и все вызовы заполнения (table_setup_column,table_next_rowи т. д.) следует пропустить доimgui.end_table().
После успешного begin_table вы настраиваете колонки через imgui.table_setup_column(), рисуете заголовки функций imgui.table_headers_row(), заполняете строки и ячейки с помощью imgui.table_next_row() и imgui.table_next_column(), а затем закрываете таблицу вызовом imgui.end_table().
imgui.table_setup_column(h)
imgui.table_setup_column(h)
Выполняет настройку текущей колонки таблицы:
- Аргумент
h(строка) задаёт текст заголовка для этой колонки, который позже отрисуется при вызовеimgui.table_headers_row(). - По умолчанию каждая колонка получает автоматическую ширину, выравнивание и флаги.
- Функция подготавливает внутренние параметры (ширину, приоритет изменения размера, флаги выравнивания) для последующего рендеринга ячеек в этой колонке.
Если нужен более тонкий контроль, можно передать дополнительные аргументы:
imgui.table_setup_column(column_id, flags, init_width_or_weight, user_id)
flags— флаги поведения колонки (например, фиксированная ширина, возможность сортировки).init_width_or_weight— начальная ширина или вес, влияющий на перераспределение свободного пространства.user_id— целочисленный идентификатор для сортировки.
Обычно, imgui.table_setup_column(h) достаточно, чтобы задать шапку и автоматически распределить колонки по контенту.
imgui.table_headers_row()
imgui.table_headers_row()
Служит для отрисовки строки заголовков таблицы. После того как вы настроили колонки вызовами imgui.table_setup_column(), этот вызов:
- Создаёт новую строку в таблице.
- В каждой колонке выводит текст заголовка, указанный в
table_setup_column. - Рисует визуальное разделение между заголовками (если используется стиль с линиями).
Без вызова table_headers_row() таблица не покажет шапку с названиями колонок — вы получите только пустую область для данных.
imgui.table_next_column()
imgui.table_next_column()
Выполняет переход к следующей ячейке в текущей строке таблицы.
Подробности:
- При вызове внутри тела таблицы этот вызов устанавливает «курсор» рендеринга в следующую колонку.
- Если вы вызвали
imgui.table_next_row()перед этим, то сначала курсор сядет в первую колонку новой строки, а последующиеtable_next_column()последовательно переходят по всем столбцам. - В каждой ячейке вы затем размещаете виджет (например,
imgui.text,imgui.buttonи т.д.). - Когда количество вызовов
table_next_column()достигает числа колонок, дальнейшие вызовы будут игнорироваться до начала новой строки.
imgui.text(str)
imgui.text(str)
Функция imgui.text(str) выводит в текущей позиции окна простой текстовый виджет с содержимым str.
- Берёт строку (или преобразованную через
tostring) и рисует её в интерфейсе. - Не реагирует на ввод — только отображает статический текст.
- После отрисовки курсор смещается вниз на высоту строки, чтобы следующий вызов рисовал ниже.
Функция imgui.set_ini_filename(filename) задаёт имя файла, в который ImGui будет сохранять и из которого загружать свою конфигурацию окна (позиции, размеры, состояния свёрнутости и т. д.) при старте/выходе.
Если вызвать imgui.set_ini_filename() без аргумента или с nil, то ImGui отключит автоматическую загрузку и сохранение настроек в .ini файл. То есть:
- Без вызова — ImGui по умолчанию создаст и будет использовать файл
imgui.iniрядом с бинарником. - С
imgui.set_ini_filename("custom.ini")— будет использоватьcustom.ini. - С
imgui.set_ini_filename()(илиnil) — отключает работу с.iniвовсе, окно всегда рисуется в месте и размере, заданном в коде.
Cоздаёт окно с заголовком “Simple Table”, которое подстраивается под содержимое.
imgui.begin_window("Simple Table", nil, imgui.WINDOWFLAGS_ALWAYS_AUTO_RESIZE)
WINDOWFLAGS_ALWAYS_AUTO_RESIZE — это флаг при создании окна ImGui, который заставляет окно автоматически подстраивать свой размер под содержимое при каждом кадре.
Подробно:
- При наличии этого флага ImGui не рисует рамку, позволяющую пользователю вручную тянуть границы окна — вместо этого ширина и высота окна вычисляются исходя из максимальных размеров виджетов внутри.
- Если вы добавляете или удаляете элементы интерфейса (текст, кнопки, таблицы), окно моментально «обхватывает» их по размеру без лишнего пустого пространства.
- Полезно для небольших вспомогательных или отладочных панелей, где критична компактность и отсутствуют статические размеры.
- Не подходит для окон со скроллингом или когда нужно сохранить постоянную область отображения при динамическом контенте.
Пример использования:
imgui.begin_window("My Window", nil, imgui.WINDOWFLAGS_ALWAYS_AUTO_RESIZE)
-- содержимое...
imgui.end_window()
В этом случае окно «My Window» всегда точно соответствует размеру своих внутренних виджетов.
Каждый элемент означает следующее:
imgui.begin_windowиimgui.end_window
Эти два вызова всегда идут парой. Всё, что рисуется между ними, попадает внутрь одного окна.- Первый аргумент
"My Window"
Заголовок окна. В нём будет отображаться текст в заголовочной полосе окна. - Второй аргумент
nil
Опциональный аргумент — указатель на булевую переменную (флажок) для контроля видимости окна.- Если передать ссылку на
true/false, ImGui сам сможет закрывать окно (по крестику) и менять эту переменную. - Если
nil, окно всегда открыто, а кнопка закрытия не рисуется.
- Если передать ссылку на
- Третий аргумент
imgui.WINDOWFLAGS_ALWAYS_AUTO_RESIZE
Флаг, заставляющий окно автоматически подстраивать свои ширину и высоту под содержимое на каждом кадре.
Следующая тема: Изучаем Dear ImGUI в Defold. Часть 2. Радиокнопки
Всем спасибо за внимание!





