BoxRunGame

The name of the function suggests you don’t have an object to be casting yet. Surely that function should be

ATile* SpawnedTile = GetWorld()->SpawnActor<ATile>(...);

No?

1 Like

@DanM Thank You , I Got It!
Can You Help Me Here -
I Made A System Like - If BoxPawn Overlaps On BP_Tile’s BoxComponent Then We’ll Spawn Another BP_Tile, (Game Like Temple Run , Subway etc, etc)


But Problem is They Are Spawning At Same Location:

My code:
BoxRunGameModeBase.cpp

void ABoxRunGameModeBase::SpawnTile()
{
	ATile* SpawnedTile = GetWorld()->SpawnActor<ATile>(Tile, NextSpawnPoint);
	if (!SpawnedTile) return;

	ATile* MasterTile = Cast<ATile>(SpawnedTile);
	if (!MasterTile) return;

	auto ArrowTransform = MasterTile->Transform();

	NextSpawnPoint = ArrowTransform;
}

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

	SpawnTile();
}

Tile.cpp

void ATile::BoxOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
	ABoxPawn* Pawn = Cast<ABoxPawn>(OtherActor);
	if (Pawn)
	{
		ABoxRunGameModeBase* GameMode = Cast<ABoxRunGameModeBase>(GetWorld()->GetAuthGameMode());
		GameMode->SpawnTile();
	}
}
FTransform ATile::Transform()
{
	return ArrowComp->GetRelativeTransform();
}
ATile* MasterTile = Cast<ATile>(SpawnedTile);

It’s already an ATile. The cast does nothing.

return ArrowComp->GetRelativeTransform();

Don’t use relative.

1 Like

@DanM
Ok!!

Too Many Bugs !!

After Spawning BP_Tile2095 , It Is Not Spawning More , Suddenly Stopped, And Pawn Deleted ,Why?

void ATile::BoxOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
	ABoxPawn* Pawn = Cast<ABoxPawn>(OtherActor);
	if (Pawn)
	{
		ABoxRunGameModeBase* GameMode = Cast<ABoxRunGameModeBase>(GetWorld()->GetAuthGameMode());
		GameMode->SpawnTile();
	}

	FTimerHandle Timer;
	GetWorld()->GetTimerManager().SetTimer(Timer, this, &ATile::OnTimerExpire, 2.f, false);
	
}

void ATile::OnTimerExpire()
{
	Destroy();
}

There’s an end to the world, you can’t keep going forever. Going too far from the origin starts to break physics simulations due to the imprecision of the floating point numbers.

You’re going to have to find a way to shift everything or go in a circle

Also you don’t need a timer, you can just use SetLifeSpan.

1 Like

@DanM Okk! Thanks,

So I Setup LeftTile , RightTile, T-Shape-Tile
That Will Spawn Based On A Number , Have A Look My Code

Tile.cpp

int32 ATile::GenerateRandomNumber()
{
	int32 Number = FMath::RandRange(0, 50);
	return Number;
}
void ATile::BoxOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
	float GenerateNumber = GenerateRandomNumber();
	ABoxPawn* Pawn = Cast<ABoxPawn>(OtherActor);
	if (Pawn)
	{
		ABoxRunGameModeBase* GameMode = Cast<ABoxRunGameModeBase>(GetWorld()->GetAuthGameMode());
		
		// TODO If Rand Num is Matching Then Spawn LeftTile RightTile OtherWise Continue Default
		if (GenerateNumber == 5)
		{
			GameMode->SpawnLeftTile();
		}
		else if(GenerateNumber == 10)
		{
			GameMode->SpawnRightTile();
		}
		else if (GenerateNumber == 15)
		{
			GameMode->Spawn_T_Tile();
		}
		else
		{
			GameMode->SpawnTile();
		}
	}
	SetLifeSpan(2.f);
}

// Only For T-Shape Tile , Other Are Useless
FTransform ATile::SecondArrowTransform()
{
	return SecondArrowComp->GetComponentTransform();
}
  • This Algorithm is Kinda Weird

  • I Would Like To Know Your Algorithm For Spawning Left, Right & T-Tile Randomly

BoxRunGameModeBase.cpp

void ABoxRunGameModeBase::SpawnTile()
{
	ATile* SpawnedTile = GetWorld()->SpawnActor<ATile>(Tile, NextSpawnPoint);
	if (!SpawnedTile) return;
	auto ArrowTransform = SpawnedTile->Transform();
	NextSpawnPoint = ArrowTransform;
	
	// TODO Stop One Side Tile Of T_Tile Spawning
	// ? - Error To Fix - When 2nd T_Tile Spawned Then 1st T_Tile Branch Becomes UnOfficial
	if (bTSpawned)
	{
		ATile* SecondSpawnedTile = GetWorld()->SpawnActor<ATile>(Tile, SecondSpawnPoint);
		if (!SecondSpawnedTile) return;
		auto NextTSpawnPoint = SecondSpawnedTile->Transform();
		SecondSpawnPoint = NextTSpawnPoint;
	}
}

void ABoxRunGameModeBase::SpawnLeftTile()
{
	ATile* SpawnedTile = GetWorld()->SpawnActor<ATile>(LeftTile, NextSpawnPoint);
	if (!SpawnedTile) return;
	auto ArrowTransform = SpawnedTile->Transform();
	NextSpawnPoint = ArrowTransform;

	if (bTSpawned)
	{
		ATile* SecondSpawnedTile = GetWorld()->SpawnActor<ATile>(LeftTile, SecondSpawnPoint);
		if (!SecondSpawnedTile) return;
		auto NextTSpawnPoint = SecondSpawnedTile->Transform();
		SecondSpawnPoint = NextTSpawnPoint;
	}
}

void ABoxRunGameModeBase::SpawnRightTile()
{
	ATile* SpawnedTile = GetWorld()->SpawnActor<ATile>(RightTile, NextSpawnPoint);
	if (!SpawnedTile) return;
	auto ArrowTransform = SpawnedTile->Transform();
	NextSpawnPoint = ArrowTransform;

	if (bTSpawned)
	{
		ATile* SecondSpawnedTile = GetWorld()->SpawnActor<ATile>(RightTile, SecondSpawnPoint);
		if (!SecondSpawnedTile) return;
		auto NextTSpawnPoint = SecondSpawnedTile->Transform();
		SecondSpawnPoint = NextTSpawnPoint;
	}
}

void ABoxRunGameModeBase::Spawn_T_Tile()
{
	// TODO Suppose When LeftTile Choosen Then T_Tile Will Spawn On SecondSpawnPoint, When RightTile Then T_Tile Will Spawn On  NextSpawnPoint 
	ATile* SpawnedTile = GetWorld()->SpawnActor<ATile>(T_Tile, NextSpawnPoint);
	if (!SpawnedTile) return;

	bTSpawned = true;

	auto ArrowTransform = SpawnedTile->Transform();
	NextSpawnPoint = ArrowTransform;

	auto SecondArrowTransform = SpawnedTile->SecondArrowTransform();
	SecondSpawnPoint = SecondArrowTransform;
}
  • May Be My Algorithm is Weird , So Can You Give Some Clue For Spawning T_Tile And Maintaining Its Branch, When I Turn From T_Tile Then Other Side Of T_Tile Should Vanish

T_Tile :

What you have seems fine. Though you are storing it in a float instead of int32.

You could have the T tile store a two TArray’s of tiles that are spawned for each side and then destroy the non taken path on overlap

1 Like

@DanM Thanks,

No Its Not seems fine And float instead of int32 Didn’t Solve The Spawning Issue.

Also I Created Two Arrays But I Am Stuck, Can You Give Me More Clues Please?
See My Code: This Code is Not Working Properly

BoxRunGameModeBase.cpp

