Correct way to draw HUD elements from Component?


I’m building different gameplay elements of my in-game characters into components. One of these is a HealthComponent, which has values for health, maximum health, etc, and triggers a death event. This can go on any Actor.

Previously, I had this built into the main character for my game, and in my HUD class would use the “Get All Actors of Class” node with my character class so that I can draw health bars on top of them all.

However, now I need to get all Actors with a HealthComponent instead, and it seems like getting all Actors of class Actor and checking for HealthComponent is too expensive to run every frame. (Doubles frame time)

The next thing I would try would be to have the HUD keep an array of Actors, and have the HealthComponent register their attached Actor when it is created and unregister it when it is destroyed, but I’m curious to know if anyone has a better way of doing this.

I’m using C++ and blueprint.

an Array of Actor Pointers in the HUD acting as a subscriber list is probably the most efficient method possible, but maybe there is some kind of optimization to cull out Actors that are not on screen. im sure the engine has some culling code, but the overhead of adding to and removing actor pointers from the list might not be worth it unless you had an army of enemies on the other side of a wall. maybe instead of subscribing to the HUD on spawn, you could try subscribing on overlap with the view frustum.

Get all components of a class, attached to any Actor

I ended up writing a new static node to do this, I think it’s better than the subscription option because it’s reusable for other components and in other places.

UFUNCTION(BlueprintCallable, Category = "Utilities", meta = (WorldContext = "WorldContextObject", DeterminesOutputType = "ComponentClass", DynamicOutputParam = "OutComponents"))
static void GetAllComponentsOfClass(UObject* WorldContextObject, TSubclassOf<UActorComponent> ComponentClass, TArray<UActorComponent*>& OutComponents);

void UBlueprintUtils::GetAllComponentsOfClass(UObject* WorldContextObject, TSubclassOf<UActorComponent> ComponentClass, TArray<UActorComponent*>& OutComponents)

	UWorld* World = GEngine->GetWorldFromContextObject(WorldContextObject);

	if (ComponentClass != NULL && World != nullptr)
		TArray<UObject*> objects;
		GetObjectsOfClass(ComponentClass, objects);
		for (UObject* object : objects)
			if (!object->IsPendingKill())
				UActorComponent* component = (UActorComponent*)object;
				if (component->GetWorld() == World)