Calling Functions across the C++ and Blueprint Boundary
So far, we have shown how to expose properties to Blueprints, but there is one last introductory topic that we should cover before you dive deeper into the engine. During the creation of the gameplay systems, designers will need to be able to call functions created by a C++ programmer as well as the gameplay programmer calling functions implemented in Blueprints from C++ code. Let us start by first making the CalculateValues() function callable from Blueprints. Exposing a function to Blueprints is just as simple as exposing a property. It takes only one macro placed before the function declaration! The code snippet below show what is needed for this.
The UFUNCTION() macro handles exposing the C++ function to the reflection system. The BlueprintCallable option exposes it to the Blueprints Virtual Machine. Every Blueprint exposed function requires a category associated with it, so that the right click context menu works properly. The image below shows how the category affects the context menu.
As you can see, the function is selectable from the Damage category. The Blueprint code below shows a change in the TotalDamage value followed by a call to recalculate the dependent data.
This uses the same function that we added earlier to calculate our dependent property. Much of the engine is exposed to Blueprints via the UFUNCTION() macro, so that people can build games without writing C++ code. However, the best approach is to use C++ for building base gameplay systems and performance critical code with Blueprints used to customize behavior or create composite behaviors from C++ building blocks.
Now that our designers can call our C++ code, let us explore one more powerful way to cross the C++/Blueprint boundary. This approach allows C++ code to call functions that are defined in Blueprints. We often use the approach to notify the designer of an event that they can respond to as they see fit. Often that includes the spawning of effects or other visual impact, such as hiding or unhiding an actor. The code snippet below shows a function that is implemented by Blueprints.
This function is called like any other C++ function. Under the covers, the Unreal Engine generates a base C++ function implementation that understands how to call into the Blueprint VM. This is commonly referred to as a Thunk. If the Blueprint in question does not provide a function body for this method, then the function behaves just like a C++ function with no body behaves: it does nothing. What if you want to provide a C++ default implementation while still allowing a Blueprint to override the method? The UFUNCTION() macro has an option for that too. The code snippet below shows the changes needed in the header to achieve this.
This version still generates the thunking method to call into the Blueprint VM. So how do you provide the default implementation? The tools also generate a new function declaration that looks like
<function name>_Implementation(). You must provide this version of the function or your project will fail to link. Here is the implementation code for the declaration above.
// Do something cool here
Now this version of the function is called when the Blueprint in question does not override the method. One thing to note, is that in previous versions of the build tools the _Implementation() declaration was auto generated. In any version 4.8 or higher, you'll be expected to explicitly add that to the header.
Now that we have walked through the common gameplay programmer workflow and methods to work with designers to build out gameplay features, it is time for you to choose your own adventure. You can either continue with this document to read more about how we use C++ in the engine or you can jump right into one of our samples that we include in the launcher to get a more hands on experience.