void ABoxRunGameModeBase::SpawnTile()
{
	ATile* SpawnedTile = GetWorld()->SpawnActor<ATile>(Tile, NextSpawnPoint);
	if (!SpawnedTile) return;
	auto ArrowTransform = SpawnedTile->Transform();
	NextSpawnPoint = ArrowTransform;
	
	RightSideTile.Add(SpawnedTile);
	
	if (bTSpawned)
	{
		ATile* SecondSpawnedTile = GetWorld()->SpawnActor<ATile>(Tile, SecondSpawnPoint);
		if (!SecondSpawnedTile) return;
		auto NextTSpawnPoint = SecondSpawnedTile->Transform();
		SecondSpawnPoint = NextTSpawnPoint;

		LeftSideTile.Add(SecondSpawnedTile);
	}
}
void ABoxRunGameModeBase::DeleteLeftTile()
{
	for (ATile* TileToDelete : LeftSideTile)
	{
		TileToDelete->Destroy();
	}
}

void ABoxRunGameModeBase::DeleteRightTile()
{
	for (ATile* TileToDelete : RightSideTile)
	{
		TileToDelete->Destroy();
	}
}

Tile.cpp

void ATile::TLeftBoxOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, 
	UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
	ABoxPawn* Pawn = Cast<ABoxPawn>(OtherActor);
	ABoxRunGameModeBase* GameMode = Cast<ABoxRunGameModeBase>(GetWorld()->GetAuthGameMode());
	if (Pawn && GameMode)
	{
		GameMode->DeleteRightTile();
	}
}

void ATile::TRightBoxOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, 
	UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
	ABoxPawn* Pawn = Cast<ABoxPawn>(OtherActor);
	ABoxRunGameModeBase* GameMode = Cast<ABoxRunGameModeBase>(GetWorld()->GetAuthGameMode());
	if (Pawn && GameMode)
	{
		GameMode->DeleteLeftTile();
	}
}

T_Tile Setup:

I wasn’t suggesting that would fix it. Just pointing out that the function returns an int, used like an int, yet your variable is using float.

I’m just giving ideas on how to go about it. I haven’t sat down to actually plan it all out as I don’t have the time.
Another aproach is for tiles to store a pointer to the tile they spawn and for the T tile to store two for each side, then when the pawn picks a side, walk down the pointers of teh other side until the end and destroy.
You may get a race condition where you destroy just after the tile spawns. Don’t have any ideas about how to solve that off the top of my head.

1 Like

@DanM Hey, I’m Really Sorry , I Shouldn’t Said That, Please Forgive Me.

That We Always Want !!!


Okk ,I Will Take Care Of T-Tile Later,
Before That I Wanna Fix The Spawning Issue
I Created A System Like Instead Of Generating Random Number Every Overlap, We Will Generate The Random Number By A Delay (SetTimer)
And After Using The Number Once We Will Set It To Default (3).
But Problem Is The SetTimer() Function isn’t Following The Timer Rate, It Is Running in Every Frame , Why?

My Code:

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

	GeneratedNumber = 3;
	FTimerHandle Timer;
	GetWorld()->GetTimerManager().SetTimer(Timer, this, &ATile::StoreGenerateNumber, 2.f, true);
}

void ATile::BoxOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, 
	UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
	ABoxPawn* Pawn = Cast<ABoxPawn>(OtherActor);
	if (Pawn)
	{
		UE_LOG(LogTemp, Warning, TEXT("%i"), GeneratedNumber)
		Spawn();
	}
}

void ATile::Spawn()
{
	ABoxRunGameModeBase* GameMode = Cast<ABoxRunGameModeBase>(GetWorld()->GetAuthGameMode());

	if (GeneratedNumber == 0)
	{
		GameMode->SpawnLeftTile();
	}
	if (GeneratedNumber == 1)
	{
		GameMode->SpawnRightTile();
	}
	if (GeneratedNumber == 2)
	{
		GameMode->Spawn_T_Tile();
		GameMode->bTSpawned = true;
	}
	if (GeneratedNumber == 3)
	{
		GameMode->SpawnTile();
	}
	GeneratedNumber = 3;

	SetLifeSpan(2.f);
}

