Hands-On Artificial Intelligence with Unreal Engine
上QQ阅读APP看书,第一时间看更新

AI Controller in C++

If you have decided to create this simple AI controller in C++, let's get started. I'm assuming that your Unreal Editor is already set up to work in C++ (e.g. you have Visual Studio installed, symbols for debugs, etc.... Here is a reference link so that you can get started: https://docs.unrealengine.com/en-us/Programming/QuickStart) and that you have basic knowledge of how C++ works in Unreal. Here is a link for the naming convention so that you understand why some classes are prefixed with letters in the code: https://docs.unrealengine.com/en-us/Programming/Development/CodingStandard.

Before you start, remember that in order to work on AI in C++, you need to add the public dependencies in your  your .cs file (in this case,  UnrealAIBook.cs ), and add  GameplayTasks  and AIModule  as public dependencies, like in the following code:
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "HeadMountedDisplay", "GameplayTasks", "AIModule" });
This will ensure that your code will compile without problems.

Let's create a new C++ class, as shown in the following screenshot:

The class needs to inherits from the AIController class. You might need to check the Show All Classes checkbox in the right-top corner and then use the search bar, as shown in the following screenshot:

Click on Next and name the class MyFirstAIController. Moreover, I'd suggest that you keep our project tidy. Thus, click on the Choose Folder button. Unreal will prompt you to go to your system folder explorer. Here, create a folder named Chapter2, and within it a sub-folder named AI. Choose this folder as the place where you are going to store the piece of code we are going to create. This is what the dialogue box should look like, just before you click on Create:

Now, click on Create and wait for your editor to load. You might see something like this:

The structure of our code will be slightly different compared to the Blueprint version. In fact, we cannot assign a Behavior Tree directly from the AI Controller class (mainly because it would be hard to reference it directly); instead, we need to take it from the Character. As I mentioned previously, this is a good approach when you're working with Blueprints too, but since we have chosen a C++ project, we should look at some code. In Visual Studio, open the UnrealAIBookCharacter.h file, and just below the public variables, add the following lines of code:

    //** Behavior Tree for an AI Controller (Added in Chapter 2)
UPROPERTY(EditAnywhere, BlueprintReadWrite, category=AI)
UBehaviorTree* BehaviorTree;

For those who are still unfamiliar, here is a larger chunk of code so that you can understand where to place the preceding code within the class:

public:
AUnrealAIBookCharacter();

/** Base turn rate, in deg/sec. Other scaling may affect final turn rate. */
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category=Camera)
float BaseTurnRate;

/** Base look up/down rate, in deg/sec. Other scaling may affect final rate. */
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category=Camera)
float BaseLookUpRate;

//** Behavior Tree for an AI Controller (Added in Chapter 2)
UPROPERTY(EditAnywhere, BlueprintReadWrite, category=AI)
UBehaviorTree* BehaviorTree;

Moreover, to compile the preceding code, we also have to include the following statement at the top of the class, just above .generated:

#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "BehaviorTree/BehaviorTree.h"
#include "UnrealAIBookCharacter.generated.h"

Close the Character class, since we have finished with it. As a result, every time we have an instance of that character placed in the world, we will be able to specify a Behavior Tree from the Details panel, as shown in the following screenshot:

Let's open the header (.h) file of our newly created AI controller (it should already be open in Visual Studio if you are using it as an IDE). In particular, we need to override a function of the AI Controller class. The function we are going to override is called Possess(), and it allows us to run some code as soon as this AI Controller possess a new Pawn (that is, when it takes control of the character, which is a Pawn). Add the following code in bold (within a protected visibility):

UCLASS()
class UNREALAIBOOK_API AMyFirstAIController : public AAIController
{
GENERATED_BODY()

protected:

//** override the OnPossess function to run the behavior tree.
void OnPossess(APawn* InPawn) override;


};

Next, open the implementation (.cpp) file. Once again, to use Behavior Trees, we have to include both Behavior Trees and the UnrealAIBookCharacter class:

#include "MyFirstAIController.h"
#include "UnrealAIBookCharacter.h"
#include "BehaviorTree/BehaviorTree.h"

Next, we need to assign a functionality to the Possess() function. We need to check whether the Pawn is actually an UnrealAIBookCharacter, and if so, we retrieve the Behavior Tree and run it. Of course, this is surrounded by an if statement to avoid our pointers being nullptr :

void AMyFirstAIController::OnPossess(APawn* InPawn)
{
Super::OnPossess(InPawn);
AUnrealAIBookCharacter* Character = Cast<AUnrealAIBookCharacter>(InPawn);
if (Character != nullptr)
{
UBehaviorTree* BehaviorTree = Character->BehaviorTree;
if (BehaviorTree != nullptr) {
RunBehaviorTree(BehaviorTree);
}
}
}
If, for any reason, you cannot get the code to work, you can just use a Blueprint controller to start the Behavior Tree, or just inherit the C++ controller, and make sure that all rest of the code runs, and make a call to the RunBehaviorTree() function in Blueprint.

Once we have compiled our project, we will be able to use this controller. Select our AI character from the Level (if you don't have it, you can create one) and this time, in the Details panel, we can set our C++ controller, as follows:

Also, don't forget to assign the Behavior Tree as well, which we always do in the Details Panel:

As a result, once the game starts, the enemy will start executing the Behavior Tree. At the moment, the tree is empty, but this gives us the structure we need so that we can start working with Behavior Trees. In the following chapters, we are going to explore Behavior Trees more in detail, especially in chapters 8, 9, and 10, where we will look at a more practical approach to designing and building Behavior Trees.