A Very Quick Guide on Implementing Gameplay Systems in Unreal Editor 4 Blueprint
A.k.a how to tack code to things that don’t easily allow code to be tacked to them.
I have been messing around with unreal editor since the first year of university. Not because it had anything to do with the bachelor’s degree I was doing, or the master’s degree I am doing now, but because I wanted to help my friends make a game they are making. After the most experienced of the group went to work for a real game company, I took the role of lead programmer, and was the one to direct the way we would implement the various game systems into the engine.
The following is a guide on what you should use to implement any game system in Unreal Engine 4, from my experience. These aren’t hard rules, but they will help you think though all of the limitations of the systems in the engine, before you make the critical mistake of implementing using one system and having to tear it all out and reimplement it using another.
Although I have written this guide for Blueprint, it may also come in useful for understanding how the systems work in C++ too. If you have any suggestions, let me know on Twitter.
What are we trying to do?
The first question you should ask yourself when trying to implement anything is if it should be implemented as a function or an event. Ask yourself: Is the thing you are trying to do reliant on a “latent node”, such as a “Delay” node, or “MoveTo” node? These “latent nodes” take an amount of game time to complete, and therefore can not be included inside a function.
A lot of people mistakenly think that you can’t get information back from an event as it doesn’t have a return node. This is true, but you shouldn’t consider this as part of your answer.
It doesn’t rely on latent nodes (it’s a Function)
Can it be a function inside an actor (is the actor an editable, non-engine actor)?
Create a new function inside the actor (or the most common ancestor of all the actors you want to have the function work in) and implement it there. If the most common ancestor isn’t available, see the other answer.
It can’t be a function inside an actor (For example, you can’t create a new function for the base “Actor” class, as it is an engine class, without editing the engine, which you probably shouldn’t do. Another reason is if it is being performed on an Object rather than an actor.)
In this case, there are a number of different ways you can implement the system:
Is the function going to be the same for all the actors (such as getting the actor, putting it into a lookup table, and then outputting something else), or will there be a significant amount of functions?
If this is the case, use a Function Library. Create a function in the library that accepts the actor and use this to perform any function you need on the actors. Function Libraries can be sort of thought of as static functions from other languages.
Does the function need to be implemented differently for each actor?
In this case, use an Interface. Interfaces can act as functions if they are given return values.
Note: something else to consider: if you make a “getter” function, set it to “const” in the advanced dropdown of the function. This firstly makes sure that the getter doesn’t modify state (which is a good idea if you want your code to be clean and make sense) and also, I believe it makes your games run faster (it’s good for compilers?).
It does rely on latent nodes (It’s an Event)
Can it be an event inside an actor (is the actor an editable, non-engine actor)?
Create a new event inside the actor (or the most common ancestor of all the actors you want to have the function work in) and implement it there. If the most common ancestor isn’t available, see the other answer.
It can’t be an event inside an actor (For example, you can’t create a new function for the base “Actor” class, as it is an engine class, without editing the engine, which you probably shouldn’t do.)
In this case, there are a number of different ways you can implement the system:
Does it need to tick or keep track of its own variables?
If this is the case, use an actor component. Create a new actor component and apply it to whatever actors you need. If you need to get information back out of the event, use an Event Dispatcher.
It doesn’t need to tick or keep track of its own variables.
If this is the case, use a Macro Library. Create a Macro in the library (and make the library for that class of object you plan to use the library in) and use this to perform any timed nodes you need on the object. If you need to get information back out of the event, use the return nodes.
Does it need to be implemented differently by each object that it’s called on?
Use an interface with no return value.