Branch: Source 4.2
Build version: 4.2.1 (Win64 Development Editor)
I have a strange problem when spawning custom Actors.
I created ASimpleActor class which have box StaticMeshComponent, and also ASimpleActrorSpawner which spawn ASimpleActor-s to the pool (they are hidden on the start). After that I switch their visibility/collision over time (showing them in the scene). This is needed for optimization on mobile devices (exclude spawn function in the middle of gameplay).
If spawn ~1500 actors and visualize them (no matter how many), everything looks good:
But if I spawn something about >2000 actors then strange graphics artifacts apear with some actors overtime:
Looks like there is a problem with the end part of the pool. Screenshots are captured on PC, but I have also tested this code on iOS and there is the same problem, but objects are not colored and simply black. Also this issue cause a very significant draw time growth. (x10 times).
SimpleActor.h:
#pragma once
#include "GameFramework/Actor.h"
#include "SimpleActor.generated.h"
UCLASS()
class ASimpleActor : public AActor
{
GENERATED_UCLASS_BODY()
UPROPERTY(Category = SimpleActor, VisibleAnywhere, BlueprintReadOnly, meta = (ExposeFunctionCategories = "Mesh,Rendering,Physics,Components|StaticMesh"))
TSubobjectPtr<class UStaticMeshComponent> StaticMeshComponent;
virtual void Tick(float DeltaSeconds) OVERRIDE;
UFUNCTION()
void Show();
UFUNCTION()
void Hide();
uint32 Counter;
};
SimpleActor.cpp:
#include "Idol.h"
#include "SimpleActor.h"
ASimpleActor::ASimpleActor(const class FPostConstructInitializeProperties& PCIP)
: Super(PCIP)
{
static ConstructorHelpers::FObjectFinder<UStaticMesh> SM_Box(TEXT("StaticMesh'/Game/Common/Meshes/SM_Box_1.SM_Box_1'"));
bWantsInitialize = false;
Counter = 0;
StaticMeshComponent = PCIP.CreateDefaultSubobject<UStaticMeshComponent>(this, TEXT("StaticMeshComponent"));
RootComponent = StaticMeshComponent;
if (SM_Box.Object)
{
StaticMeshComponent->SetStaticMesh(SM_Box.Object);
}
StaticMeshComponent->CreateAndSetMaterialInstanceDynamic(0);
StaticMeshComponent->SetRelativeScale3D(FVector(0.2, 0.2, 0.2));
StaticMeshComponent->Mobility = EComponentMobility::Movable;
StaticMeshComponent->SetCollisionProfileName(UCollisionProfile::BlockAllDynamic_ProfileName);
}
// End
void ASimpleActor::Tick(float DeltaSeconds)
{
Super::Tick(DeltaSeconds);
Counter++;
}
// End
void ASimpleActor::Show()
{
PrimaryActorTick.bCanEverTick = true;
this->SetActorTickEnabled(true);
this->SetActorHiddenInGame(false);
this->SetActorEnableCollision(true);
}
// End
void ASimpleActor::Hide()
{
PrimaryActorTick.bCanEverTick = false;
this->SetActorTickEnabled(false);
this->SetActorHiddenInGame(true);
this->SetActorEnableCollision(false);
}
// End
SimpleActorSpawner.h:
#pragma once
#include "GameFramework/Actor.h"
#include "SimpleActor.h"
#include "SimpleActorSpawner.generated.h"
UCLASS()
class ASimpleActorSpawner : public AActor
{
GENERATED_UCLASS_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = SimpleActorSpawner)
int32 PoolSize;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = SimpleActorSpawner)
int32 VisibleAmount;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = SimpleActorSpawner)
int32 ChangesPerTick;
UPROPERTY()
TArray<ASimpleActor*> Pool;
UPROPERTY()
TArray<ASimpleActor*> Visible;
virtual void BeginPlay() OVERRIDE;
virtual void Tick(float DeltaSeconds) OVERRIDE;
UFUNCTION()
void FillPool();
};
SimpleActorSpawner.cpp:
#include "Idol.h"
#include "SimpleActorSpawner.h"
ASimpleActorSpawner::ASimpleActorSpawner(const class FPostConstructInitializeProperties& PCIP)
: Super(PCIP)
{
PrimaryActorTick.bCanEverTick = true;
this->SetActorTickEnabled(true);
PoolSize = 3000;
VisibleAmount = 400;
ChangesPerTick = 5;
}
// End
void ASimpleActorSpawner::BeginPlay()
{
Super::BeginPlay();
FillPool();
}
// End
void ASimpleActorSpawner::FillPool()
{
ASimpleActor* SimpleActor;
for (int32 i = 0; i < PoolSize; i++)
{
SimpleActor = GWorld->SpawnActor<ASimpleActor>(FVector(0, 0, 0), FRotator(0, 0, 0));
if (SimpleActor && SimpleActor->IsValidLowLevel())
{
SimpleActor->Hide();
Pool.Add(SimpleActor);
}
}
}
void ASimpleActorSpawner::Tick(float DeltaSeconds)
{
Super::Tick(DeltaSeconds);
ASimpleActor* SimpleActor;
int32 i;
for (i = 0; i < ChangesPerTick && Pool.Num() + Visible.Num() > 0; i++)
{
SimpleActor = Pool[0];
Pool.RemoveAt(0);
FVector Loc = FVector(FMath::SRand() - 0.5, FMath::SRand() - 0.5, FMath::SRand()*0.5);
Loc.Normalize();
SimpleActor->SetActorLocation(Loc * 500);
SimpleActor->Show();
Visible.Add(SimpleActor);
}
while (Visible.Num() > VisibleAmount)
{
SimpleActor = Visible[0];
Visible.RemoveAt(0);
SimpleActor->Hide();
Pool.Add(SimpleActor);
}
}
// End


