wow. so simple! thanks so much! it works.
I’m trying to use the FObjectFinder to reference a blueprint. I reference the blueprint in the constructor then try to spawn blueprint/actor in the Tick function but the FObjectFind.object is null in the Tick even though it had a value in the constructor.
Header
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "Engine/World.h"
#include "Public/Balloon.h"
#include "CoreUObject/Public/UObject/ConstructorHelpers.h"
#include "BalloonGenerator.generated.h"
UCLASS()
class WATERBALLOONS_API ABalloonGenerator : public AActor
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
ABalloonGenerator();
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
// Functions
const void DropBalloon();
private:
// Reference to self
AActor* Owner = nullptr;
// Balloon Reference
UBlueprint* BalloonBP = nullptr;
// Timer variable for dropping balloons
float LastDropTime = 0.0f;
// Random delay for ballon drops
float RandomDelayTime = 6.0f;
UPROPERTY(EditAnywhere)
float MaxDelayBetweenSpawns = 6.0f; // In seconds
// Max/min X and Y for random positioning
// for balloon drops
UPROPERTY(EditAnywhere)
float MinPossibleX = 0.0f;
UPROPERTY(EditAnywhere)
float MaxPossibleX = 0.0f;
UPROPERTY(EditAnywhere)
float MinPossibleY = 0.0f;
UPROPERTY(EditAnywhere)
float MaxPossibleY = 0.0f;
UPROPERTY(EditAnywhere)
float ZHeightToDropBalloonFrom = 0.0f;
};
CPP
#include "BalloonGenerator.h"
// Sets default values
ABalloonGenerator::ABalloonGenerator()
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
}
// Called when the game starts or when spawned
void ABalloonGenerator::BeginPlay()
{
Super::BeginPlay();
// Get Reference to Self
Owner = GetOwner();
if (!Owner)return;
if (!BalloonBP) {
UE_LOG(LogTemp, Error, TEXT("%s does not have a reference to Balloon blueprint."), *Owner->GetName());
return;
}
// Reference ballon object
ConstructorHelpers::FObjectFinder<UBlueprint> BlueprintObj(TEXT("Blueprint'/Game/Balloon_BP.Balloon_BP_C'"));
if (BlueprintObj.Succeeded()) {
BalloonBP = BlueprintObj.Object;
}
else{
UE_LOG(LogTemp, Warning, TEXT("Balloon Blueprint did not get referenced."));
}
// Start drop timer
LastDropTime = GetWorld()->GetTimeSeconds();
if (MaxPossibleX == 0 || MaxPossibleY == 0) {
UE_LOG(LogTemp, Error, TEXT("Max random X and Y for balloon generator are not set"))
}
}
// Called every frame
void ABalloonGenerator::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
float CurrentTime = GetWorld()->GetTimeSeconds();
if (CurrentTime - LastDropTime > RandomDelayTime) {
// Drop a balloon
DropBalloon();
LastDropTime = CurrentTime;
RandomDelayTime = FMath::RandRange(MaxDelayBetweenSpawns / 3, MaxDelayBetweenSpawns);
}
}
// Spawn a balloon into world
const void ABalloonGenerator::DropBalloon() {
// Determine x,y to spawn balloon
float X = FMath::RandRange(MinPossibleX, MaxPossibleX);
float Y = FMath::RandRange(MinPossibleY, MaxPossibleY);
// Create creation vector
FVector CreatePosition = FVector(X, Y, ZHeightToDropBalloonFrom);
FRotator Rotation = FRotator::ZeroRotator;
FActorSpawnParameters SpawnInfo;
if(!BalloonBP){
UE_LOG(LogTemp, Warning, TEXT("Balloon Blueprint is null - no generation."));
return;
}
UE_LOG(LogTemp, Warning, TEXT("Create Position: %s"), *((CreatePosition).ToString()));
GetWorld()->SpawnActor<ABalloon>(BalloonBP->GetClass(), CreatePosition, Rotation, SpawnInfo);
}
Just use
in the header:
UPROPERTY(EditAnywhere)
TSubclassOf<ABalloon> BalloonClassToSpawn;
and in the cpp:
GetWorld()->SpawnActor<ABalloon>(BalloonClassToSpawn, CreatePosition, Rotation, SpawnInfo);
no need to make it hard on yourself with explicitly pointing to blueprints.