Radar in C++ with Actor distance and tags

enter code hereHello, I’m trying to create my own radar in C++, based on the Actor distance and then filter the collected actors with tags. But it works not exactly it should.

.h
// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "GameFramework/HUD.h"
#include "ZSFSNewHUD.generated.h"

/**
 * 
 */
UCLASS()
class ZSFS_I_API AZSFSNewHUD : public AHUD
{
	GENERATED_BODY()
	
	public:
	AZSFSNewHUD();
	
	// Called when the game starts or when spawned
	virtual void BeginPlay() override;

	// Called every frame
	virtual void Tick(float DeltaSeconds) override;

	/** Primary draw call for the HUD */
	virtual void DrawHUD() override;
	
	private:
	/** Crosshair asset pointer */
	class UTexture2D* RadarTex;
	
	/** Crosshair asset pointer */
	class UTexture2D* PlayerTex;
	
	protected:
	/*The start location of our radar*/
	UPROPERTY(EditAnywhere, Category = Radar)
	FVector2D RadarStartLocation = FVector2D(0.1f,0.165f);
	
	/*The start location of our radar*/
	UPROPERTY(EditAnywhere, Category = Radar)
	FVector2D RadarStartLocationText = FVector2D(0.035f,0.02f);
	
	/*The radius of our radar*/
	UPROPERTY(EditAnywhere, Category = Radar)
	float RadarRadius = 80.f;
	
	/*The pixel size of the drawable radar actors*/
	UPROPERTY(EditAnywhere, Category = Radar)
	float DrawPixelSize = 10.f;
	
	/*Returns the center of the radar as a 2d vector*/
	FVector2D GetRadarCenterPosition();
	
	/*Returns the center of the radar as a 2d vector*/
	FVector2D GetRadarCenterPositionText();
	
	/*Draws the radar*/
	void DrawRadar();
	
	/*Holds a reference to every actor we are currently drawing in our radar*/
	TArray<AActor*> RadarActors;
	
	/*Holds a reference to every actor we are currently drawing in our radar*/
	TArray<AActor*> RadarAmmo;
	
	/*The distance scale of the radar actors*/
	UPROPERTY(EditAnywhere, Category = Radar)
	float RadarDistanceScale = 55.0f;

	float ObjectRadius;

	/*Converts the given actors' location to local (based on our character)*/
	FVector2D ConvertWorldLocationToLocal(AActor* ActorToPlace);
	
	/*Draws the player in our radar*/
	void DrawPlayerInRadar();
	
	/*Draws the player in our radar*/
	void AZSFSNewHUD::PerformRadarObjectFinfing();


	/*Draws the raycasted actors in our radar*/
	void DrawFoundActors();
	
	/*Draws the raycasted actors in our radar*/
	void DrawFoundAmmo();

	void GetAllActors();
	
	//TSubclassOf<ZSFSEnemy1BP> EnemyToFind;
	//EnemyToFind = ZSFSEnemy1BP::StaticClass();
	
	TArray<AActor*> ZSFSEnemy1;
	
	//TSubclassOf<Box1BP> AmmoToFind;
	//AmmoToFind = Box1BP::StaticClass();
	
	TArray<AActor*> Ammo;
	
};

.cpp

// Fill out your copyright notice in the Description page of Project Settings.

#include "ZSFS_I.h"
#include "ZSFSNewHUD.h"


AZSFSNewHUD::AZSFSNewHUD(){
	
	
	
	// Set the crosshair texture
	static ConstructorHelpers::FObjectFinder<UTexture2D> RadarTexObj(TEXT("/Game/AI_GameMode/radar11.radar11"));
	RadarTex = RadarTexObj.Object;
	
	// Set the crosshair texture
	static ConstructorHelpers::FObjectFinder<UTexture2D> PlayerTexObj(TEXT("/Game/AI_GameMode/black-dot-hi.black-dot-hi"));
	PlayerTex = PlayerTexObj.Object;

	ObjectRadius = 5000.0f;
	
}

