Different variable type according to enum?

Hello, I am making a game where a player levels up and unlocks upgrades. I tried making a data table to store each upgrade type and value according to the level the player has reached. The structure looks like this:

Level/Upgrade/Value, eg 2/Health/+0.05 (which means the player gets a health increase by 0.05 percent at level 2)

Im using an enum for the upgrade type. However, things get complicated when an upgrade unlocks a new ability and doesnt have to do with a numeric value (like in the example above). The problem would be solved if there was a wildcard variable for the ā€œvalueā€ but there isnt.

Is there a way to change the variable type according to the enum value? For example if I set the enum to ā€œunlock abilityā€ the variable type changes to an ability class (that I have setup)?
I know this is probably not possible in a data table but what is the best way to handle this?Should I just add all the variable types I need and just use those that I want in each row or is it expensive to have many variables in each row that arent used?

I assume you want to create a system that automates the level up process and ability / upgrade system. Basically, you setup the structure and functions and then once all is setup the rest of the code executes without you having to do any other work.

If you want to do such a thing, a great solution would be to create a class or component which you can call or add to your character that shall receive the upgrades.

I would create a struct to handle the bulk data:

{
  "upgrades": [
    {
      "level": 2,
      "upgradeType": "Health",
      "value": 0.05
    },
    {
      "level": 5,
      "upgradeType": "UnlockAbility",
      "value": "Fireball"
    },
    {
      "level": 8,
      "upgradeType": "UnlockAbility",
      "value": "Teleport"
    }
  ]
}

I would also create an Enum for the upgradeType. Having the enum as an upgrade type would allow me to execute various functions based on the task at hand.

With all of this said, the execution flow would be as follows:

  1. When the character levels up you trigger the class or component to look if there is any new ability to unlock. This is simply done by comparing the new level to the required level for unlocking an ability.
  2. If there is an ability to unlock what type is it? If it is a Health upgrade, check the enum and execute the Upgrade Health function you created.

Since unlocking a spell should be the same process for every spell, you can simply have one function to rule them all. Simply just take the output of the struct to know what type of spell to unlock and you should be fine. The spells themselves could also be a struct which will allow you to modify their strengths as you level up further.

I hope this makes sense, and best of luck! :slight_smile:

But, what should the variable type of Value be? Since it will need to handle both numeric and (ability) class input? Is there a way to do it without c++?

A way would be to have the third item being a structure in itself, for example: Level(int)/Upgrade(enum)/Value(structB), where structB contains a intValue/EnumValue/StringValue/Class etc. When you read the table you base what Value you retreive from StructB based from your Upgrade (enum). This means each row will have some ā€˜unused’ or default values, which is not ideal, but it will work.

Thanks for your reply, do you think I should use this way or is there a more optimal way? I’m willing to leave the data table and use something else if it works ideally.

Sorry I am not sure of the best method. I have never used the Gameplay Ability System which also requires some C++ coding, however it seems to be built for this type system. There was a free demo game called ā€œAction RPGā€ that demonstrated this.

There is also other free games like ā€œAdvanced Stats with Runes Systemā€ that looks to have similar things that you require.

I know that sometimes there are issues with structures once you change them. So I would make sure that you cover all the required attributes in the structure before going too far.

Good luck

Could you produce an example of such ability? Instead of Health++, we now get to shoot fireballs when we double jump? That kind of thing?

I have created an ability system that uses abilities that derive from a BaseAbility parent class. The abilities could be a fireball or a teleport ability that can be used by the player during the game. So basically, when the player levels up he either gets a health buff, or a damage buff, or a new ability, depending on a list of upgrades based on the level of the player.

BaseAbility parent class.

I’d keep the data table and add actor components to the mix

  • comps:

image

  • struct that goes into the table holds stats and a potential ability class:

image

We learn to cast balls of fire at lvl 3 and teleport at lvl 10.

  • the base comp class has a virtual event:

image

  • player levels up, gets stats, and a new ability!

The last node:

image

  • the fireball actor component extended from base class:

  • player using the new fireball


This can be done with actor classes, ofc but components seem to fit here better (unless you need to run timelines).

1 Like

I see. Is there any performance cost /disadvantage of having many rows with unused data? Since not every row is going to have an upgrade to all the stats (or a new ability) and I’ll end up with a lot of ā€œ0ā€ and ā€œnoneā€ values. Is this alright?

Good question. The cost is there but would be negligible. However, you can completely offset it by using soft class references:

1 Like

Thank you very much! I didn’t really pay any attention to the soft references, and they seem to be very useful. I guess there isn’t such thing about the float values, that makes them invisible rather than just ā€œ0ā€?

Not to my knowledge. I don’t even know how you’d measure any performance hit here, not sure if this is measurable. The visible clutter can be a nuisance, but structs can be nested, it makes them more crashy, though. :innocent:

If it’s purely visual, we can always tick stuff that is not needed:

I’m pretty sure you meant that it bothers you the struct entries needlessly exist. I wouldn’t worry about optimisation, not in this very case.

Yeah, that was what I was worrying about. If only there was a way to have a dynamic variable type that changes according to what upgrade is implemented, it would be very convinient but I guess there isn’t, at least with blueprints. I’ll stick with your advice since it seems to be the best way.

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.