Real-Time Crowd Simulation Sample
This code sample was taken from an Unreal C++ project. The task below was used in a Behavior Tree, which selects the nearest entry point into an airport, determined from the AI’s current position.
#include "Task_SetEntryPoint.h"
#include "AirportEntrancePoint.h"
#include "MyAIController.h"
#include "BehaviorTree/BlackboardComponent.h"
#include "./Engine/Classes/Engine/World.h"
#include "./Engine/Classes/GameFramework/PlayerController.h"
#include "../Engine/Classes/Kismet/GameplayStatics.h"
EBTNodeResult::Type UTask_SetEntryPoint::ExecuteTask(UBehaviorTreeComponent & OwnerComp, uint8 * NodeMemory)
{
AMyAIController * AICon = Cast<AMyAIController>(OwnerComp.GetAIOwner());
if (AICon)
{
UBlackboardComponent* BlackboardComp = AICon->GetBlackboardComp();
AAirportEntrancePoint* CurrentPoint = Cast<AAirportEntrancePoint>(BlackboardComp->GetValueAsObject("LocationToGo"));
TArray<AActor*> AvailableTargetPoints = AICon->GetAvailableEntryPoints();
int32 index = 0;
AAirportEntrancePoint* NextTargetPoint = nullptr;
FVector actorLocation = AICon->GetPawn()->GetActorLocation();
float shortestDistance = FLOAT_MAX;
for (size_t i = 0; i < AvailableTargetPoints.Num(); i++)
{
FVector location = AvailableTargetPoints[i]->GetActorLocation();
float distance = FVector::Dist(actorLocation, location);
if (distance < shortestDistance)
{
shortestDistance = distance;
index = i;
}
}
NextTargetPoint = Cast<AAirportEntrancePoint>(AvailableTargetPoints[index]);
BlackboardComp->SetValueAsObject("LocationToGo", NextTargetPoint);
BlackboardComp->SetValueAsBool("IsInAirport", true);
return EBTNodeResult::Succeeded;
}
return EBTNodeResult::Failed;
}
Pacman Level Loading Sample
The next sample is taken from a C++ Pacman game, the sample is the chunk of code that takes care of the level loading. It reads out a binary file, and creates a level using the data read out from that file.
//Create the grid
int horOffset = 100;
int verOffset = 100;
int collumnSize = 31;
int rowSize = 31;
int tileSize = 16;
//Read pacman level from file
BinaryReader br;
br.Open("PacmanLevel01.bin");
std::vector<std::vector<int>>tiles;
br.Read(tiles);
br.Close();
auto pGrid = std::make_shared<std::vector<std::vector<GameObject*>>>();
(*pGrid).resize(tiles.size());
for (size_t i = 0; i < (*pGrid).size(); i++)
{
(*pGrid)[i].resize(tiles[i].size());
}
for (int i = 0; i< collumnSize; i++)
{
for (int j = 0; j < rowSize; j++)
{
int locInVector = i * collumnSize + j;
if (!(locInVector >= int(tiles.size() * tiles[0].size())))
{
GameObject* tileObject = new GameObject();
auto pTransformComponent = new TransformComponent();
pTransformComponent->SetPosition(float(horOffset + i * tileSize), float(verOffset + j * tileSize), 0.0f);
tileObject->AddComponent(pTransformComponent);
auto pDrawComponent = new DrawComponent();
tileObject->AddComponent(pDrawComponent);
auto pGridComponent = new GridComponent();
int type = tiles[i][j];
pGridComponent->SetTileType(TileType(type));
tileObject->AddComponent(pGridComponent);
(*pGrid)[i][j] = tileObject;
//std::cout << i << ", " << j << "\n";
scene.Add(tileObject);
}
}
}
Pacman Component Sample
This sample is take from the same Pacman game, this code is the chunk that takes care of creating Pacman.
//Create Pacman GameObject* pacmanObject = new GameObject(); auto pTransformComponent = new TransformComponent(); pTransformComponent->SetPosition(float(horOffset) + 14 * tileSize - 8, float(verOffset) + 23 * ze - 8, 0.0f); pacmanObject->AddComponent(pTransformComponent); auto pDrawComponent = new DrawComponent(); pacmanObject->AddComponent(pDrawComponent); auto pPacmanComponent = new PacmanComponent(); pPacmanComponent->SetTextures(); pPacmanComponent->SetGridReference(pGrid); pPacmanComponent->SetRespawnLoc(14, 23); pPacmanComponent->AddTeleportLocation(0, 14, 27, 14); pPacmanComponent->AddTeleportLocation(28, 14, 1, 14); pPacmanComponent->SetPlayerId(0); pacmanObject->AddComponent(pPacmanComponent); scene.Add(pacmanObject); std::shared_ptr<GameObject*> pacmanRef = std::make_shared<GameObject*>(pacmanObject);
Crystal Geometry Shader
You may also want to have a look at my Crystal Geometry Shader. The code is a bit too long to post in it’s entirety here [The page is already pretty long!], but you can find it here!
AI Steering Behaviors Sample
Last but not least, this sample is taken from another C++ project in which an AI had to find its way through a level, trying to avoid enemies and go through checkpoints. This chunk of code is specifically the calculating of the direction the AI will be going, taking into account any obstacles & possible goals.
void Plugin::SeekCheckpoint(SteeringPlugin_Output & steering, IExamInterface* pInterface, float maxDistance,
float minDistance, float enemyAvoidanceToWaypointPercentage, bool & switchDirectionBool,
int & lastEnemiesWithinSight, vector<EnemyInfo> & vEnemiesInFOV, vector<std::pair<EnemyInfo, float>> & enemiesSpotted)
{
steering = SteeringPlugin_Output();
AgentInfo agentInfo = pInterface->Agent_GetInfo();
Elite::Vector2 checkpointLocation = pInterface->World_GetCheckpointLocation();
Elite::Vector2 nextTargetPos = pInterface->NavMesh_GetClosestPathPoint(checkpointLocation);
float minToMaxDistanceScale = 1 / (maxDistance - minDistance);
vector<Elite::Vector2> desiredDirections;
desiredDirections.push_back(nextTargetPos - agentInfo.Position);
//Enemy Flee Influence
vector<float>m_EnemyDistances;
vector<float>m_EnemyPriorities;
//Calculate the distance between all positions in the m_EnemiesSpotted vector and the player
for (size_t i = 0; i < enemiesSpotted.size(); i++)
{
m_EnemyDistances.push_back(enemiesSpotted[i].first.Location.Distance(agentInfo.Position));
}
//Calculate Priority(/Weight) of each location
for (size_t i = 0; i < m_EnemyDistances.size(); i++)
{
float temp = m_EnemyDistances[i] - minDistance;
temp *= minToMaxDistanceScale;
m_EnemyPriorities.push_back(temp);
}
//Calculate flee directions and apply priority(/weight)
for (size_t i = 0; i < m_EnemyPriorities.size(); i++)
{
Elite::Vector2 temp = Elite::Vector2(enemiesSpotted[i].first.Location - agentInfo.Position);
temp *= -m_EnemyPriorities[i];
desiredDirections.push_back(temp);
}
//Add these together and normalize
Elite::Vector2 desiredDirection;
for (size_t i = 0; i < desiredDirections.size(); i++)
{
desiredDirection += desiredDirections[i];
}
desiredDirection.Normalize();
//Apply flee-to-seek percentage
desiredDirection *= enemyAvoidanceToWaypointPercentage;
//Add seeking checkpoint
Elite::Vector2 goalDir = (nextTargetPos - agentInfo.Position);
goalDir.Normalize();
goalDir *= (1 - enemyAvoidanceToWaypointPercentage);
desiredDirection += goalDir;
desiredDirection.Normalize();
steering.LinearVelocity = desiredDirection;
//Rescale to Max Speed
steering.LinearVelocity *= agentInfo.MaxLinearSpeed;
//Rotation Logic
float angSpeed = -float(E_PI_2);
if (switchDirectionBool)
{
angSpeed *= -1.0f;
}
if (size_t(lastEnemiesWithinSight) > vEnemiesInFOV.size())
{
switchDirectionBool = !switchDirectionBool;
}
lastEnemiesWithinSight = vEnemiesInFOV.size();
steering.AngularVelocity = angSpeed;
steering.AutoOrientate = false;
}