// Called when the game starts or when spawned
void AZSFSNewHUD::BeginPlay()
{
	Super::BeginPlay();
	
	/* UGameplayStatics::GetAllActorsOfClass(GetWorld(), AActor::StaticClass(), RadarActors);
	UE_LOG(LogTemp,Warning,TEXT("Ammo is %d"), RadarActors.Num() );
	
	for (AActor* It : RadarActors){
		AActor* CurrentActor = It;
		//In case the actor contains the word "Radar" as a tag, add it to our array
		if (CurrentActor && CurrentActor->ActorHasTag("Radar")){
			ZSFSEnemy1.Add(CurrentActor);
		} 
		else if(CurrentActor && CurrentActor->ActorHasTag("Ammo")){
			Ammo.Add(CurrentActor);
		}
				
	}
	
	UE_LOG(LogTemp,Warning,TEXT("Ammo is %d"), ZSFSEnemy1.Num() );
	UE_LOG(LogTemp,Warning,TEXT("Ammo is %d"), Ammo.Num() ); */
	
	//UGameplayStatics::GetAllActorsOfClass(GetWorld(), ACharacter::StaticClass(), ZSFSEnemy1);
	//UE_LOG(LogTemp,Warning,TEXT("ZSFSEnemy1 is %d"), ZSFSEnemy1.Num() );
	
	
}

void AZSFSNewHUD::Tick(float DeltaTime) {
	Super::Tick(DeltaTime);

	GetAllActors();


}


void AZSFSNewHUD::DrawHUD(){
	Super::DrawHUD();
	
	
		
	DrawRadar();
	
	DrawPlayerInRadar();
	
	
	
	PerformRadarObjectFinfing();

	if (ZSFSEnemy1.Num() > 0) {
		

		DrawFoundActors();
		
	}
	
	if (Ammo.Num() > 0) {
		DrawFoundAmmo();
	}

	//Empty the radar actors in case the player moves out of range,
	//by doing so, we have always a valid display in our radar
	//ZSFSEnemy1.Empty();
	//Ammo.Empty();
	
}

FVector2D AZSFSNewHUD::GetRadarCenterPosition(){
		//If the canvas is valid, return the center as a 2d vector
		return (Canvas) ? FVector2D(Canvas->SizeX*RadarStartLocation.X, Canvas->SizeY*RadarStartLocation.Y) : FVector2D(0, 0);
	}
	
FVector2D AZSFSNewHUD::GetRadarCenterPositionText(){
		//If the canvas is valid, return the center as a 2d vector
		return (Canvas) ? FVector2D(Canvas->SizeX*RadarStartLocationText.X, Canvas->SizeY*RadarStartLocationText.Y) : FVector2D(0, 0);
	}
	
void AZSFSNewHUD::DrawRadar(){
	
	FVector2D RadarCenter = GetRadarCenterPositionText();

	// offset by half the texture's dimensions so that the center of the texture aligns with the center of the Canvas
	const FVector2D RadarDrawPosition( (RadarCenter.X),(RadarCenter.Y));

	// draw the radar
	FCanvasTileItem TileItem1( RadarDrawPosition, RadarTex->Resource, FVector2D(150.0f, 150.0f), FLinearColor::White);
	TileItem1.BlendMode = SE_BLEND_Translucent;
	Canvas->DrawItem( TileItem1 );
	
	}
	
void AZSFSNewHUD::DrawPlayerInRadar(){
	
	FVector2D RadarCenter = GetRadarCenterPositionText();
	
	const FVector2D RadarDrawPositionPlayer( (RadarCenter.X + 70.0f),(RadarCenter.Y + 70.0f));
	
	// draw the player
	FCanvasTileItem TileItem2( RadarDrawPositionPlayer , PlayerTex->Resource, FVector2D(10.0f, 10.0f), FLinearColor::White);
	TileItem2.BlendMode = SE_BLEND_Translucent;
	Canvas->DrawItem( TileItem2 );
	
	}

void AZSFSNewHUD::GetAllActors() {

	APawn* Player = UGameplayStatics::GetPlayerPawn(GetWorld(), 0);
	//Player->GetDistanceTo
	for (TActorIterator<AActor> it(GetWorld()); it; ++it) {
		float Distance = Player->GetDistanceTo(*it);

		if (Distance <= ObjectRadius) {
			
			if(RadarActors.Contains(*it)){
				
				return;
			}
				
			RadarActors.AddUnique(*it);
				UE_LOG(LogTemp, Warning, TEXT("RadarActors is %s"), *it->GetName());
			
		
			//UE_LOG(LogTemp,Warning,TEXT("ZSFSEnemy1 is %d"), RadarActors.Num() );
			//UGameplayStatics::GetAllActorsOfClass(GetWorld(), AActor::StaticClass(), RadarActors);
		}
		else {
			RadarActors.Remove(*it);
			//RadarActors.Empty();
		}
	}
}
	
