Основные типы

Godot имеет богатый набор классов и шаблонов которые составляют его ядро, и все строится над ними.

Эта справка попытается перечислить их для лучшего понимания.

Определения

Godot использует стандартные типы C98, такие как uint8_t, uint32_t, int64_t, итд. которые поддерживаются всеми компиляторами. Изобретение колеса для них не нужно, так как делает код более сложным для чтения.

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

Для файлов или размеров памяти, используется size_t, чтобы гарантированно иметь 64 бита.

Для строк Юникода, вместо wchar_t используется CharType, поскольку многие архитектуры имеют 4 байтовое wchar_t, где 2 байта могут быть предпочтительнее. Хотя, по умолчанию, это не обязательно и CharType напрямую переводится в wchar_t.

Источники:

Модель памяти

PC чудесная архитектура. Компьютеры часто содержат гигабайты RAM, терабайты данных и гигагерцы CPU, и когда приложению нужно больше ресурсов OS просто отдает неактивные. Другие архитектуры (такие как мобильные телефоны или консоли) в целом более ограниченны.

Самая частая модель памяти это куча, где приложение будет запрашивать область в памяти, а основная OS будет пытаться выделить её где-нибудь и вернуть указатель. Это часто работает превосходно и гибко, но с течением времени могут происходить ошибки, что ведёт к сегментации.

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

However, in many studies and tests, it is shown that given enough memory, if the maximum allocation size is below a given threshold in proportion to the maximum heap size and proportion of memory intended to be unused, segmentation will not be a problem over time as it will remain constant. In other words, leave 10-20% of your memory free and perform all small allocations and you are fine.

Godot ensures that all objects that can be allocated dynamically are small (less than a few kb at most). But what happens if an allocation is too large (like an image or mesh geometry or large array)? In this case Godot has the option to use a dynamic memory pool. This memory needs to be locked to be accessed, and if an allocation runs out of memory, the pool will be rearranged and compacted on demand. Depending on the need of the game, the programmer can configure the dynamic memory pool size.

Выделение памяти

Godot имеет много инструментов для отслеживания использования памяти в игре, особенно во время отладки. Из-за этого, обычные вызовы библиотек C и C++ не должны быть использованы. Вместо них, даны некоторые другие.

Для аллокации в стиле C, Godot предоставляет пару макросов:

memalloc()
memrealloc()
memfree()

Они эквивалентны обычным malloc, realloc, free из стандартной библиотеки C.

Для аллокаций C++, даны специальные макросы:

memnew( Class / Class(args) )
memdelete( instance )

memnew_arr( Class , amount )
memdelete_arr( pointer to array )

которые эквивалентны new, delete, new[] и delete[].

memnew/memdelete также использует маленькую магию C++ и оповещают Объекты которые они создают, перед их удалением.

Для динамической памяти, используется шаблон PoolVector<>. PoolVector это стандартный векторный класс, очень похожий на vector из стандартной библиотеки C++. Для создания PoolVector, используйте это:

PoolVector<int> data;

К PoolVector можно получить доступ через оператор [] и пара вспомогательных методов существует для этого:

PoolVector<int>::Read r = data.read()
int someint = r[4]
PoolVector<int>::Write w = data.write()
w[4] = 22;

Эти операции дают быстрый доступ записи/чтения из PoolVector’ов и сохраняют из закрытыми до тех пор пока они не покинут область видимости. Хотя, PoolVector’а должны быть использованы для маленьких, динамических операций с памятью, так как read() и write() слишком медленны для больших объёмов доступа.

Контейнеры

Godot предоставляет следующий набор контейнеров:

  • Вектор
  • List
  • Задать
  • Map

Они весьма просты и нацелены на то чтобы быть маленькими по возможности, как шаблоны в C++ часто встроенные(inlined) и делают размер бинарника весьма большим, для символов отладки и кода. List, Set и Map могут быть просмотрены(итерированы) через указатели, вот так:

for(List<int>::Element *E=somelist.front();E;E=E->next()) {
    print_line(E->get()); //print the element
}

Класс Vector<> также имеет пару прекрасных возможностей:

  • Он делает копию на запись, что делает создание копий очень производительным до тех пор пока их не изменяют.
  • Он поддерживает мульти-поточность, через использования атомарных операций на счётчике ссылок.

String

Godot также предоставляет класс строки String. Этот класс имеет большой набор возможностей, полную поддержку Юникода во всех функциях (таких как операции с регистром), парсинг/выделение utf8, а также вспомогательные функции для конверсии и визуализации.

Источники:

StringName

StringNames похожи на String, но они уникальны. Создание StringName из строки приводит созданию уникального внутреннего указателя на все одинаковые строки. StringName’ы полезны для использования строк в идентификаторах, так как их сравнение это просто сравнение указателя.

Создание StringName’а (особенно нового) медленная операция, но сравнивание - быстрая.

Источники:

Математические типы

Существует несколько типов линейной алгебры в директории core/math.

Источники:

NodePath

Это специальный тип данных для сохранения путей в дереве сцены и быстрых ссылок на них.

Источники:

RID

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

Источники: