Arguments of SpawnEmitterAtLocation

Hi

I’m trying to add some explosion effect to my spheres

I’ve created a


UPROPERTY()
		class UParticleSystemComponent* DestroyParticleSystem;

Then I’ adding it into the cpp file

After that i’m gonna use particle system in my OnHit function to destroy the sphere with an explosion

void AEnemy::OnCompHit(UPrimitiveComponent* HitComp, AActor* OtherActor, UPrimitiveComponent* OtherComp, FVector NormalImpulse, const FHitResult& Hit)
{
	if (IsValid(OtherActor) && IsValid(OtherComp)) 
	{ // Check that these are not nullptr and not pending kill
		UGameplayStatics::SpawnEmitterAtLocation( ???, DestroyParticleSystem, this->GetActorLocation(), FRotator::ZeroRotator, true, NAME_None, false);
		AddDeathCount();
	}
}

What are the correct arguments for the SpawnEmitterAtLocation? What is the correct argument should be instead of “???”

I’ m using this version of the function:

static UParticleSystemComponent * SpawnEmitterAtLocation
(
    const UObject * WorldContextObject,
    UParticleSystem * EmitterTemplate,
    FVector Location,
    FRotator Rotation,
    bool bAutoDestroy,
    EPSCPoolMethod PoolingMethod,
    bool bAutoActivateSystem
)

Also could you explain the meaning of all arguments of this function? I understand the meaning of Location and Rotation, AutoDestroy, but WorldContextObject, PoolingMethod and AutoActivateSystem(a little bit) are incomprehensible to me

You want a world location. Typically you want the world location of the impact point where the explosion hit (you may get this from collision testing/handling) but, worst case, just use the actor world location of the exploding actor.

PoolingMethod has to do with if you have tons of explosions, and want them to re-use rendering resources (and limit the max number going at the same time.)
AutoActivateSystem means it will start playing right away, you don’t have to separately call Activate on it to make it start emitting particles and animate.
WorldContextObject is the object that tells this system which world to spawn into. 99.9999% of the time, you’ll want to use the object that’s exploding, or if that’s already gone, use perhaps the player(controller) viewing the explosion.

2 Likes

Listen to this ^^^.

Also, you’re giving a UParticleSystemComponent into the SpawnEmitterAtLocation’s EmitterTemplate argument. That’s wrong – you need to give it a UParticleSystem. SpawnEmitterAtLocation makes the new component automatically, so you can remove the DestroyParticleSystem component is the only place you are using it. To store the emitter template, in your header file, you’ll want to add a UParticleSystem variable, and set that to ParticleAsset.Object in the constructor. Then pass it in to the SpawnEmitterAtLocation function.

Hope this helps!

Thanks for the explanation. Now it became much clearer to me

As I don’t understand how to use my Actor as a UObject class (maybe I should use cast, but it’s not gonna work), I decided to use this overriden version:

static UParticleSystemComponent * SpawnEmitterAtLocation
(
    UWorld * World,
    UParticleSystem * EmitterTemplate,
    const FTransform & SpawnTransform,
    bool bAutoDestroy,
    EPSCPoolMethod PoolingMethod,
    bool bAutoActivate
)

In this way:

UGameplayStatics::SpawnEmitterAtLocation(this->GetWorld(), DestroyParticleSystem, this->GetTransform(), true, NAME_None, false);

However I still don’t understand the pooling method. I’m trying to create a variable EPSCPoolMethod Pool but I can’t assign any value to it

Clear, thanks!

But whar are the ways of setting Objects to UParticleSystem variable? Can’t find anything in documentation

I’m not quite sure what you mean… what I meant by setting the ParticleSystem template was this:

Header file, in class:

UParticleSystem* MyParticleSystem;

CPP file, in constructor:

static ConstructorHelpers::FObjectFinder<UParticleSystem> ParticleAsset("/Game/StarterContent/Particles/P_Explosion.P_Explosion"));
MyParticleSystem = ParticleAsset.Object;
1 Like

An AActor is a UObject. So if you just pass in this as the argument, it will work. No casting required.


Also, this->GetWorld() can be substituted with GetWorld() and this->GetTransform() can be substituted with just GetTransform(). You only need this when you want a reference to the current object.


Just pass in “EPSCPoolMethod::YourEnumChoice” as the argument.

Okay, the things are really easier than I thought)

After all the fixes project compiled but there is no particle effect onhit (as no autodestroy as well)

I’m trying to use the function this way:

void AEnemy::OnCompHit(UPrimitiveComponent* HitComp, AActor* OtherActor, UPrimitiveComponent* OtherComp, FVector NormalImpulse, const FHitResult& Hit)
{
	if (IsValid(OtherActor) && IsValid(OtherComp)) 
	{
		UGameplayStatics::SpawnEmitterAtLocation(GetWorld(), DestroyParticleSystem, GetTransform(), true, EPSCPoolMethod::None, false);
		AddDeathCount();
//		Destroy(); // Destroy self if we hit anything
	}
}

Do you know if the code is actually being run? You could put this after the “AddDeathCount” line to print to the OutputLog to check:

UE_LOG(LogTemp, Warning, TEXT("Enemy was hit"));

If the code was run, you’ll see “Enemy was hit” in the log.

Logging is a very handy tool and you should get to know it anyway :slight_smile: