Download

[Solved] How to use pointers with TArrays (and getting a dynamically generated array)

Hi,

I’m having trouble with pointers (I think) when iterating over a TArray and trying to grab the results. I have a main actor with an overlapping sphere collider that detects other actors within it’s radius. It puts these overlapping actors into an array (a TArray). Then I iterate over the array to try to find the closest actor for the “main actor” to pick-up, via distance. The problem I’m having is that the actor my main character grabs is ALWAYS the same actor, every time, and it’s never a different actor, even if other actors happen to be closer in distance.

My theory on why my function is always grabbing the exact same actor (despite it being far away), is because there is a pointer always pointing to the same value. But I don’t know how to force the variable to be a different value, other than what it was first “pointed to” to begin with. I come from a C# background, and so pointers are very new to me. I think I understand them, but maybe I’m using them incorrectly in this case.

Here is my function that creates an array and “grabs” the closest actor that I want, and puts that actor/value into a function on another script (via parameter):



void UGameAnimInstance1::ScanEnemyToGrab()
{
 mainCharacterActor = GetWorld()->GetFirstPlayerController()->GetPawn();

 TArray<AActor*> EnemiesInSphereRadius;
 TSubclassOf < AMyMedWarCharacterClass1 > ClassFilter;

 // Clear the array
 EnemiesInSphereRadius.Empty();

 if (EnemiesInSphereRadius.Num() > 0)
 {
  EnemiesInSphereRadius.RemoveAt(0);
 }


 // Generate/populate the "EnemiesInSphereRadius" array with the resulting actors that are overlapped
 mainCharacterActor->GetOverlappingActors(EnemiesInSphereRadius, ClassFilter);

 int32 TempInt1 = EnemiesInSphereRadius.Num();

 UE_LOG(LogTemp, Warning, TEXT("%d actors in the array"), TempInt1);

 if (EnemiesInSphereRadius.Num() > 0)
 {
  // Use the first element (actor element) in the array
  UMainCharacterController1 *ScriptComponent1 = mainCharacterActor->FindComponentByClass<UMainCharacterController1>();

  // Set the "ActorToGrab1" variable to null
  //ScriptComponent1->ActorToGrab1 = nullptr;

  //ScriptComponent1->ActorToGrab1 = EnemiesInSphereRadius[0];

  //AActor TempActor1 = EnemiesInSphereRadius[0];

  //ScriptComponent1->AttachActorToFootSocket1(EnemiesInSphereRadius[0]);

  // Set the initial distance float
  InitialDistance1 = FMath::RoundToPositiveInfinity(900000000.0f);

  for (int32 ActorIndex = 0; ActorIndex < EnemiesInSphereRadius.Num(); ActorIndex++)
  {
   ClosestDistance1 = (mainCharacterActor->GetActorLocation() - EnemiesInSphereRadius[ActorIndex]->GetActorLocation()).Size();

   // Get the closest actor by distance to the main character in the array.
   // For now though, I'm simply going to grab the first actor in the array if there is one.
   if (ClosestDistance1 < InitialDistance1)
   {
    InitialDistance1 = ClosestDistance1;

    TempActor1 = EnemiesInSphereRadius[ActorIndex];

    //if (TempActor2 != nullptr)
    //{
     //ScriptComponent1->AttachActorToFootSocket1(EnemiesInSphereRadius[ActorIndex]);
    //}
   }
  }

  if (TempActor1 != nullptr)
  {
   ScriptComponent1->AttachActorToFootSocket1(TempActor1);
  }

 }
 else
 {
  UE_LOG(LogTemp, Warning, TEXT("There are no enemies in this area!"));
 }


 //UE_LOG(LogTemp, Warning, TEXT("I ran the grab event!"));
}


I tried clearing the array every time the function is run, in order to ensure the array generated is populated with different actors, but it still grabs/returns the same actor every time.

Thanks for any help or info.

Just seems like a logic problem to me. This is how I would do it:



const FVector MyLocation = GetActorLocation();
float ClosestDistSqrd = MAX_Flt;
AActor* ClosestActor = nullptr;

for (AActor* ActorItr : ActorsInRange)
{
    // Check actor is valid
    if (!ActorItr || ActorItr->IsPendingKill()) { continue; }

    // Use Distance Squared (it's cheaper)
    const float DistSqrd = FVector(ActorItr->GetActorLocation() - MyLocation).SizeSquared();
    if (DistSqrd < ClosestDistSqrd)
    {
        ClosestDistSqrd = DistSqrd;
        ClosestActor = ActorItr;
    }
}

if (ClosestActor)
{
    // Do something
}


FVector have :: Dist() or :: Distance() statics btw;

Hey guys, thanks for the replies. I found out my problem actually. It turns out my code was actually working correctly (for once :stuck_out_tongue: ), but I was attaching the actor I wanted to grab to my main character via the “AttachToActor” function. This function “welded” the two transforms of my actors together – which caused the actor I wanted to grab to always be the “closest” actor.

Once I realized the first actor I grabbed had the same transform position as my main character, I realized I had to manually “detach” the grabbed character so that it had it’s own transform again. I didn’t know that was the behavior of the function in UE4.

Anyways, the code works now, and I have everything working. Thank you! :slight_smile: