Creating a new C++ Behaviour Module - Unreal
In this section, we are going to create a new behaviour module: the follow target module.
Set up Atoms
Add the AtomsUnreal plugin to your unreal projects.
Open the Plugins dialog from the Edit menu. Go inside the “Installed” section and enable the AtomsUnreal plugin.
Before you start creating the behaviour module, you need to add the AtomsUnreal and AtomsRealtime dependency to your build config file.
Open your Build.cs file in your project, then add the “AtomsUnreal“ and “AtomsRealtime” modules.
using UnrealBuildTool;
public class AtomsDemo : ModuleRules
{
public AtomsDemo(ReadOnlyTargetRules Target) : base(Target)
{
PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
PublicDependencyModuleNames.AddRange(
new string[] {
"Core",
"CoreUObject",
"Engine",
"InputCore",
"AtomsRealtime",
"AtomsUnreal"
});
PrivateDependencyModuleNames.AddRange(new string[] { });
}
}
Create the Atoms module
In your project, create a new header file called MyFollowTargetBehaviourModule.h.
In this file, create a new class and inherit from the base Atoms::BehaviourModule class. Define a constructor, a destructor and a static creator function (needed by Atoms to create an instance of this module).
#pragma once
#include <Atoms/BehaviourModule.h>
class MyFollowTargetModule: public Atoms::BehaviourModule
{
public:
MyFollowTargetModule();
virtual ~MyFollowTargetModule();
static Atoms::BehaviourModule* creator(const std::string& parameter);
};
Now add a MyFollowTargetBehaviourModule.cpp file to your project.
In this file, implement the constructor, destructor and creator functions.
#include "MyFollowTargetBehaviourModule.h"
MyFollowTargetModule::MyFollowTargetModule() : Atoms::BehaviourModule()
{
}
MyFollowTargetModule::~MyFollowTargetModule()
{
}
Atoms::BehaviourModule* MyFollowTargetModule::creator(const std::string& parameter)
{
return new MyFollowTargetModule();
}
Register the behaviour module
Now you need to register your new module. Go inside the StartupModule() function of your game module and register your new behaviour module.
Now de-register the module inside the ShutdownModule() function of your game module.
Add input Attributes
You need to add now some input attributes.
For this module, you need only a target position attribute. The module's attributes are stored inside a MapMetadata object, you can add new attributes using the "addAttribute" function. Attributes should always be added inside the constructor.
The third attribute of the addAttribute method defines if the attribute is overridable per agent or not. In this example, we'll make it overridable.
Implement the behaviour logic
Now you need to compute the new agent direction at each frame before the agent pose is computed. This will be done inside the initFrame method.
For this example, we won't need to override any other method.
Please have a look at the Behaviour Module documentation if you want to implement other methods.
In the initFrame function, get the targetPosition value, iterate over each agent to read the position and set their new direction.
Use per agent attributes
The target position attribute is overridable per agent, but the code to handle it isn't there yet. When you override an attribute, new map metadata named "AttributeName_override" is created. The keys of this map metadata are the agent group ids, but they will be present only when the user specifies an override from inside his 3D application.
Use the function getAttributePerAgent
to get the value per agent. This function checks if there is an override and returns the value, otherwise it returns the default value.
Improve performance
If you want to improve the performance of the module, you can parallelize the main for loop.
Create an UAtomsBehaviourComponent
The atoms behaviour module is now ready. Now you need to create an UAtomsBehaviourComponent to use your behaviour module in unreal.
In your project, create a new class MyFollowtargetBehaviourComponent and inherit from the UAtomsBehaviourComponent.
You need to add these arguments to the UCLASS.
You need to add the constructor and destructor.
Implement the constructor setting the AtomsBehaviourModule
member. This variable contains the name of the Atoms behaviour module that this component creates.
Add attributes uproperty
You need now to expose the target position property and pass its value to the atoms behaviour module.
Add an FVector property to your class and call it “targetPosition”. This is the same name of the attribute inside the atoms behaviour module. Set the property as BlueprintReadOnly and EditAnywhere.
To expose the per-agent override attribute you need to add a uproperty for type TMap<int32, FVector>. The int32 key contains the agent group Id, while the vector value contains the override for that agent.
Now you need to implement the GetAtomsAttributes member to translate the unreal properties to the atoms module attributes. Luckily there are some defines that you can use to translate the properties.
Add Setter functions
The last step is to expose functions to set the component properties and update the atoms module attributes simultaneously.
We need to add a SetTargetPosition/SetTargetPositionOverride and RemoveSetTargetPositionOverride. The sequencer will also use the SetTargetPosition. So you need to implement this function if you want to drive this property by the sequencer.
This is called after the automatic translation.
The GetAtomsAttributes
and the OnBehaviourModuleCreated
method are called only once at the beginning of the simulation. If you want to update the attributes during the simulation, you need to turn on the UpdateOnTick property on the behaviour component. If you want to update the attributes manually outside the behaviour component, use the Set* function.
Final source files:
.
The module is now ready to be used. Create an agent group with a grid layout and a clipReader or state machine module. Add the new MyFollowTarget component and set the target position property. Press play and you are done!
Copyright © 2017, Toolchefs LTD.