Problem with Making Setup(spawn) Manager with C++

※sorry about My Poor English Conversation.

Hello, I’m Making Tile setup Manager for my Game Project.

but, there is some problems with making setup Manager. so I want to get some advices from anyone who knows with this.

first, I have made GridSetup Actor Class, this is setup Manager.

then, I made blueprint class derived from GridSetup actor class.

and, I dragged it to Level viewport.

then, I changed Properties Grid X, Grid Y. (row :Grid X , col : Grid Y) this will be applied in level viewport and Make Grid tile in level.

problem are

  1. supposing when I set initial Grid X and Grid Y to (2,2) in derived blueprint class setting, and I drag it to level viewport. Setup Manager will make 2X2 Grid. when I moved Setup Manager, 2X2 Grid Also be Moved. but there are duplicated 2x2 Grid at initial Position after already moved Setup Manager.

266181-p1.png

  1. in Derived Class blueprint editor, when I Changed Grid X and Grid Y, Grid will be spawned in blueprint viewport. I compiled and saved, and turn off the blueprint editor. but, I turn on blueprint Editor again, Editor’s viewport don’t have any Grid.

like this below Images.

I think, these are results of that I Used improper functions to setup grid.

I used PostEditChangeProperty() function. so, Grid Will be spawned when I Change Grid X and Grid Y.

And I used GetWorld()->SpawnActor to spawn Grid Instances.

GridSetup.h

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "GridSetup.generated.h"

UCLASS()
class TEST_API AGridSetup : public AActor
{
	GENERATED_BODY()
	
public:	
	// Sets default values for this actor's properties
	AGridSetup();

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

	UPROPERTY(VisibleAnywhere, Category = Grid)
		class USphereComponent* sphere;

	// resticted max size 50
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Grid, meta = (ClampMin = 0, ClampMax = 50))
		int32 grid_x;
	// resticted max size 50
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Grid, meta = (ClampMin = 0, ClampMax = 50))
		int32 grid_y;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Grid)
		float gridSize;

	UPROPERTY(EditAnywhere,BlueprintReadWrite, Category = Grid)
		TSubclassOf<class AGridBase> Grid;



public:	

	UPROPERTY(VisibleAnywhere,BlueprintReadWrite, Category = Grid)
		TArray <class AGridBase*> gridArray;

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

	virtual void PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) override;

	void SpawnGrid();

};

GridSetup.cpp

#include "GridSetup.h"
#include "GridBase.h"
#include"Engine/Classes/Engine/World.h"
#include "Runtime/Engine/Classes/Components/StaticMeshComponent.h"
#include "Runtime/Engine/Classes/Components/SphereComponent.h"

// Sets default values
AGridSetup::AGridSetup()
{
 	// Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = false;

	grid_x = 0;
	grid_y = 0;
	gridSize = 128.0f;

	sphere = CreateDefaultSubobject<USphereComponent>(TEXT("SPHERE"));
	RootComponent = sphere;
	sphere->SetSphereRadius(20.0f);

}

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

}

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


void AGridSetup::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent)
{
	Super::PostEditChangeProperty(PropertyChangedEvent);

	SpawnGrid(); // spawn function
}

void AGridSetup::SpawnGrid()
{
	if (!Grid) // grid is not exist, do not anything.
		return;
	UWorld* const world = GetWorld();
	if (!world) // check world is valid. 
		return;
	
	for (auto it = gridArray.CreateIterator(); it; it++) // delete all in gridArray
	{
		(*it)->Destroy();
	}
	gridArray.Empty();

	FVector currentPosition = RootComponent->GetComponentLocation();
	float init_y = currentPosition.Y;
	float init_x = currentPosition.X;

	for (int32 i = grid_x; i != 0; i--)
	{
		for (int32 j = grid_y; j != 0; j--)
		{

			//Grid spawn And add to Array
			AGridBase* newGrid = world->SpawnActor<AGridBase>(Grid, currentPosition, FRotator::ZeroRotator);
			newGrid->AttachToComponent(RootComponent, FAttachmentTransformRules::KeepWorldTransform);
			gridArray.Add(newGrid);
			//next Y position.
			currentPosition.Y += gridSize;

		}
		//if j end, next position for X and init Y position.
		currentPosition.X += gridSize;
		currentPosition.Y = init_y;
	}
	
}

I already search another Methods and test my code with OnConstruction() and PostInitializeComponents() but it didn’t work.

if I should not Use PostEditChangeProperty() , then What I use for spawn?
and, there is Another Spawn Method can be applied in Blueprint Viewport?
or, There is any Youtube Tutorial making Tile?

I’m using C++ for Unreal Engine about 2 months for study, and I don’t know Very much.

please don’t tell me “stop using C++, and just use blueprint for game programming”… ;(