Download

Issue with TArray

Hi

I’am creating a rpg game where i create a array with 9 slots, for that i use a TArray<FVector> Here is the code




UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Misc)
TArray<FVector> aLocationGrid;

ABattleArena::ABattleArena()
{
 	// 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;
	
	ConstructorHelpers::FObjectFinder<UBlueprint> itemBlueprint(TEXT("/Game/Blueprints/BattleGrid_BP"));

	if (itemBlueprint.Object)
	{
		uBattleGridBP = (UClass*)itemBlueprint.Object->GeneratedClass;
	}

	aLocationGrid.Add(FVector(GetActorLocation().X + 820.0f, GetActorLocation().Y - 830.0f, GetActorLocation().Z));
	aLocationGrid.Add(FVector(GetActorLocation().X + 820.0f, GetActorLocation().Y, GetActorLocation().Z));
	aLocationGrid.Add(FVector(GetActorLocation().X + 820.0f, GetActorLocation().Y + 830.0f, GetActorLocation().Z));
	aLocationGrid.Add(FVector(GetActorLocation().X, GetActorLocation().Y - 830.0f, GetActorLocation().Z));
	aLocationGrid.Add(GetActorLocation());
	aLocationGrid.Add(FVector(GetActorLocation().X, GetActorLocation().Y + 830.0f, GetActorLocation().Z));
	aLocationGrid.Add(FVector(GetActorLocation().X - 820.0f, GetActorLocation().Y - 830.0f, GetActorLocation().Z));
	aLocationGrid.Add(FVector(GetActorLocation().X - 820.0f, GetActorLocation().Y, GetActorLocation().Z));
	aLocationGrid.Add(FVector(GetActorLocation().X - 820.0f, GetActorLocation().Y + 830.0f, GetActorLocation().Z));
}


void ABattleArena::BeginPlay()
{
	Super::BeginPlay();
	
	UWorld* const world = GetWorld();

	aLocationGrid.Add(FVector(GetActorLocation().X + 820.0f, GetActorLocation().Y - 830.0f, GetActorLocation().Z));
	aLocationGrid.Add(FVector(GetActorLocation().X + 820.0f, GetActorLocation().Y, GetActorLocation().Z));
	aLocationGrid.Add(FVector(GetActorLocation().X + 820.0f, GetActorLocation().Y + 830.0f, GetActorLocation().Z));
	aLocationGrid.Add(FVector(GetActorLocation().X, GetActorLocation().Y - 830.0f, GetActorLocation().Z));
	aLocationGrid.Add(GetActorLocation());
	aLocationGrid.Add(FVector(GetActorLocation().X, GetActorLocation().Y + 830.0f, GetActorLocation().Z));
	aLocationGrid.Add(FVector(GetActorLocation().X - 820.0f, GetActorLocation().Y - 830.0f, GetActorLocation().Z));
	aLocationGrid.Add(FVector(GetActorLocation().X - 820.0f, GetActorLocation().Y, GetActorLocation().Z));
	aLocationGrid.Add(FVector(GetActorLocation().X - 820.0f, GetActorLocation().Y + 830.0f, GetActorLocation().Z));

	if (world)
	{
		for (int i = 0; i < aLocationGrid.Num(); ++i)
		{
			ABattleGrid* temp = Cast<ABattleGrid>(world->SpawnActor<ABattleGrid>(uBattleGridBP, aLocationGrid*, GetActorRotation()));
			temp->iIdGrid = i;
			temp->eGridElement = EElement::VE_Fire;
			aBattleGrids.Add(temp);
		}
	}
	
}

//Set 7 for debug
FVector ABattleArena::GetGridLocation(int32 id)
{
	return aLocationGrid[7];

}



You may wonder why I initialize 2 two times the aLocationGrid. This is where i got an issue. If I only initialize aLocationGrid array in ABattleArena constructor the BeginPlay can’t create the arena event there is value in this array the UE_LOG shows the value in log, but I try to put this value one by one , the programs crash !

If I only initialize in BeginPlay, the function GetGridLocation crashs (calls from Blueprint) because it’s can return any value of the aLocation event the programs prints the array got value in it (9)…

More stange, this class ABattleArena is use from a gameMode class. Every time I open Unreal Engine, the game crashs, but I modify the name of variable for Battle Arena in GameMode class. Build and launch, it’s now work without crashing. I have to do this process every time …

Can someone help me?

Thanks !

Update : I watch the log and it’s seems like we can’t generate actor on collision with other actor


 [2016.05.08-13.02.34:070] 94]LogSpawn:Warning: SpawnActor failed because of collision at the spawn location [X=-820.000 Y=830.000 Z=117.500] for [GameRPGCharacter_BP_C]
[2016.05.08-13.02.34:071] 94]LogSpawn:Warning: SpawnActor failed because the spawned actor /Game/Maps/UEDPIE_0_BattleMap.BattleMap:PersistentLevel.GameRPGCharacter_BP_C_13 IsPendingKill 

