Hello! I currently am making a game with UE4 where i have AI players as well as 1 local player. I’m trying to make a Team Deathmatch gamemode. I’ve got everything done but i have one problem. I need my AIController class to target the nearest ‘enemy’ (the enemy pawns have teams on them) so basically the closest actor of my pawn class that isn’t on the AiController’s team. What is an elegant way of implementing this?
What i do so far is spawn all controllers and pawns in the gamemode class and store references to those on every spawned pawn. Then once one dies a delegate fires off removing the killed pawn reference from all the pawns that are still alive. Vice versa for re-spawning. Then each tick (which is Totally gross and i know this is wrong) all the pawns iterate through their respective enemy pawn references and get the distance to the referenced pawns and return whatever pawn had the closest distance.
Before asking this here. I did a lot of searches on the web for solutions to this problem but the closest i could get is a tab targeting system you can buy on in the workshop.
I’m fairly new to the entirety of developing games (started studying C++ and UE4 2 months ago). So if there is a obvious solution, I am very sorry.
Looking forward from hearing form you, thanks in advance
Ruben Versavel
Edit:
I’ve taken a new approach. I iterate through all objects of class ATank every frame and get their distance and compare it to the previous calculated distance. when its a smaller distance it sets the new pending target. This does it fine. The problem is when a tank’s hp reaches 0 it is destroyed
ATank* ATankAIController::GetClosestEnemyTank()
{
ATank* PendingTarget = TargetTank;
for (TObjectIterator<ATank> Itr; Itr; ++Itr) //for all tanks in the world
{
if (Itr->GetTeam() != Team)
{
if (PendingTarget == nullptr) { PendingTarget = *Itr; continue; }
if (Itr->GetDistanceTo(PossessedTank) < PendingTarget->GetDistanceTo(PossessedTank))
{
PendingTarget = *Itr;
}
}
}
return PendingTarget;
}
float ATank::TakeDamage(float DamageAmount, FDamageEvent const & DamageEvent, AController * EventInstigator, AActor * DamageCauser)
{
int32 DamagePoints = FPlatformMath::RoundToInt(DamageAmount);
int32 DamageToApply = FMath::Clamp<int32>(DamagePoints, 0, TankCurrentHealth);
TankCurrentHealth -= DamageToApply;
if (TankCurrentHealth == 0)
{
OnTankDeathEvent.Broadcast(this);
}
return DamageToApply;
}
void ATankAIController::OnTankDeath(AActor* TankThatDied)
{
UnPossess();
Spawnpoint->bInUse = false;
Cast<ATeamDeatmatchGameMode>(GetWorld()->GetAuthGameMode())->OnRespawnRequestEvent.Broadcast(this);
TankThatDied->Destroy();
}
The problem is there are 12 tanks in total. When one dies at that split moment where in the iteration the distance gets calculated i get an exception and the game crashes. At least that’s what i think it is…
Here are the catches of the exception by Visual Studio and crash report of Unreal.
Access violation - code c0000005 (first/second chance not available)
UE4Editor_Engine!AActor::GetDistanceTo()
[d:\build++ue4+release-4.19+compile\sync\engine\source\runtime\engine\private\actor.cpp:4413]
UE4Editor_BattleTank_727!ATankAIController::GetClosestEnemyTank()
[f:\unreal
projects\battle-tank\battletank\source\battletank\private\tankaicontroller.cpp:70]
UE4Editor_BattleTank_727!ATankAIController::Tick()
[f:\unreal
projects\battle-tank\battletank\source\battletank\private\tankaicontroller.cpp:37]
UE4Editor_Engine!AController::TickActor()
[d:\build++ue4+release-4.19+compile\sync\engine\source\runtime\engine\private\leveltick.cpp:408]
UE4Editor_Engine!FActorTickFunction::ExecuteTick()
[d:\build++ue4+release-4.19+compile\sync\engine\source\runtime\engine\private\actor.cpp:134]
UE4Editor_Engine!FTickFunctionTask::DoTask()
[d:\build++ue4+release-4.19+compile\sync\engine\source\runtime\engine\private\ticktaskmanager.cpp:273]
UE4Editor_Engine!TGraphTask::ExecuteTask()
[d:\build++ue4+release-4.19+compile\sync\engine\source\runtime\core\public\async\taskgraphinterfaces.h:829]
UE4Editor_Core!FNamedTaskThread::ProcessTasksNamedThread()
[d:\build++ue4+release-4.19+compile\sync\engine\source\runtime\core\private\async\taskgraph.cpp:665]
UE4Editor_Core!FNamedTaskThread::ProcessTasksUntilQuit()
[d:\build++ue4+release-4.19+compile\sync\engine\source\runtime\core\private\async\taskgraph.cpp:574]
UE4Editor_Core!FTaskGraphImplementation::WaitUntilTasksComplete()
[d:\build++ue4+release-4.19+compile\sync\engine\source\runtime\core\private\async\taskgraph.cpp:1355]
UE4Editor_Engine!FTickTaskSequencer::ReleaseTickGroup()
[d:\build++ue4+release-4.19+compile\sync\engine\source\runtime\engine\private\ticktaskmanager.cpp:542]
UE4Editor_Engine!FTickTaskManager::RunTickGroup()
[d:\build++ue4+release-4.19+compile\sync\engine\source\runtime\engine\private\ticktaskmanager.cpp:1449]
UE4Editor_Engine!UWorld::RunTickGroup()
[d:\build++ue4+release-4.19+compile\sync\engine\source\runtime\engine\private\leveltick.cpp:770]
UE4Editor_Engine!UWorld::Tick()
[d:\build++ue4+release-4.19+compile\sync\engine\source\runtime\engine\private\leveltick.cpp:1429]
UE4Editor_UnrealEd!UEditorEngine::Tick()
[d:\build++ue4+release-4.19+compile\sync\engine\source\editor\unrealed\private\editorengine.cpp:1693]
UE4Editor_UnrealEd!UUnrealEdEngine::Tick()
[d:\build++ue4+release-4.19+compile\sync\engine\source\editor\unrealed\private\unrealedengine.cpp:401]
UE4Editor!FEngineLoop::Tick()
[d:\build++ue4+release-4.19+compile\sync\engine\source\runtime\launch\private\launchengineloop.cpp:3339]
UE4Editor!GuardedMain()
[d:\build++ue4+release-4.19+compile\sync\engine\source\runtime\launch\private\launch.cpp:166]
UE4Editor!GuardedMainWrapper()
[d:\build++ue4+release-4.19+compile\sync\engine\source\runtime\launch\private\windows\launchwindows.cpp:144]
UE4Editor!WinMain()
[d:\build++ue4+release-4.19+compile\sync\engine\source\runtime\launch\private\windows\launchwindows.cpp:223]
UE4Editor!__scrt_common_main_seh()
[f:\dd\vctools\crt\vcstartup\src\startup\exe_common.inl:253]
kernel32 ntdll