Use SetActorLocation() for elements in OnConstruction()

Hello,

I want to move static meshes continuously in one direction. I’m using the OnConstruction() function because I want to dynamically modify in the editor the number of static meshes, the distance between them, and the scale of each.

The problem is that I can’t move the static meshes created with OnConstruction(). I use SetActorLocation(), the actor’s coordinates change but the meshes don’t.

Here’s what I’ve done in my code:

Buildings.h
private:

UPROPERTY(VisibleAnywhere)
TArray<UStaticMeshComponent*> Pillars;

UPROPERTY(EditAnywhere)
int NumOfPillars = 10;

UPROPERTY(EditAnywhere)
float PillarGap = 500.0f;

UPROPERTY(EditAnywhere)
float MoveSpeed = -10.0f;

UPROPERTY(EditAnywhere)
float PillarHeightMin = 1.0f;

UPROPERTY(EditAnywhere)
float PillarHeightMax = 4.0f;

UPROPERTY(EditDefaultsOnly)
UStaticMesh* PillarMesh;

UPROPERTY(EditDefaultsOnly)
USceneComponent* Root;

UFUNCTION(BlueprintCallable)
void SpawnPillars();

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

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

	// Construction Script
	virtual void OnConstruction(const FTransform& Transform) override;

public:	
	// Called every frame
	virtual void Tick(float DeltaTime) override;
};
Buildings.cpp
#include "Buildings.h"

void ABuildings::SpawnPillars()
{
	UE_LOG(LogTemp, Warning, TEXT("Spawning Pillars"));

	for (size_t i = 0; i < Pillars.Num(); i++)
	{
		if (Pillars[i])
		{
			Pillars[i]->DestroyComponent();
		}
	}

	Pillars.Empty();

	for (size_t i = 0; i < NumOfPillars; i++)
	{
		UStaticMeshComponent* smc = (UStaticMeshComponent*)AddComponentByClass(UStaticMeshComponent::StaticClass(), false, FTransform(), true);
		
		if (smc)
		{
			smc->RegisterComponent();
			smc->SetMobility(EComponentMobility::Movable);
			smc->AttachToComponent(Root, FAttachmentTransformRules::SnapToTargetNotIncludingScale);
			smc->SetWorldLocation(GetActorLocation() + FVector(0, PillarGap * i, 0));
			smc->SetWorldScale3D(FVector(1, 1, FMath::RandRange(PillarHeightMin, PillarHeightMax))); // Hauteur des meshs randomisés
			smc->SetStaticMesh(PillarMesh);
			Pillars.Add(smc);
		}
	}
}

// Sets default values
ABuildings::ABuildings()
{
 	// 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;

	Root = CreateDefaultSubobject<USceneComponent>(TEXT("Root"));
	SetRootComponent(Root);

}

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

void ABuildings::OnConstruction(const FTransform &Transform)
{
	SpawnPillars();
}

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

	// Moving pillars
	SetActorLocation(GetActorLocation() + FVector(0, MoveSpeed * DeltaTime, 0));

	GEngine->AddOnScreenDebugMessage(-1, 2.0f, FColor::Red, GetActorLocation().ToString());
}

As you can see, I use SetActorLocation(GetActorLocation() + FVector(0, MoveSpeed * DeltaTime, 0));

The actor itself moves well, but my meshs don’t.

Thank you very much for your help.

I would suggest using local transform using SetRelativeLocation or AddRelativeLocation. It should behave the same and can be visualized inside blueprints too.

// Set relative location and scale instead of world
			smc->SetRelativeLocation(FVector(0, PillarGap * i, 0));
			smc->SetRelativeScale3D(FVector(1, 1, FMath::RandRange(PillarHeightMin, PillarHeightMax)));

I’ve already tried it and unfortunately it makes no difference. The actor himself moves well, but the meshes do not. I really don’t know what I need to change.

Hi @Shotendev,

May you be great!

This issue is quite simple to solve, simple call Super on your OnConstruction:

void ABuildings::OnConstruction(const FTransform &Transform)
{
	Super::OnConstruction(Transform);
	SpawnPillars();
}

or even (Depending on your implementation)

void ABuildings::OnConstruction(const FTransform &Transform)
{
	SpawnPillars();
	Super::OnConstruction(Transform);
}

May that help you.

Bye.

Hello,

Thank you very much for offering your help. I’ve tried both solutions, but it doesn’t make any difference. I hope it’s not just a bug on my end.

It doesn’t make sense, since all changed variables on OnConstruction() are UPROPERTY(), that should update the transformation.

Have you tried reload your blueprint?

It just didn’t make sense! I’ve just deleted my blueprint actor and recreated it again from the C++ class and it works. Thanks a lot for your help.