int32 ATile::GenerateRandomNumber()
{
	int32 Number = FMath::RandRange(0, 2);
	return Number;
}

void ATile::StoreGenerateNumber()
{
	GeneratedNumber = GenerateRandomNumber();
	UE_LOG(LogTemp, Error, TEXT("%i"), GeneratedNumber)
}

Log:
786378378378378
The Red Lines Are Generating Random Number , My Question Is Why It Is In Every Line?
It Suppose To Be After 2 Sec Later Right??
Please Help Me.
I Spend 6 hours On It, Can’t Figure It Out,

Is your repo up to date?

1 Like

@DanM Thank You Very Much ,

Just Updated - Repo

– Just Take Your Time :slightly_smiling_face:

They’re from different tiles

LogTemp: Error: [BP_Tile_C_5] 1
LogTemp: Error: [BP_Tile_C_4] 0
LogTemp: Error: [BP_Tile_C_1] 1
LogTemp: Error: [BP_Tile_C_9] 1
LogTemp: Error: [BP_Tile_C_8] 2
LogTemp: Error: [BP_Tile_C_3] 2
LogTemp: Error: [BP_Tile_C_0] 1
LogTemp: Error: [BP_Tile_C_7] 2
LogTemp: Error: [BP_Tile_C_2] 1
LogTemp: Error: [BP_Tile_C_6] 2

Also I think it would be better if you make the T tile a derived class. Have ATile hold a pointer to the spawned tile. Have ATTile store an additional pointer and then have a protected member function that’s something like

ATile::RecursiveDestroy()
{
    if(SpawnedTile)
    {
        SpawnedTile->RecursiveDestroy();
    }
    Destroy();
}

And calling that on which ever path isn’t taken.

1 Like

@DanM
Oh No!!! How I Missed The Definition Of BeginPlay()!!!
Ok Thanks !!!
And Finally I Completed The T-Tile Story, Thanks For The Idea, :handshake:


But I Am Getting A Small Issue While I Playing - Unreal Is Crashing if We Choose 3 Times Right And 1 Time Left Or 5 Times Right 1 Time Left From The T-Tile.


Can You Help Me To To Find The Cause?

BoxRunGameModeBase.cpp [131]
1
TTile.cpp[80]

Can’t seem to reproduce this on my end. So choose right 3 times and then on the 4th go left?

1 Like

@DanM
Yes , If You Choose 5 Times Right , and Then Left , Or Vice Versa , then This Error Occurs,
Also , Can You See Any Error In My Code?

I do not and I’m not crashing with what you have on GitHub.

On a side note I think you might need to do a line trace before spawning as I’ve been hit/blocked by raised tiles so they should be raised/lowered by enough for clearance of the cube.

One solution for not having tiles spawn into existing ones is to use SweepSingleBy

1 Like

@DanM ,
Hey , I Am Really Sorry For Asking Same Topic , But You Said There Were No Error In My Code , And That’s Why I Am Confused , So I Made A Video Of This Incident,
Video Link - UE4 Crash Video - Google Drive
If You Have Tried This Steps (5R - 5L - R) and Didn’t Crash Then What Can I Consider For This?
Also What’s The Error is Saying? Reading A Null Memory Address?


Yes, I Am Working On It,


  • *** okk!!! I Have a Questions ***
    So In My Code I Have Setup Everything In GameMode And Then Calling Them From Different Class(Tile, TTile), My Question Is, Is There Something else ,That Is Similar As GameMode So We Can Setup There that We Have Currently,
    In Simple Text, Is There Are Something Similar As BoxRunGameModeBase So We Can Setup Everything There , What We Have Currently in BoxRunGameModeBase?

You said 5 then 1. Now I’m getting a crash with 5, 5, 1

Just use the tile?

I see your issue. You’re only clearing one array when you delete the tile, you need to clear both.

1 Like

Privacy & Terms