In the last chapter, we covered how to use Data Tables to import custom data. Before that, we decided on what stats would play into combat and how. Now we're going to combine those to define our game's characters, classes, and enemy encounters.
Remember that in Chapter 1, Getting Started with RPG Design in Unreal, we established that our characters have the following stats:
Of these, we can discard health and magic because they vary during the game, while the other values are predefined based on the character class. The remaining stats are what we will define in the Data Table. As mentioned in Chapter 1, Getting Started with RPG Design in Unreal, we also need to store what the value should be at level 50 (the maximum level). Characters will also have some abilities they start out with, and some they learn as they level up.
We'll define these in the character class spreadsheet, along with the name of the class. So our character class schema will look something like the following:
The ability string arrays will contain the ID of the ability (the value of the reserved name
field in UE4). Additionally, there are two separate cells for learned abilities—one that contains the ability IDs, another that contains the levels at which those abilities are learned.
In a production game, one thing you might consider is writing a custom tool to help manage this data and reduce human error. However, writing such a tool is outside the scope of this book.
Now, instead of creating a spreadsheet for this, we're actually going to first create the class and then the Data Table inside Unreal. The reason for this is that at the time of writing, the proper syntax to specify arrays in a cell of a Data Table is not well documented. However, arrays can still be edited from inside the Unreal editor, so we'll simply create the table there and use Unreal's array editor.
Firstly, as usual, create a new class. The class will be used as an object that you can call from, so choose Object
as the parent class. Name this class FCharacterClassInfo
and, for organization purposes, path your new class to your Source/RPG/Data
folder.
Open FCharacterClassInfo.h
and replace the class definition with the following code:
USTRUCT( BlueprintType ) struct FCharacterClassInfo : public FTableRowBase { GENERATED_USTRUCT_BODY() UPROPERTY( BlueprintReadWrite, EditAnywhere, Category = "ClassInfo" ) FString Class_Name; UPROPERTY( BlueprintReadWrite, EditAnywhere, Category = "ClassInfo" ) int32 StartMHP; UPROPERTY( BlueprintReadWrite, EditAnywhere, Category = "ClassInfo" ) int32 StartMMP; UPROPERTY( BlueprintReadWrite, EditAnywhere, Category = "ClassInfo" ) int32 StartATK; UPROPERTY( BlueprintReadWrite, EditAnywhere, Category = "ClassInfo" ) int32 StartDEF; UPROPERTY( BlueprintReadWrite, EditAnywhere, Category = "ClassInfo" ) int32 StartLuck; UPROPERTY( BlueprintReadWrite, EditAnywhere, Category = "ClassInfo" ) int32 EndMHP; UPROPERTY( BlueprintReadWrite, EditAnywhere, Category = "ClassInfo" ) int32 EndMMP; UPROPERTY( BlueprintReadWrite, EditAnywhere, Category = "ClassInfo" ) int32 EndATK; UPROPERTY( BlueprintReadWrite, EditAnywhere, Category = "ClassInfo" ) int32 EndDEF; UPROPERTY( BlueprintReadWrite, EditAnywhere, Category = "ClassInfo" ) int32 EndLuck; UPROPERTY( BlueprintReadWrite, EditAnywhere, Category = "ClassInfo" ) TArray<FString> StartingAbilities; UPROPERTY( BlueprintReadWrite, EditAnywhere, Category = "ClassInfo" ) TArray<FString> LearnedAbilities; UPROPERTY( BlueprintReadWrite, EditAnywhere, Category = "ClassInfo" ) TArray<int32> LearnedAbilityLevels; };
Most of this code should be familiar to you already; however, you may not recognize the last three fields. These are all of the TArray
type, which is a dynamic array type provided by Unreal. Essentially, a TArray
can have elements dynamically added to it and removed from it, unlike a standard C++ array.
Upon compiling this code, create a new folder called Data
within your Content
folder so that you can stay organized by keeping Data Tables that you create within the Data
folder. Navigate to Content | Data in the Content Browser and create a new Data Table by right-clicking on Content Browser and choosing Miscellaneous | Data Table. Then, select Character Class Info from the drop-down list. Name your Data Table CharacterClasses and then double-click to open it.
To add a new entry, hit the + button. Then, give a name to the new entry by entering something in the Row Name field and pressing Enter.
After an entry has been added, you can select the entry in the Data Table pane and edit its properties in the Row Editor pane.
Let's add a Soldier class to the list. We will it give the name S1
(which we'll use to refer to the character class from other Data Tables) and it will have the following properties:
When you are finished, your Data Table should look like this:
If you have more character classes that you would like to define, continue to add them to your Data Table.
With classes defined, let's take a look at characters. Since most of the important combat-related data is already defined as part of a character's class, the character itself is going to be quite a bit simpler. In fact, for now, our characters will be defined by just two things: the name of the character and the character's class.
Firstly, create a new C++ class called FCharacterInfo
whose parent is Object
, and path it to the Source/RPG/Data
folder. Now, replace the class definition in FCharacterInfo.h
with this:
USTRUCT(BlueprintType) struct FCharacterInfo : public FTableRowBase { GENERATED_USTRUCT_BODY() UPROPERTY( BlueprintReadWrite, EditAnywhere, Category = "CharacterInfo" ) FString Character_Name; UPROPERTY( BlueprintReadOnly, EditAnywhere, Category = "CharacterInfo" ) FString Class_ID; };
As we did earlier, we're just defining the two fields for the character (character name and class ID).
After compiling, create a new Data Table in your Data
folder that you created earlier from within the Content Browser and select CharacterInfo as the class; call it Characters
. Add a new entry with the name S1
. You can name this character whatever you like (we named our character soldier Kumo), but for class ID, enter S1
(as this is the name of the Soldier class we defined earlier).
As for enemies, rather than defining a separate character and class information, we'll create a simplified combined table for these two pieces of information. An enemy generally does not have to deal with experience and leveling up, so we can omit any data related to this. Additionally, enemies do not consume MP as players do, so we can omit this data as well.
Therefore, our enemy data will have the following properties:
Much like the previous Data Class creations, we create a new C++ class that derives from Object
, but this time we will call it FEnemyInfo
and place it with the rest of our data in the Source/RPG/Data
directory.
At this point, you should have an understanding of how to construct the class for this data, but let's take a look at the struct header anyway. In FEnemyInfo.h
, replace your class definition with the following:
USTRUCT( BlueprintType ) struct FEnemyInfo : public FTableRowBase { GENERATED_USTRUCT_BODY() UPROPERTY( BlueprintReadWrite, EditAnywhere, Category = "EnemyInfo" ) FString EnemyName; UPROPERTY( BlueprintReadOnly, EditAnywhere, Category = "EnemyInfo" ) int32 MHP; UPROPERTY( BlueprintReadOnly, EditAnywhere, Category = "EnemyInfo" ) int32 ATK; UPROPERTY( BlueprintReadOnly, EditAnywhere, Category = "EnemyInfo" ) int32 DEF; UPROPERTY( BlueprintReadOnly, EditAnywhere, Category = "EnemyInfo" ) int32 Luck; UPROPERTY( BlueprintReadOnly, EditAnywhere, Category = "EnemyInfo" ) TArray<FString> Abilities; };
After compiling, create a new Data Table, select EnemyInfo
as the class, and call the Data Table Enemies
. Add a new entry with the name S1
and the following properties:
At this point, we've got the data for a character, the character's class, and a single enemy for the character to fight. Next, let's start keeping track of which characters are in the active party and what their current stats are.
3.145.50.222