Before I will move forward with perks I would like to show you guys how to get, set and increase variables (floats and ints) by name. You don’t need to have reference to variable to make operations on it.

In this tutorial I will create global functions that can:

Get/Set float by name,

Get/Set int by name,

Increase float/int by name,

Again I will use C++ for this and as always it will be super easy!

This Tutorial has been created using Unreal Engine 4.10

Make sure you are working on the same version of the engine.

Theory

Why you should make operations on variables by name? Because of the flexibility. Let me show you some examples.

Weapon Upgrade System is good example.

You can hard code all variables that upgrade system can support. You will be updating those variables during production. (eg. Designer want to have possibility to change fire rate) Other way is to create possibility to change variables by name. So designer can just configure upgrades without pinging programmers:

UpgradeName: Increase fire rate

VariableToIncrease: FireRate

IncreaseBy: 5

UpgradeName: Increase damage

VariableToIncrease: Damage

IncreaseBy: 15

This way your designer will be able to configure upgrades without pinging programmers to add / update whole system.

Another good example is RPG Skill system. You can hard code every skill or create similar system for designers:

SkillName: Fireball

ClassToSpawn: FireballProjectile

VariablesToChangeOnHitTarget: {Health, -50}, {DamageOverLife, 5}

VariablesToChangeOnOwner: {FireResistance, 10}

SkillName: Heal

ClassToSpawn: HealSelfParticleEffect

VariablesToChangeOnHitTarget:

VariablesToChangeOnOwner: {Health, 25}

They are just examples what you can do if you will think about iteration speed. Combining this with data in cloud your designers will be happy when balancing and creating new upgrades or skills. Of course you need to spend some time thinking about format for your upgrades/skills so they can be easily created by anyone in your team.

Hope you get the idea.

Global Functions

In this tutorial I won’t be creating perks yet. First I would like to show you guys how make changes to variables by name. I will use BlueprintFunctionLibrary as functions there can be called in any space in your project.

Create new C++ class named ShooterFunctions extending from BlueprintFunctionLibrary.

Functions in this class need to be static.

Get Float variable by name

Let’s start by getting float variable by name. In ShooterFunctions.h:

UCLASS() class SHOOTERTUTORIAL_API UShooterFunctions : public UBlueprintFunctionLibrary { GENERATED_BODY() public: UFUNCTION(BlueprintCallable, Category = "ShooterFunctions|Variables") static bool GetFloatByName(UObject* Target, FName VarName, float &outFloat); };

And in ShooterFunctions.cpp:

#include "ShooterTutorial.h" #include "ShooterFunctions.h" bool UShooterFunctions::GetFloatByName(UObject * Target, FName VarName, float &outFloat) { return false; }

Compile your game and open editor – when opening any blueprint you can find this function when typing GetFloatByName. For now it won’t do anything. Some explanation:

UObject* Target – this is reference to Object that we would like to search for variable in.

FName VarName – variable name to search for in Target.

&outFloat – “&” means return in blueprint node. It will returns found float.

Now let’s get back to function.

