Download

How to add reference to AActor type BP, from within an AActorComponent C++

Hi all. I am fairly new to coding c++ and very new to Unreal. I have made an AActor called Bird (it will just fly in a straight line once it is spawned. Be animated. And live for n secs, then destroy itself).
I also create a Tree AActor. The bird and tree, I have also created BP off.

I am a coder first and foremost and enjoy coding written rather than visual scripting.

I created an ‘Actor Component’ class called BirdSpawner. This component is intended to be a component added to Tree. My plan was to have BirdSpawner hold a reference to the Bird_BP file and spawn a bird after specified interval.

Now, when I go into my Tree_BP to assign the AActor variable ‘Bird’, I have problem. The only items I can choose in drop down are existing scene Actors. And even if I drag a bird somewhere into the scene so that it becomes an option in the dropdown, I still cannot choose it. -I am pretty certain therefore that the ‘Bird_BP’ is not actually of type AActor.

So how do I make a component keep a reference to an Actor_BP and spawn it?

Here is my C++ code:


class INSANO_WORLD_API ABird : public AActor
{
    GENERATED_BODY()

public:    
    // Sets default values for this actor's properties
    ABird();

private:
    void UpdateBirdLocation(float DeltaTime);
    void HandleLifespan(float DeltaTime);

protected:
    // Called when the game starts or when spawned
    virtual void BeginPlay() override;

public:    
    // Called every frame
    virtual void Tick(float DeltaTime) override;

    UPROPERTY(EditDefaultsOnly, Category = Colliders)
    class USphereComponent* SphereComponent;

    UPROPERTY(EditDefaultsOnly, Category = Mesh)
    class USkeletalMeshComponent* SkeletalMeshComponent;

    UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = Mesh)
    FVector MeshLocationOffset;

    UPROPERTY(EditAnywhere, Category = Behaviour)
    float Speed;

    UPROPERTY(EditAnywhere, Category = Behaviour)
    FVector Direction;

    UPROPERTY(EditAnywhere, Category = Behaviour)
    float Lifespan;

};


ABird::ABird()
{
     // 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;

    SphereComponent = CreateDefaultSubobject<USphereComponent>("SphereCollider");
    RootComponent = SphereComponent;
    SkeletalMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("Mesh"));
    SkeletalMeshComponent->SetupAttachment(RootComponent);
    SkeletalMeshComponent->SetRelativeLocation(MeshLocationOffset);
}

// Called when the game starts or when spawned
void ABird::BeginPlay()
{
    Super::BeginPlay();

}

// Called every frame
void ABird::Tick(float DeltaTime)
{
    Super::Tick(DeltaTime);

    UpdateBirdLocation(DeltaTime);
    HandleLifespan(DeltaTime);

}

void ABird::UpdateBirdLocation(float DeltaTime)
{
    FVector Loc = GetActorLocation();
    Loc = Loc + Direction * Speed * DeltaTime;
    FHitResult Hit;
    SetActorLocation(Loc, true, &Hit);
}

void ABird::HandleLifespan(float DeltaTime)
{
    Lifespan -= DeltaTime;
    if (Lifespan <= 0)
    {
        Destroy();
    }
}


class INSANO_WORLD_API ATree : public AActor
{
    GENERATED_BODY()

public:    
    // Sets default values for this actor's properties
    ATree();

    UPROPERTY(EditAnywhere, Category = Mesh)
    class UStaticMeshComponent* StaticMesh;

    UPROPERTY(EditAnywhere, Category = Spawners)
    class USpawner_Bird* Spawner_Bird;

protected:
    // Called when the game starts or when spawned
    virtual void BeginPlay() override;

public:    
    // Called every frame
    virtual void Tick(float DeltaTime) override;

};


ATree::ATree()
{
     // 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;

    StaticMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("StaticMesh"));
    RootComponent = StaticMesh;

    Spawner_Bird = CreateDefaultSubobject<USpawner_Bird>(TEXT("Spawner Bird"));
    Spawner_Bird->SetActive(true);

}

// Called when the game starts or when spawned
void ATree::BeginPlay()
{
    Super::BeginPlay();

}

// Called every frame
void ATree::Tick(float DeltaTime)
{
    Super::Tick(DeltaTime);

}


class INSANO_WORLD_API USpawner_Bird : public UActorComponent
{
    GENERATED_BODY()

public:    
    // Sets default values for this component's properties
    USpawner_Bird();


    UPROPERTY(EditAnywhere, Category = Behaviour)
    float Interval;

    float Interval_Timer = 0.0f;

    UPROPERTY(EditAnywhere, Category = Behaviour)
    FVector BirdDirection;

    UPROPERTY(EditAnywhere, Category = Behaviour)
    AActor* Bird;  // **<- THIS IS WHERE I AM HAVING PROBLEMS**

protected:
    // Called when the game starts
    virtual void BeginPlay() override;

public:    
    // Called every frame
    virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;


};


USpawner_Bird::USpawner_Bird()
{
    // Set this component to be initialized when the game starts, and to be ticked every frame.  You can turn these features
    // off to improve performance if you don't need them.
    PrimaryComponentTick.bCanEverTick = true;

    // ...
}


// Called when the game starts
void USpawner_Bird::BeginPlay()
{
    Super::BeginPlay();

    // ...

}


// Called every frame
void USpawner_Bird::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
    Super::TickComponent(DeltaTime, TickType, ThisTickFunction);

    Interval_Timer += DeltaTime;
    if (Interval_Timer >= Interval)
    {
        Interval_Timer = 0.f;
    }
}

I think, to be able to select an actor you need to have an actual component in the UWorld, IE place the tree in the world and select an actor from the ddetail panel.
Anyway, for a spawner i’d use:

UPROPERTY(BlueprintReadWrite, EditAnywhere)
    TSubclassOf&lt;AActor&gt; ClassToSpawn;

That’ll allow you to choose the “ClassToSpawn” anywhere, since it’s just a reference to a class, not an actual actor.

thank you so much. I had also found this meanwhile (http://www.orfeasel.com/actor-spawning/) and it describes the same function as you. I’m currently trying to get it to work now, but thought i’d post this here in case anyone else wants to read the link.

Hi friend. I have read thru the above link and considered your advice. But I can’t get this to work. The editor even now allows me to select my Bird_BP as a UPROPERTY inside the blueprint editor, but the bird doesn’t spawn. I put some log commands in and for some reason I get the log “Failed to spawn bird”. Please if I post all my code could you check it for me. I feel it is almost correct hopefully just needs one or two little things changed/added. I’d be happy to post the whole project if there is a feasable way to do that.

For now, I just post the Spawner class as I think this is where the main work is done:


UCLASS(ClassGroup = (Custom), meta = (BlueprintSpawnableComponent))
class INSANO_WORLD_API USpawner_Bird : public UActorComponent
{
    GENERATED_BODY()

public:
    // Sets default values for this component's properties
    USpawner_Bird();

    float Interval;

    float Interval_Timer = 0.0f;

    FTransform TreeTransform;

    FVector RelativeLocation;

    FVector BirdDirection;

    UPROPERTY(EditDefaultsOnly, Category = Spawner)
    TSubclassOf<class ABird> BirdBP;

protected:
    // Called when the game starts
    virtual void BeginPlay() override;

public:
    // Called every frame
    virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;

    void Init_Spawner(FTransform treeTransform, FVector relativeLocation, FVector birdDirection, float interval);


};


USpawner_Bird::USpawner_Bird()
{
    // Set this component to be initialized when the game starts, and to be ticked every frame.  You can turn these features
    // off to improve performance if you don't need them.
    PrimaryComponentTick.bCanEverTick = true;
}

void USpawner_Bird::Init_Spawner(FTransform treeTransform, FVector relativeLocation, FVector birdDirection, float interval)
{
    TreeTransform = treeTransform;
    RelativeLocation = relativeLocation;
    BirdDirection = birdDirection;
    Interval = interval;

    UE_LOG(LogTemp, Warning, TEXT("Spawner Initialised"));
}

void USpawner_Bird::BeginPlay()
{
    Super::BeginPlay();


}


// Called every frame
void USpawner_Bird::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
    Super::TickComponent(DeltaTime, TickType, ThisTickFunction);

    Interval_Timer += DeltaTime;
    if (Interval_Timer >= Interval)
    {
        Interval_Timer = 0.f;
        if (BirdBP)
        {
            UE_LOG(LogTemp, Warning, TEXT("Spawning bird..."));

            //Spawn parameters for the current spawn.
            //We can use this for a number of options like disable collision or adjust the spawn position
            //if a collision is happening in the spawn point etc..
            FActorSpawnParameters SpawnParams;

            ABird* NewBirdie = GetWorld()->SpawnActor<ABird>(BirdBP, TreeTransform, SpawnParams);
            NewBirdie->Init_Bird(BirdDirection);
        }
        else
        {
            UE_LOG(LogTemp, Warning, TEXT("Failed while Spawning bird..."));
        }
    }
}

It seems if(BirdBP) is returning false. How can I change this? (Note: BirdBP is a property in the Blueprint Editor and I have set it to my Bird_BP asset , which is of type Bird and has values set such as speed and lifespanSecs etc. …

Thanks