How to reactivate a ParticleSystemComponent after it has been deactivated?

Hello,
this is my first question here, so I hope I am following the rules here correctly.

I have a problem with reactivating a ParticleSystemComponent.

What I have is a Ribbon Data Type following my Projectile Actor.

For performance reasons I am preallocating a bunch of Projectiles and storing them in a TArray, so Projectiles don’t have to be spawned at runtime.

After a projectile needs to be “destroyed”, I am putting it back into my TArray for later usage.
At this moment I want my ParticleSystem Ribbon Trail to stop leaving a trail.

I am hiding my projectile and deactivating my UParticleSystemComponent *TrailParticles by:

Projectile->SetActorHiddenInGame(true);
Projectile->TrailParticles->DeactivateSystem();

As far as I can tell, this works. But I cannot reactivate the system with:

Projectile->SetActorHiddenInGame(false);
Projectile->TrailParticles->ActivateSystem(true);

The projectile will move without its trail.

Here is a screenshot of my

I hope you can help me out with this.

Kind regards.

I have found a link recently, which was asking about toggling of a Particle System, coming from the forums.
It was adviced to use ToggleActive() on an UParticleSystemComponent*, which I already had. So I tried it with at first creating the Projectile and then disabling the TrailParticles with:

Projectile->TrailParticles->ToggleActive();
UE_LOG(LogTemp, Log, TEXT("Trail is %s"),
	Projectile->TrailParticles->IsActive() ? TEXT("active!") : TEXT("not active."));

The Debug though showed “Trail is active!”, so I thought it was disabled on creation. But when I have removed the Projectile and put it back for later usage with

RemoveProjectile->TrailParticles->ToggleActive();
UE_LOG(LogTemp, Log, TEXT("Trail is %s"), 
	RemoveProjectile->TrailParticles->IsActive() ? TEXT("active!") : TEXT("not active."));

The Debug message was printing the same, “Trail is active!”. The reason might be that the method is shown as bool UActorComponent::IsActive() const, which won’t change its value later during runtime.

I even changed from a previous TArray approach with last in first out to a TQueue with first in first out, as I thought it had some race condition problems. But this doesn’t seem to be the case.

Does anyone know how to toggle a Ribbon Data Type?

Kind regards.

Are you able to activate the particle effect? I ask because your question regarding the Ribbon Data Type seems different, at least I don’t understand the connection at this point.

As for activating the particle effects, something I do in my own code:

TArray<UParticleSystemComponent*> theEffects;
GetComponents(theEffects);

int32 effectCount = theEffects.Num();
for (int32 y = 0; y < effectCount; y++)
{
    // if you just want to activate the effect
    theEffects[y]->Activate();

    // if you want to activate an effect by name
    if (theEffects[y]->GetName().Compare(particleSystemName) == 0)
    {
        theEffects[y]->Activate();
    }
}

My Projectiles have a public UParticleSystemComponent *TrailParticles, which I reference in the constructor by

	TrailParticles = CreateDefaultSubobject<UParticleSystemComponent>(TEXT("MovementParticles"));
	TrailParticles->AttachTo(CapsuleVisual); //the root component, a UStaticMeshComponent
	TrailParticles->bAutoActivate = true;
	TrailParticles->SetRelativeLocation(FVector(0.0f, 0.0f, 0.0f));
	static ConstructorHelpers::FObjectFinder<UParticleSystem> ParticleAsset(TEXT("/Game/Materials/Trail.Trail"));
	if (ParticleAsset.Succeeded())
	{
		TrailParticles->SetTemplate(ParticleAsset.Object);
		
		if (Debug)
		{
			UE_LOG(LogTemp, Log, TEXT("%s: Created TrailParticles."), *GetDebugName(this));
		}
	}

And in another class, I am spawning these Projectiles by

while (i < 100)
{
	Projectile = World->SpawnActor<AProjectile>(FVector(2500.f, 2500.f, -1000.f), FRotator(0.0f), SpawnInfos);
	if (Projectile != NULL)
	{
		Projectile->SetActorHiddenInGame(true);
		Projectile->ResetSpeed(); //sets the moving vector to 0, so Tick() won't move them
		Projectile->TrailParticles->ToggleActive();
		if (ProjectileQueue->Enqueue(Projectile))
			i++;
	}
}

I am preallocating some Projectiles, so I am then adding these into my TQueue, that’s why I want to disable them at first. The Ribbons should be activated, when I use the projectiles in the game, which works:

UWorld* World = Creator->GetWorld();
AProjectile* Projectile = NULL;

while (GetProjectileQueue(World)->Dequeue(Projectile) == false && Projectile == NULL)
{ // if the Queue is already empty, I am creating additional Projectiles
	if (GEngine != NULL)
	{
		if (World != NULL)
		{
			FActorSpawnParameters SpawnInfos;
			SpawnInfos.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
			Projectile = World->SpawnActor<AProjectile>(FVector(2500.f, 2500.f, -1000.f), FRotator(0.0f), SpawnInfos);
			Projectile->TrailParticles->ToggleActive();
		}
	}
}

Projectile->InstantiateProjectile(some parameters); //Method which sets some values after the constructor
Projectile->SetActorHiddenInGame(false);
Projectile->TrailParticles->ToggleActive();

To reuse projectiles, after they have hit something, I want to deactivate the Ribbon effect and insert them into the TQueue for later usage:

UWorld* World = Projectile->GetWorld();
UGameplayStatics::SpawnEmitterAtLocation(World, Projectile->ExplosionParticle->Template, Projectile->GetTransform()); //Spawns an explosion effect, which is visible.
Projectile->SetActorHiddenInGame(true);
Projectile->ResetSpeed();
Projectile->TrailParticles->ToggleActive(); // deactivate until reactivated later
Projectile->SetActorLocation(FVector(2500.f, 2500.f, -1000.f));
GetProjectileQueue(World)->Enqueue(Projectile);

When I am Dequeueing a previous used Projectile now, it will be set in the world with the third code snippet, but the Ribbon effect isn’t visible anymore.

I am pretty helpless at the moment, as I really want to use the preallocation for performance reasons on level startup, but the Trail isn’t showing up for the secondly used Projectiles.

Am I making a mistake somewhere?

Sorry for this wall of text and code snippets.

If I understand you correctly, Projectile->TrailParticles is a UParticleSystemComponent pointer. Does Activate() work:

Projectile->TrailParticles->Activate();

My setup is a little different in that I have Auto-Activate off and then I enable it when needed. In your case though you’re activating it (and it works right?), then deactivating it, and trying to reactivate it again (which isn’t working).

Yes, TrailParticles is a UParticleSystemComponent*.

I haven’t tried this with Activate(), yet, just ActivateSystem(true) and SetActive(true, true).

Yes, it works on spawn, I also can deactivate it, but reactivating it doesn’t work.

What I als tried was to not deactivate the Trails at all, but when I spawned them again into the world (secondly placed projectiles), then the Trail got very long, and UE had some Warning Debug Logs:

    LogParticles:Warning: RIBBON   : FillReplayData failed.
    LogParticles:Warning:     IndexCount (99408) exceeds allowed value (65535).
    LogParticles:Warning:     ActiveParticleCount = 500.
    LogParticles:Warning:     TriangleCount = 99406.
    LogParticles:Warning:     TrailCount = 22.
    LogParticles:Warning:     /Game/Materials/Trail.Trail

This is why I tried using TrailParticles->SetActive(true, true);, as the parameters are SetActive(bool bNewActive, bool bReset = false). So I tried activating them and also resetting them, so that it seems the trail was just spawned, but of no avail.

Are you able to reset your particle system, as you said you enable it, when needed? Or is this just a one time activation?

Maybe I am overlooking something, but I have the feeling, that a simple deactivation and reactivation of Ribbon Data Types isn’t supported. I really hope it’s just a mistake of me somewhere.

I am able to activate, deactivate, and reactive my UParticleSystemComponents using:

if (activateCounter > 0)
{
    activateCounter -= DeltaSeconds;
    if (activateCounter <= 0)
    {
        if (activeEffect != nullptr)
        {
            if (flipflop)
                activeEffect->Deactivate();
            else
                activeEffect->Activate();

            activateCounter = 10.0f;
            flipflop = !flipflop;
        }
    }
}

Are you also using a Ribbon Data Type for your Particle System?

I have tried it now with your approach:

// for spawning of Projectiles with Trail active
GetProjectileQueue(World)->Dequeue(Projectile);
Projectile->SetActorHiddenInGame(false);
Projectile->TrailParticles->Activate();  

// for removing of Projectiles with Trail inactive
Projectile->SetActorHiddenInGame(true);
Projectile->TrailParticles->Deactivate();
GetProjectileQueue(World)->Enqueue(Projectile);

But the effect seems to be the same. The secondly used projectiles aren’t leaving their Trail.

I have also set on the constructor:

TrailParticles->bAutoActivate = false;

I’m not using a ribbon. I’ll try to add one when I get a chance and see if I get the same results. At the moment I’m preoccupied with finishing up some other items so this will need to take a backseat. Hopefully you’ll figure it out or someone will at least point you in the right direction.

I would like to mention that on one thread someone else was doing object pooling but an Epic staff member advised against it. It was deemed resource intensive in doing so compared to just creating and spawning the new object. Of course this may not apply across the board, or for your use case but mentioning it here for completeness sake. In Unity I made heavy use of object pooling but as of yet I haven’t had the need to do so with the UE.

Thank you for your help so far. Your own project of course needs to take priority.

We started to need the preallocation, as spawning of new projectiles stopped the runtime by some noticeable frames. With the queueing mechanism we could remove the small freezes. But thank you for your input. It is much appreciated.

I’m having exactly the same problem after upgrading from 4.8 to 4.12. The exact method you describe was working perfectly in 4.8 but has since stopped working along the way. I’m going to diff the various files involved and see if I can find something that might have stopped this working.

Update: OK it seems that this changed at some point between 4.8 and 4.12 but now if the actor that owns the particle system component you are trying to re-activate is hidden then the particle system emitters will not be reinitialized.

One work around is to make sure you unhide the actor before you call activate() not after.

Are you also refering to Ribbon Data Types for your UParticleSystemComponents? And what methods are you talking about?

  • DeactivateSystem() / ActivateSystem(true) ?
  • ToggleActive() ?
  • SetActive(true, true) ?
  • Deactivate() / Activate() ?

Sadly I haven’t found a way around this yet, so I cannot provide you with a solution.

I just want to necro and say that as of 4.20 this is still not working for beams and ribbon particle effects.