Привет, ребята,

Мы собираемся продолжить изучение основ 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);

Не плохо, а люди? К ним довольно легко привыкнуть, и они дают массу преимуществ при разработке сложных игровых систем.

Для получения более подробной информации по этим различным темам перейдите по ссылкам ниже: