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;
}