Hitman
Disguise System
Engine and Creation
-
Developed With: Unreal Engine 4 and C++
-
Date Developed: September 2021 - May 2022
-
Status: Finished
Main Features
-
Interactions with the world based on their own personality trait
-
Interactions involve reacting to dead friendlies, interacting with objects, and more
-
Looks of AI influenced by their curiosity
-
Easily improved upon and more functionality added (see "What is Curiosity")
What are Curious AI?
As the name suggests, curious AI are AI that have some personality to them, according to their level of curiosity they will react different to the environment, for example an AI with low curiosity may not react if they see a dead AI, however one with higher curiosity will react, and go and inspect what happened to their friend.
How can this be used?
This could be used in a wide variety of games, however I believe stealth games such as Hitman may benefit from this the most, as it would mean the player needs to plan more where they kill AI, where they interact with certain objects in the world and where they leave certain objects in the world.
What is Curiosity?
The curiosity of my AI system is dependent on a few things:
-
The Curiosity header file
This header file contains a namespace of curiosity values, consisting of Object Types and Dead Friendlies, but as the need arises more values can be added.
#pragma once
#include "Runtime/Core/Public/UObject/NameTypes.h"
#include "Runtime/Core/Public/Containers/UnrealString.h"
namespace CuriosityValues
{
float const DeadFriendly = 70.f;
float const BasicObject = 25.f;
float const MediumObject = 50.f;
float const AdvancedObject = 65.f;
}
-
The Team ID header file and Team Agent Interface
This header file consists of different enums which different classes in the project can utilise to tell the AI which team they are apart of. Basic objects would be classed as the Basic Object Team and if the AI detects that object and has high enough curiosity it will do an action based on this, such as picking up the object.
The TeamAgentInterface is an Unreal designed interface which allows Classes to register as teams, and can be used to make AI look for other classes which use that interface.
#pragma once
#include "Runtime/Core/Public/UObject/NameTypes.h"
#include "Runtime/Core/Public/Containers/UnrealString.h"
#include "RunTime/Core/Public/HAL/Platform.h"
#include "UObject/ObjectMacros.h"
#include "UObject/Interface.h"
#include "Engine/UserDefinedEnum.h"
namespace TeamIDVals
{
uint8 const AITeamDefault = 1;
uint8 const PlayerTeam = 2;
uint8 const DeadAITeam = 3;
uint8 const BasicObjectTeam = 4;
uint8 const MediumObjectTeam = 5;
uint8 const AdvancedObjectTeam = 6;
}
UENUM(BlueprintType)
namespace ETeamNames
{
enum Names
{
AITeamDefault UMETA(DisplayName = "AI Default"),
PlayerTeam UMETA(DisplayName = "Player Team"),
DeadAITeam UMETA(DisplayName = "Dead Team"),
BasicObjectTeam UMETA(DisplayName = "Basic Object"),
MediumObjectTeam UMETA(DisplayName = "Medium Object"),
AdvancedObjectTeam UMETA(DisplayName = "Advanced Object"),
Max UMETA(Hidden)
};
}
-
AI Perception Components
Finally to complete this system any objects of interest to be detected by the AI must have an AI Perception component, so that way the AI's sight can detect when an object has been spotted, be it another AI, the Player or a specific object.
Then depending on what has been detected the AI can perform different actions, such as: Chasing the player, Investigating a dead friendly, picking up and object of interest, and more!
Code Example Below checks if the detected Actor has the TeamAgent interface and then performs a Switch statement based on it's TeamID
if (const IGenericTeamAgentInterface* TeamAgent = Cast<IGenericTeamAgentInterface>(Actor))
{
FGenericTeamId OtherId = TeamAgent->GetGenericTeamId();
switch (OtherId)
{
case TeamIDVals::BasicObjectTeam:
ObjectFound(Actor, OtherId);
break;
}
What did I learn?
I learnt a lot about Unreal's AI and Perception system, I've used it briefly before in Blueprint but never with C++ and setting it up, at first was a challenge but I eventually managed to get a system I was happy with, where the AI has a field of view coming from their eyes and can detect objects within that field of view.
Creating custom behaviour tree tasks was a huge part of this system, and again, something completely new to me, but I think I effectively achieved what I wanted with this and managed to get a behaviour tree which is versatile in most gameplay situations, depending on what you want the AI to do (i.e. automatically chase the player, patrol (omni/bi-directional), wander randomly, etc.).
There will most likely me improvements needed for this system but for my first time tackling this, I was extremely happy with the results.