Best way to storage and use data for objects?

'm working on a JRPG game which will feature many characters and many classes. Of course I’ll need a way to store information about all these characters and classes, including the ones that the player hasn’t unlocked yet.

At first I thought of creating a separate class for each character / class, but then the sheer number of C++ classes that would populate the solution made me change my mind.

Currently I’m doing a way which is working, but I’m not sure if it’s optimal, and so far I haven’t implemented huge differences between classes, just numeric stats changes. How it works: in my game instance, I have a set of characters (character roster) and a set of classes (for all available classes), and an array of characters to represent the current party (the distinction between character and class is because more than one character can have the same class). By the way, character and class are objects (classes inheriting from UObject), but instead of having one object class for each character, I have only one, and construct characters in the game instance.

I created a custom blueprint function (in the game instance) called Add Character to Roster, with input arguments being all the properties needed to define a character (name, level, model, class, etc.). So I have a different function for each character, with these properties hardcoded (so my Game Instance has one function for each character and one for each class).

What do you think of this approach? I was considering also getting data from excel, instead of typing it directly within a function in the game instance, although I still wouldn’t know how to implement variations like classes’ differences in attacks and skills (for now, classes only differ in stats like Strength, Vitality, etc.). Should I maybe try to have a class for each character and playable class?

If you make a separate class for every character type, you’re misunderstanding what a class is designed for. That’s why making 50+ classes for each character sounds daunting – because it is!

What I would do is create a general “character” class for your game. Treat it as a base class. Then, if you have a few different character categories, those character categories can inherit from the base character class and implement their category unique attributes and functionality. Sometimes, the only difference between one type of character and another type might just be a few differences in variable values, so that difference may probably not be notable enough to warrant a separate class. So, with that in mind, you have to think carefully about what is a classification type variable vs what is an instance type variable.

For example, let’s pretend we have a fantasy game. We have swordsmen, magicians, archers, humans, goblins, horses, dogs, and cats. How would you design a class system to capture this?

I would probably create a “Creature” base class. That might be all I need. Everything else can be captured with data values. Swordsmen, magicians, archers could all just be a “profession” variable. humans, goblin or animal could be an enum value. Horses, dogs and cats could be another variable. You could put everything into this base class and let instance data define the actual creature. You could also create an “Animal” class which inherits from the “Creature” class to make horses, dogs and cats distinct from “humanoids” like humans and goblins. But, do you need to? That depends entirely on whether you actually need to make a functional distinction between the two classes.

In terms of instance data, you could look into data tables as a way to store class instance data values. Instead of creating a separate goblin blueprint, just to change a few instance values, you can have a row in your creature table which contains all of the goblin specific attributes. When you spawn a goblin from a creature class, you can just query this data table value to get these values. With this setup, you could easily support hundreds of character types through a few classes.

Just to jump in here, I’m pretty new to C++ and Unreal too but have discovered and been using data tables myself. Is there any advantage to using Structs rather than classes for something like this? In my case I’m making weapons instead of characters, but it’s the same principle. Let me explain what I’m thinking and you can let me know if I’m over-complicating things. I do think that this would be relevant to the OP because we’re trying to accomplish essentially the same thing.

Right now I’m using a data table to set values in the class (things like muzzle velocity, damage done, etc.) via an FDataTableRowHandle variable. If I intend to have similar classes (like VehicleWeapons) that use this same data but otherwise might function slightly differently, should I instead make this data a UStruct which I then add as a variable to each of these broader classes? Or maybe make an actor component that holds these values instead, and set its member variables using the data table?

I don’t know if any of these are “good” options, but I’d be interested in people’s thoughts. While I love the freedom of “Do what gets the job done!” I’m not always sure if I’m really doing things efficiently.

I personally use ‘Gameplay Tags’ for this, structs become convoluted quickly, but it’s a somewhat new feature and docs aren’t very feature complete:

Well… a struct is very similar to a class. In the C language, classes didn’t actually exist and people just used structs everywhere. Classes came into existence with C++ and helped create object oriented programming. Classes are structs, but extend the capabilities. A class can inherit from other classes, structs cannot. A class can also have member functions, but typically structs do not. People think of structs primarily as data containers and classes like objects which can be instantiated, but you can very easily use a class like a struct. As far as the compiler is concerned, they’re organized very similarly in memory.

You can use a data table. There’s nothing wrong with that. In some cases, it would be a good idea. I tend to think of classes like templates with variable values which can be set on a per-instance basis. If you have a soldier class, it will have a lot of properties which are common to all soldiers. But, if you created a 100 instances of soldiers and wanted to have a little bit of variety between soldiers (such as variations in hitpoints, endurance, strength, etc), you could either create a bunch of soldier variants with preloaded data values or select the values randomly from a preset range. If you have premade variants, you could just toggle the soldier variants with a drop down list which maps to an ID, and that ID can function as a lookup value which pulls a data table row and loads the soldier with the resulting values. You could also manually set these values from a blueprint with a large switch statement and hard coded values. But, using a data table is a bit more elegant because it can contain data values for multiple soldier classes (infantry, medic, rocketeer, demolitions, etc). All the variants can be stored in one file, so if you want to modify the properties of a soldier variant, you can do it from the data file instead of opening up each blueprint and modifying the hard coded values. For you, the decision you’ll need to make is “what variables belong in a data table?”.

That’s awesome stuff, thanks guys. I have a pretty good idea of what I want in the data tables and they make the most sense for what I’m doing, and gameplay tags sound like an awesome way to organize the data being used for my different “families” of subclasses. I’ll have to look into them more but they seem pretty useful.

I think it sounds like the use of an additional struct or actor component just adds an a additional and unnecessary step so I’m gonna avoid it for now. Thanks again, fellas!