Trouble populating and spawning from Subclass Array

I’m sure I’m making this more complicated than it needs to be, but I can’t seem to successfully fill a TSubclassOf array with the Blueprints inherited from my C++ class.

I’m working on a wave spawning system which spawns Actors derived from my AEnemy class.

I would like to search a folder in my project and load all of the derived Blueprints contained within, and add them to a TArray>.

Finally, I need to spawn these actors on demand.

This all sounds fairly simple, right? Well, apparently I’m also fairly simple, as I can’t seem to get this to work for me.
Below is the code in it’s current format which populates the array of Blueprints:

void UWaveManager::InitialiseEnemyList() {

	FAssetRegistryModule* AssetRegistryModule = &FModuleManager::LoadModuleChecked<FAssetRegistryModule>(TEXT("AssetRegistry"));

	TArray<FAssetData> AssetData;
	FARFilter Filter;
	Filter.ClassNames.Add(UBlueprint::StaticClass()->GetFName());
	Filter.PackagePaths.Add("/Game/Blueprints/Enemies");
	AssetRegistryModule->Get().GetAssets(Filter, AssetData);

	int no = 0;

	for (TArray<FAssetData>::TConstIterator PkgIter = AssetData.CreateConstIterator(); PkgIter; ++PkgIter)
	{
		FAssetData Asset = *PkgIter;
		UBlueprint* BlueAsset = Cast<UBlueprint>(Asset.GetAsset());
		if (BlueAsset->ParentClass == AEnemy::StaticClass()) {
			//Do something

			EnemyTypesArray.Add(BlueAsset->GetClass());

			//TSubclassOf<AEnemy> FoundEnemy = *Cast<TSubclassOf<AEnemy>>(BlueAsset);
			//TSubclassOf<AEnemy> FoundEnemy = *Cast<TSubclassOf<AEnemy>>(BlueAsset);

			//EnemyTypesArray.Add(FoundEnemy->GetClass());
			no++;
		}

	}

	UE_LOG(LogTemp, Warning, TEXT("Number of BPs found = %d"), no);
	UE_LOG(LogTemp, Warning, TEXT("Number of Enemy Type BPs added to array = %d"), EnemyTypesArray.Num());


}

Next is the temporary code used for spawning:

void UWaveManager::PerformWaveAction() {		
		FActorSpawnParameters SpawnParams;
//		SpawnParams.Owner = this;
//		SpawnParams.Instigator = this;

		TSubclassOf<AEnemy> EnemyTypeToSpawn = EnemyTypesArray[0];

		if (EnemyTypeToSpawn != NULL) {
			AEnemy* NewEnemy = GetWorld()->SpawnActor<AEnemy>(EnemyTypeToSpawn);
			if (NewEnemy) {
				AliveEnemyArray.Add(NewEnemy);


				Cast<AEnemy>(NewEnemy->EnemyDeathDelegate.AddDynamic(this, &UWaveManager::RegisterEnemyDeath));
			}
		}
		else UE_LOG(LogTemp, Warning, TEXT("ActorToSpawn is Null"));


}

I’ve gotten so muddled with this, after trying again and again at different approaches, that I’m planning to start again in an attempt to spot and rectify any stupid little mistakes I’ve made. But in the meantime I would greatly appreciate it if someone else more able than I would be able to glance through the code and sight said mistakes on my behalf.

My understanding is that I need to convert the UBlueprint pointer to a Class type reference, but then store it in the subclass array. I should then be able to spawn by simply calling spawn actor, using the class in the array at the chosen index. The EnemyTypesArray does appear to be populated, but what with I’m not sure, as I am unable to spawn them.

Thanks in advance!

Still causing issues for me, so I’m bumping this thread =/

Great, thanks!
I’m so busy with work at the moment (this is for a fun/side project), but as soon as I get a chance I’ll take a look.

This works great, thanks! A much more compact approach too.

I also happened across what I believe may have been the issue to begin with which was that **UObject::GetWorld() returns Null.

This is the first time I’ve derived a class from UObject and I evidently didn’t pay enough attention to what was causing the error - assuming it was the more complicated subclass array, rather than the simple, reliable getworld function.

The solution to this I used was found here:

Header:

UFUNCTION(BlueprintCallable, Category = Misc, meta = (WorldContext = WorldContextObject))

static bool RandomFunc(UObject * WorldContextObject);

Cpp:

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

I’m sure there are other ways, but this works nicely too.

I’d like to mark your comment as an answer, but I’m not sure how. Moderator? ^^’

Glad to be of help!
This is how you mark an answer by the way :

Ah, but you’ve posted this as a comment/reply, not an answer :wink:

Hey, I tried to replicate your problem and found a possible solution, but using a UObjectLibrary instead, which works wonderfully with generated BPs.

I pretty much stole it from this thread : Loading Blueprints with ObjectLibrary - Programming & Scripting - Unreal Engine Forums

I did something like this and it works :

auto ItemLibrary = UObjectLibrary::CreateLibrary(AEnemy::StaticClass(), true, GIsEditor);
		ItemLibrary->AddToRoot();
		ItemLibrary->LoadBlueprintsFromPath(TEXT("/Game/Blueprints/Enemies"));

		TArray<UBlueprintGeneratedClass *> ClassesArray;
		ItemLibrary->GetObjects<UBlueprintGeneratedClass>(ClassesArray);

		for (int32 i = 0; i < ClassesArray.Num(); ++i)
		{
			UBlueprintGeneratedClass * BlueprintClass = ClassesArray[i];
			UE_LOG(LogTemp, Warning, TEXT("UBP generated %s"), *BlueprintClass->GetName());

			AEnemy* NewEnemy = GetWorld()->SpawnActor<AEnemy>(BlueprintClass);
			if (NewEnemy) {
							UE_LOG(LogTemp, Warning, TEXT("Actor Spawned"));
						}
		}

Hope it helps. :wink:

■■■■, didn’t notice, sorry! I’ve converted it.