void AZSFSNewHUD::PerformRadarObjectFinfing(){
	if (RadarActors.Num() > 0) {

		for (AActor* It : RadarActors) {
			if (It && !It->IsPendingKill()) {
				AActor* CurrentActor = It;
				//if (RadarActors.Num() > 0) {
					//In case the actor contains the word "Radar" as a tag, add it to our array
					if (CurrentActor && CurrentActor->ActorHasTag("Radar")) {
						ZSFSEnemy1.Add(CurrentActor);
					}
					else if (CurrentActor && CurrentActor->ActorHasTag("Ammo")) {
						Ammo.Add(CurrentActor);
					}

				//}
			}
		}

	}
	//UE_LOG(LogTemp,Warning,TEXT("ZSFSEnemy1 is %d"), ZSFSEnemy1.Num() );
	//UE_LOG(LogTemp,Warning,TEXT("Ammo is %d"), Ammo.Num() );
	
	}
	
	
FVector2D AZSFSNewHUD::ConvertWorldLocationToLocal(AActor* ActorToPlace){
		APawn* Player = UGameplayStatics::GetPlayerPawn(GetWorld(), 0);

		if (Player && ActorToPlace){
			//Convert the world location to local, based on the transform of the player
			FVector ActorsLocal3dVector = Player->GetTransform().InverseTransformPosition(ActorToPlace->GetActorLocation());

			//Rotate the vector by 90 degrees counter-clockwise in order to have a valid rotation in our radar
			ActorsLocal3dVector = FRotator(0.f, -90.f, 0.f).RotateVector(ActorsLocal3dVector);

			//Apply the given distance scale
			ActorsLocal3dVector /= RadarDistanceScale;

			//Return a 2d vector based on the 3d vector we've created above
			return FVector2D(ActorsLocal3dVector);
			}
		return FVector2D(0,0);
	}
	
	void AZSFSNewHUD::DrawFoundActors(){
		FVector2D RadarCenter = GetRadarCenterPositionText();

		for (auto It : ZSFSEnemy1){
			
			FVector2D convertedLocation = ConvertWorldLocationToLocal(It);

			FVector tempVector = FVector(convertedLocation.X, convertedLocation.Y, 0.f);

			//Subtract the pixel size in order to make the radar display more accurate
			tempVector = tempVector.GetClampedToMaxSize2D(RadarRadius - DrawPixelSize);

			//Assign the converted X and Y values to the vector we want to display
			convertedLocation.X = tempVector.X;
			convertedLocation.Y = tempVector.Y;

			DrawRect(FLinearColor::Red, RadarCenter.X + convertedLocation.X + 75.0f, RadarCenter.Y + convertedLocation.Y + 75.0f, DrawPixelSize, DrawPixelSize);
		}
	}
	
	
	void AZSFSNewHUD::DrawFoundAmmo(){
		FVector2D RadarCenter = GetRadarCenterPositionText();

		for (auto It : Ammo){
		FVector2D convertedLocation = ConvertWorldLocationToLocal(It);

		FVector tempVector = FVector(convertedLocation.X, convertedLocation.Y, 0.f);

		//Subtract the pixel size in order to make the radar display more accurate
		tempVector = tempVector.GetClampedToMaxSize2D(RadarRadius - DrawPixelSize);

		//Assign the converted X and Y values to the vector we want to display
		convertedLocation.X = tempVector.X;
		convertedLocation.Y = tempVector.Y;

		DrawRect(FLinearColor::Blue, RadarCenter.X + convertedLocation.X + 75.0f, RadarCenter.Y + convertedLocation.Y + 75.0f, DrawPixelSize, DrawPixelSize);
		}
	}

The code is compiled, but the actors are displayed that are at the beginning of the game and then it isn’t updated.

A few possible cultprits that I see, but the one that probably solves your problem is clearing the RadarActors array in GetAllActors() before iterating.

Hard to read with this formation, but I think you are trying to remove something in GetAllActors() with but that seems tedious and error prone to me, I would just call RadarActors.Empty() before you interate over all actors and refill the whole array every frame - or better: based on a timer.

DennyR, thanks a lot! I knew I needed to clear the array, but I didn’t know where exactly to do that. This code solve the problem:

void AZSFSNewHUD::Tick(float DeltaTime) {
Super::Tick(DeltaTime);

RadarActors.Empty();
GetAllActors();

}

void AZSFSNewHUD::DrawHUD(){
Super::DrawHUD();

DrawRadar();

DrawPlayerInRadar();

PerformRadarObjectFinfing();

DrawFoundActors();

DrawFoundAmmo();

ZSFSEnemy1.Empty();
Ammo.Empty();

}

We need to clear ZSFSEnemy1 and Ammo arrays too because the objects on the radar should disappear when the distance is longer.

Nice, please mark the thing as solved :slight_smile:

Done! Thank you again.