bool UShooterFunctions::GetFloatByName(UObject * Target, FName VarName, float &outFloat) { if (Target) //make sure Target was set in blueprints. { float FoundFloat; UFloatProperty* FloatProp = FindField<UFloatProperty>(Target->GetClass(), VarName); // try to find float property in Target named VarName if (FloatProp) //if we found variable { FoundFloat = FloatProp->GetPropertyValue_InContainer(Target); // get the value from FloatProp outFloat = FoundFloat; // return float return true; // we can return } } return false; // we haven't found variable return false }

Thanks to UE4 reflection you can access properties using TProperty. In this example I know I’m searching for float that’s why I’m using UFloatProperty. You can compile your game open editor and test this out!

I’m using Level Blueprint for tests.

Get Int variable by name

Now if you know the basics you should get the idea how to get int variable. In ShooterFunctions.h:

UFUNCTION(BlueprintCallable, Category = "ShooterFunctions|Variables") static bool GetIntByName(UObject* Target, FName VarName, int32 &outInt);

And in ShooterFunctions.cpp:

bool UShooterFunctions::GetIntByName(UObject * Target, FName VarName, int32 &outInt) { if (Target) { int32 FoundInt; UIntProperty* IntProp = FindField<UIntProperty>(Target->GetClass(), VarName); //this time I'm using UIntProperty as I'm searching for int if (IntProp) { FoundInt = IntProp->GetPropertyValue_InContainer(Target); outInt = FoundInt; return true; } } return false; }

This time I’m using UIntProperty as I’m searching for int. Compile and test it out!

Set Variables by name

Now let’s actually set some variables. In ShooterFunctions.h:

UFUNCTION(BlueprintCallable, Category = "ShooterFunctions|Variables") static bool SetFloatByName(UObject* Target, FName VarName, float NewValue, float &outFloat); UFUNCTION(BlueprintCallable, Category = "ShooterFunctions|Variables") static bool SetIntByName(UObject* Target, FName VarName, int32 NewValue, int32 &outInt);

And in ShooterFunctions.cpp:

bool UShooterFunctions::SetFloatByName(UObject * Target, FName VarName, float NewValue, float & outFloat) { if (Target) { float FoundFloat; UFloatProperty* FloatProp = FindField<UFloatProperty>(Target->GetClass(), VarName); if (FloatProp) { FloatProp->SetPropertyValue_InContainer(Target, NewValue); //this actually sets the variable FoundFloat = FloatProp->GetPropertyValue_InContainer(Target); outFloat = FoundFloat; return true; } } return false; } bool UShooterFunctions::SetIntByName(UObject * Target, FName VarName, int32 NewValue, int32 & outInt) { if (Target) { int32 FoundInt; UIntProperty* IntProp = FindField<UIntProperty>(Target->GetClass(), VarName); if (IntProp) { IntProp->SetPropertyValue_InContainer(Target, NewValue); //this actually sets the variable FoundInt = IntProp->GetPropertyValue_InContainer(Target); outInt = FoundInt; return true; } } return false; }

Using SetPropertyValue_InContainer on IntProp/FloatProp is actually changing the variable!

Increase Variables by name

Increasing variables is almost the same as setting them but you sets variable after increasing it.

In ShooterFunctions.h:

UFUNCTION(BlueprintCallable, Category = "ShooterFunctions|Variables") static bool IncreaseFloatByName(UObject* Target, FName VarName, float ValueToAdd, float &outFloat); UFUNCTION(BlueprintCallable, Category = "ShooterFunctions|Variables") static bool IncreaseIntByName(UObject* Target, FName VarName, int32 ValueToAdd, int32 &outInt);

And in ShooterFunctions.cpp:

bool UShooterFunctions::IncreaseFloatByName(UObject * Target, FName VarName, float ValueToAdd, float &outFloat) { if (Target) { float FoundFloat, IncreasedFloat; UFloatProperty* FloatProp = FindField<UFloatProperty>(Target->GetClass(), VarName); { if (FloatProp) { FoundFloat = FloatProp->GetPropertyValue_InContainer(Target); IncreasedFloat = FoundFloat + ValueToAdd; //increase the value FloatProp->SetPropertyValue_InContainer(Target, IncreasedFloat); //and then set it outFloat = IncreasedFloat; return true; } } } return false; } bool UShooterFunctions::IncreaseIntByName(UObject * Target, FName VarName, int32 ValueToAdd, int32 &outInt) { if (Target) { int32 FoundInt, IncreasedInt; UIntProperty* IntProp = FindField<UIntProperty>(Target->GetClass(), VarName); if (IntProp) { FoundInt = IntProp->GetPropertyValue_InContainer(Target); IncreasedInt = FoundInt + ValueToAdd; IntProp->SetPropertyValue_InContainer(Target, IncreasedInt); outInt = IncreasedInt; return true; } } return false; }

And that’s all! This is why C++ in UE4 is handy. Knowledge from this tutorial will be used in Perks implementation.

Here you can find .h and .cpp files: ShooterFunctions.cpp ShooterFunctions.h