I am going to take a wild gander here and might be wrong. But based on what I see in the errors what is happening is as follows:

Two objects with collision are colliding whilst spawning. So you need to possibly either do a manual check at the location or you need to set the overrides for the spawn as to how you want the collision handled. (check the docs for the spawn method i nb there being some flags.)

Secondly it seems like something is trying to interact with the object that is marked for garbage collection. You could get around this by doing a IsValid check.

priot to interacting with the object throwing the exception.

I will look into this when I am at home and got a gap:) just browsing the forums while chomping some grub at work.

Looking at the code, I see a few things you could change/add to help you narrow down the problem.

First, I don’t think GetActorLocation is valid while in the constructor (but I could be wrong about that), so you probably want to do your Array population in BeginPlay or PostActorCreated.




ABattleArena::ABattleArena()
{
 	// 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;
	
	ConstructorHelpers::FObjectFinder<UBlueprint> itemBlueprint(TEXT("/Game/Blueprints/BattleGrid_BP"));

	if (itemBlueprint.Object)
	{
		uBattleGridBP = (UClass*)itemBlueprint.Object->GeneratedClass;
	}
        const int NUM_OF_SLOTS = 9; // Number of Slots for your RPG
	aLocationGrid.SetNum(NUM_OF_SLOTS);
}


void ABattleArena::BeginPlay()
{
	Super::BeginPlay();
	
	UWorld* const world = GetWorld();
        
        check(aLocationGrid.Num() == NUM_OF_SLOTS); // This is probably a bit paranoid, but it'll get compiled out in release.
	aLocationGrid[0].Set(GetActorLocation().X + 820.0f, GetActorLocation().Y - 830.0f, GetActorLocation().Z);
	aLocationGrid[1].Set(GetActorLocation().X + 820.0f, GetActorLocation().Y, GetActorLocation().Z);
	aLocationGrid[2].Set(GetActorLocation().X + 820.0f, GetActorLocation().Y + 830.0f, GetActorLocation().Z);
	aLocationGrid[3].Set(GetActorLocation().X, GetActorLocation().Y - 830.0f, GetActorLocation().Z);
	aLocationGrid[4].Set(GetActorLocation());
	aLocationGrid[5].Set(GetActorLocation().X, GetActorLocation().Y + 830.0f, GetActorLocation().Z);
	aLocationGrid[6].Set(GetActorLocation().X - 820.0f, GetActorLocation().Y - 830.0f, GetActorLocation().Z);
	aLocationGrid[7].Set(GetActorLocation().X - 820.0f, GetActorLocation().Y, GetActorLocation().Z);
	aLocationGrid[8].Set(GetActorLocation().X - 820.0f, GetActorLocation().Y + 830.0f, GetActorLocation().Z);

	if (world)
	{
		for (int i = 0; i < aLocationGrid.Num(); ++i)
		{
			ABattleGrid* temp = Cast<ABattleGrid>(world->SpawnActor<ABattleGrid>(uBattleGridBP, aLocationGrid*, GetActorRotation()));
			temp->iIdGrid = i;
			temp->eGridElement = EElement::VE_Fire;
			aBattleGrids.Add(temp);
		}
	}
	
}


Next, in your GetGridLocation method, we should probably make it a bit smarter so it handles trying to access an invalid index in the array and doesn’t crash.



// Rather than just setting this to 7 in code, I would create a constant integer (e.g. 7) in your blueprint and pass that through to here.
FVector ABattleArena::GetGridLocation(int32 id)
{
    if (!aLocationGrid.IsValidIndex(id))
    {
        // You probably want to print some log message here, swap YourGameCategory with whatever category you setup for your logging.
        UE_LOG(YourGameCategory, Warning, Text("Invalid index passed to GetGridLocation. Index = %d, Array size = %d), id, aLocationGrid.Num());
        return FVector::ZeroVector;
    }

    return aLocationGrid[id];

}


Give that a shot and see if it helps you at all. Fair warning, I didn’t compile any of this so forgive any syntax errors if you just copy/paste it.

Hi !

Indeed I need to add more check on the code like isValid, thanks I forget about this function !

For now because i’am testing, I pass right value . I know that not a good way to code ! :frowning:

Thanks now it’s work, it’s was because when the actor is spawn. it’s will collide with another actor

Treating the root cause of the issue is paramount, but in the future if you want to be able to spawn objects regardless of their position you can set the spawn parameter bNoCollisionFail = true.



if (world)
{
        FActorSpawnParameters SpawnParams;
        SpawnParams.bNoCollisionFail = true;

	for (int i = 0; i < aLocationGrid.Num(); ++i)
	{
		ABattleGrid* temp = Cast<ABattleGrid>(world->SpawnActor<ABattleGrid>(uBattleGridBP, aLocationGrid*, GetActorRotation(), SpawnParams));
		temp->iIdGrid = i;
		temp->eGridElement = EElement::VE_Fire;
		aBattleGrids.Add(temp);
	}
}