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