Привет, ребята,
Мы собираемся продолжить изучение основ Unreal Engine C++, взглянув на разработку, управляемую данными, с использованием DataTables.
Как обычно, я создал проект GitHub, который содержит примеры ниже, а также видео с небольшим количеством более подробной информации.
Что такое таблица данных?
DataTable — это группа записей, которые имеют общие свойства, к которым затем можно получить доступ с помощью ссылок на строки или ключей строк.
Другими словами, это набор строк, как в электронной таблице, все из которых имеют общие столбцы.
И еще один способ — сказать, что это простое хранилище ключевых значений.
Или базу данных.
Хватит ваших проклятых слов, покажите мне фотографии!
Давайте посмотрим на пример ниже.
У нас есть две строки, содержащие следующие атрибуты/столбцы:
- Монтаж — ссылка на ранее сделанный анимационный монтаж.
- Всего анимаций — количество анимаций, которые мы ожидаем запустить во время атаки.
- Описание — краткое описание того, что мы здесь храним.
Отлично, мы перешли от игр к электронным таблицам? Что дает ?
Что ж, как бы мы все ни хотели делать забавные вещи, когда дело доходит до разработки игр, в конце концов, это всего лишь разработка программного обеспечения. Большинство заданий по разработке программного обеспечения требуют, чтобы вы использовали какую-либо базу данных хотя бы один раз. Есть SQL Server, Postgres, MongoDB и даже Excel. Все это в конечном итоге обеспечивает работу приложений и игр, поскольку всем нам необходимо извлекать и хранить большие наборы общих данных.
В сфере разработки игр это просто используется для большего удовольствия, чем в других секторах.
Все это позволяет нам иметь общие места для ввода данных, представляющих множество «вещей» в нашей игре, а затем иметь возможность запрашивать или извлекать эти данные по прихоти.
Давайте посмотрим на пример ниже.
Если бы у вас была ролевая игра со статическими определениями опыта и того, сколько этого опыта вам нужно для достижения определенного уровня. Вы можете сделать все это вручную и добавить в свои определения классов, но тогда, если вы захотите внести изменения, вам придется все остановить, перекомпилировать, повторно протестировать и попробовать еще раз. Было бы намного проще просто иметь список этих значений и настраивать их по мере необходимости.
Теперь, если у вас есть таблица данных, база данных, объект-контейнер, которым вы можете манипулировать вне вашей игры, это позволит вам приспосабливаться к значениям. Внезапно вы становитесь волшебником, поскольку изменения этих точек данных становятся тривиальными. Обновите файл, сохраните и повторно запустите игру.
Хорошо, я продан, так как мне его сделать?
Таблицы данных — это, по сути, USTRUCTS, производные от FTableRowBase. Наследование от FTableRowBase — это то, что позволяет вводить их в качестве определений DataTable в Unreal Engine, без этого они являются просто старыми структурами.
ПРИМЕЧАНИЕ:
Чтобы использовать DataTables, вам необходимо убедиться, что вы включаете заголовок DataTables в свой код.
Вот так: #include 'Engine/DataTable.h'
Теперь давайте посмотрим, как выглядит DataTable в действии.
// Header #include "Engine/DataTable.h" USTRUCT(BlueprintType) struct FPlayerAttackMontage : public FTableRowBase { GENERATED_BODY() public: /** montage **/ UPROPERTY(EditAnywhere, BlueprintReadWrite) UAnimMontage* Montage; /** count of animations in montage **/ UPROPERTY(EditAnywhere, BlueprintReadWrite) int32 AnimSectionCount; /** description **/ UPROPERTY(EditAnywhere, BlueprintReadWrite) FString Description; };
Это было довольно просто, что теперь?!
Что ж, теперь у вас есть несколько вариантов:
- Вы можете читать данные из таблицы данных непосредственно в C++, а также записывать записи.
- Вы можете импортировать данные, которые входят в таблицу данных, из файла CSV или JSON, чтобы сэкономить время, см. видео.
- Вы можете создавать их на лету и делать с ними все, что вам нужно.
Итак, давайте взглянем на чтение, так как это будет основной функцией.
// Header UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = Animation, meta = (AllowPrivateAccess = "true")) class UDataTable* PlayerAttackMontageData; // Source - constructor static ConstructorHelpers::FObjectFinder<UDataTable> PlayerAttackMontageObject(TEXT("DataTable'/Game/TUTORIAL_RESOURCES/DataTables/PlayerAttackMontage.PlayerAttackMontage'")); if (PlayerAttackMontageObject.Succeeded()) { PlayerAttackMontageData = PlayerAttackMontageObject.Object; } // Source - calling data table static const FString ContextString(TEXT("Player Attack Montage")); FPlayerAttackMontage* AttackMontage = PlayerAttackMontageData->FindRow<FPlayerAttackMontage>(FName(TEXT("Punch1")), ContextString, true); if (AttackMontage) { // generate number between 1 and whatever the data table contains for animation counts: int MontageSectionIndex = rand() % AttackMontage->AnimSectionCount + 1; FString MontageSection = "start_" + FString::FromInt(MontageSectionIndex); PlayAnimMontage(AttackMontage->Montage, 1.f, FName(*MontageSection)); }
Читать легко, творить сложно!
В дополнение к чтению мы также можем писать в наши таблицы данных из нашей игры.
// define our data table struct FPlayerAttackMontage NewAttackMontage; NewAttackMontage.AnimSectionCount = 10; NewAttackMontage.Montage = NULL; NewAttackMontage.Description = "Newly added row"; // call AddRow to insert the record PlayerAttackMontageData->AddRow(FName(TEXT("New Row")), NewAttackMontage);
Не плохо, а люди? К ним довольно легко привыкнуть, и они дают массу преимуществ при разработке сложных игровых систем.
Для получения более подробной информации по этим различным темам перейдите по ссылкам ниже: