Unreal Engine - Using Tasks to Sequence Events
Let the engine manage dependencies and sequence the code
Introduction
In the course of a game, there are times that the input from a player will initiate a predetermined sequence of events. The individual steps of an event may have a complicated dependency structure where some parts are prerequisites of others while other parts may be able to run in parallel. Unreal Engine provides the Tasks System, a generic job system that can handle sequencing of events and does so asynchronously by default.
Demonstration
Below is a demonstration of how the Tasks System can be used inside of a ViewModel.
Tasks are run via the Launch function in the UE::Tasks namespace. The function takes the following parameters:
A debug string. The provided UE_SOURCE_LOCATION macro will set the debug string to the name and line number of the source file
The task to run. This is either a lambda or an rvalue reference to a functor — an object with an overloaded operator()
An optional list of prerequisite tasks.
In this demonstration, Tasks 2 and 3 have a prerequisite of Task 1. The final task has prerequisites of Tasks 2 and 3. As the name implies, all prerequisites must be complete before a given task will start; therefore Task 2 and 3 will start in parallel as soon as Task 1 is complete. Task 4 will only start after both Task 2 and 3 are complete.
Below is the definition of the functor used in this function.
Finally, below is the SetLoadingTaskColor function that the functor calls:
Since the Task System doesn’t run code on the GameThread, SetLoadingTaskColor must use the AsyncTask method to force the color changing code on the GameThread as Unreal requires all UI changes to happen there.
The video below shows the TaskDemonstration function in action:
Example
A common event sequence found in games is going from one world to another, for example a main menu screen to an in-game world. In Unreal Engine, this would commonly be the result of a ClientTravel call on the PlayerController. This process can be hidden behind a loading screen that persists until the target world is ready for the player.
The video below shows a travel sequence made up of several tasks. The loading screen remains visible until all tasks are complete, demonstrated by the three green squares at the completion of the sequence.
Task Events
Sometimes Tasks may take several frames to complete, e.g. traveling to another world. Since a Task is marked as complete after the code in operator() completes (or the lambda code completes if using one), there needs to be another mechanism to inform dependent Tasks when a given Task is “actually” complete.
This is where Task Events can be useful. Instead of using a Task as a prerequisite, a Task Event that must be manually triggered can be used as a substitute.
Below is an example of a Task that travels to another world and triggers a Task Event when that travel is complete:
Below is another example of a Task that defines a Task Event. The Task Event is passed along to another ViewModel for triggering completion after the simulated loading completes and the GameThread has updated the color accordingly.


Finally, here is the code that runs all the tasks when the Travel to Another World button is clicked:
The function breaks down as follows:
A loading screen widget is placed over the entire screen
A Task is started to travel to another world
3 Simulate Loading Tasks are created, all with a prerequisite of the OnTravelComplete Task Event being triggered
Finally, using a lambda version of a Task, the loading screen widget is removed from the viewport after the 3 Task Events from the 3 Simulate Loading Tasks are triggered
Conclusion
Unreal Engine’s Task System is a great built-in tool for running parallel tasks and can handle complicated dependency structures.
Example code can be found here.
Example data can be found here.