Setting variable from the BeginPlay() of a GameMode CPP doesn't work

Edit : I haven’t found the solution to the problem, but I just made a work around by having the soldier class figure out the level block he is on with a raycast on his beginplay. It seem like the pointer generated by GetAllActorsOfClass seem to provoke this bug, I do not know why.

Feel free to delete this post. Thank you for your help eblade.


I am trying to set the value of an actor that is get in the begin play of a game mode script. The game mode parse through all the level block and find the one that is tag as the starting position. Then it spawn the player character on it. That portion work. What doesn’t work is I want to also set properties on the level block that was found and the value of the object always come back to it default value of null and false (the variable UnitOnBlock and test).

Nowhere in my code do these value should be reset the next frame. It is true I could set the value a bit later, but I find it weird that I need to do such work around in the first place.

Here is the code sample:

void ATBTacticalGameMode::BeginPlay()
{
	Super::BeginPlay();
	
	//Setup TilePathFinder
	TilePathFinder = NewObject<UTilePathFinder>(GetTransientPackage(), UTilePathFinder::StaticClass());
	
	TArray<AActor*> AllActors;
	const UWorld* WorldPtr = GEditor->GetEditorWorldContext().World();
	UGameplayStatics::GetAllActorsOfClass(WorldPtr,AActor::StaticClass(),AllActors);

	if (WorldPtr && AllActors.Num() > 0)
	{
		UKismetSystemLibrary::FlushPersistentDebugLines(AllActors[0]);
		
		for (int i=0; i<AllActors.Num(); i++)
		{
			if (ALevelBlock* LevelBlockPtr = Cast<ALevelBlock>(AllActors[i]))
			{
				if (LevelBlockPtr->bIsStartingPosition)
				{
					TArray<UNodePath*> AllNodePaths;
					LevelBlockPtr->GetComponents<UNodePath>(AllNodePaths);
					UNodePath* StartingNodePtr = AllNodePaths[LevelBlockPtr->NodePathIndex];
					
					if (SoldierClass)
					{
						ASoldier* SoldierPtr = GetWorld()->SpawnActor<ASoldier>(SoldierClass, StartingNodePtr->GetComponentLocation() + FVector(0.0f,0.0f,88.0f), FRotator(0.0f, 90.0f, 0.0f));
						SoldierPtr->TileMovementComponent->LocatedNodePath = StartingNodePtr;
						LevelBlockPtr->UnitOnBlock = SoldierPtr; //get unnasign the next frame
						LevelBlockPtr->test = true; //get unnasign the next frame
					}
				}
			}
		}
	}
	
	bInitialized = true;
}
  1. Are you sure that this code is running? I don’t believe GameMode is guaranteed to BeginPlay after everything else is loaded.

  2. Assuming that GameMode BeginPlay does occur after everything else is loaded, everything else’s BeginPlay might occur after, so is there something in ALevelBlock BeginPlay or shortly thereafter changing it?

  3. Is BeginPlay really the best place to do this? StartPlay or StartMatch might be more appropriate, if this is even something that should be handled in GameMode and not elsewhere.

  1. Yeah it is running, the soldier is spawned at the right place and it is the only code that does this.

For 2 and 3, well I did further testing just for the hell of it, and it seem that the variable get reset no mater what. There is an exception later when I move my character with another code, but it is the weirdest thing.

In soldier, I use his tick component to set the variable, since I do have a reference of the levelblock that is set on the TileMovementComponent, but the very next frame, the value is reset to null.

void ASoldier::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);
	ALevelBlock* test = Cast<ALevelBlock>(TileMovementComponent->LocatedNodePath->GetOwner());
	test->UnitOnBlock = this;
}


the value is clearly assign next


but when I go to the next frame, the value is reset to what you see in the first screenshot.

This code, however work ?:

	if (bChangeDestination)
	{
		UNodePath* NodePathPtr = Path.Pop();
		if (Path.Size() == 0)
		{
			Cast<ALevelBlock>(LocatedNodePath->GetOwner())->UnitOnBlock = nullptr;
			LocatedNodePath = NodePathPtr;
			Cast<ALevelBlock>(NodePathPtr->GetOwner())->UnitOnBlock = Cast<ASoldier>(GetOwner());
		} 
		
		Destination = NodePathPtr->GetComponentLocation() + FVector(0.0f,0.0f,88.0f);
		MovementDirection = Destination - GetOwner()->GetActorLocation();
		MovementDirection.Normalize();
		bChangeDestination = false;
	}

And no, this is not where the value get reset, I already put a breakpoint there. This is where I change the reference of the soldier to a new levelblock.

At some point, I thought it was because of the Cast, but nah it is ok… I am really at my wits end with this problem lol I really don’t get what is going on in the background of Unreal …

In Visual Studio, you can set a breakpoint for a value changing by right-clicking an item in the Autos, Watch, or Locals window and selecting Break when value changes in the context menu. You can also select New > Data Breakpoint in the Breakpoints window.

Set a breakpoint on the data changing, and see what the callstack looks like then?