Play Different Particle Effect on AnimNotify Timed Particle Effect

So I have a timed particle effect in my animation. It works great. However, I want to switch it out for a different particle effect when the character has a certain weapon. Rather than copying/pasting the same animation and switching out the particle effect, is there a way I can switch out the particle effect in my anim bp or in C++ ? (either one works for me). I’m sure this is doable, but I just can’t find anything out there on it.

Thank you!

Hopefully this helps someone! I ended up discovering the answer to this question. I first decided to override the UAnimNotifyState_TimedParticleEffect class. However, there were some compile issues with that. Subsequently, I created a Custom_TimedNotify class and copied the exact same code from UAnimNotifyState_TimedParticleEffect except for the places that were not compiling. IT was just debug stuff that wasn’t compiling well. Specifically this location of code:

#if WITH_EDITORONLY_DATA
	// The following arrays are used to handle property changes during a state. Because we can't
	// store any stateful data here we can't know which emitter is ours. The best metric we have
	// is an emitter on our Mesh Component with the same template and socket name we have defined.
	// Because these can change at any time we need to track previous versions when we are in an
	// editor build. Refactor when stateful data is possible, tracking our component instead.
	UPROPERTY(transient)
	TArray<UParticleSystem*> PreviousPSTemplates;

	UPROPERTY(transient)
	TArray<FName> PreviousSocketNames;
	
#endif

No matter. I ended up creating my own class and then adding my own code into the notify begin area.

// Fill out your copyright notice in the Description page of Project Settings.

#include "ShooterGame.h"
#include "Custom_TimedNotify.h"
#include "ShooterCharacter.h"
#include "ShooterWeapon.h"
#include "Components/SkeletalMeshComponent.h"
#include "Particles/ParticleSystemComponent.h"
#include "Kismet/GameplayStatics.h"

UCustom_TimedNotify::UCustom_TimedNotify(const FObjectInitializer& ObjectInitializer)
	: Super(ObjectInitializer)
{
	PSTemplate = nullptr;
	LocationOffset.Set(0.0f, 0.0f, 0.0f);
	RotationOffset = FRotator(0.0f, 0.0f, 0.0f);
}


void UCustom_TimedNotify::ClearEffects()
{
	PSTemplate = NULL;
	SocketName = "";
}

void UCustom_TimedNotify::SetParticleEffect(UParticleSystem* particle)
{
	PSTemplate = particle;
}

void UCustom_TimedNotify::SetAttachPoint(FName socket)
{
	SocketName = socket;
}


void UCustom_TimedNotify::NotifyBegin(USkeletalMeshComponent * MeshComp, class UAnimSequenceBase * Animation, float TotalDuration)
{
   /* Start of custom code to grab the right weapon effects and spawn them in the proper location */
	AShooterCharacter* MyOwner = Cast<AShooterCharacter>(MeshComp->GetOwner());
	if (MyOwner)
	{
		AShooterWeapon* theweapon = Cast<AShooterWeapon>(MyOwner->GetWeapon());
		if (theweapon)
		{
			SocketName = theweapon->GetMuzzleAttachPoint();
			PSTemplate = theweapon->GetMuzzleFX();
		}
	}

	/* End of custom code to spawn my own effects in the proper location */

		// Only spawn if we've got valid params
		if (ValidateParameters(MeshComp))
		{
			UParticleSystemComponent* NewComponent = UGameplayStatics::SpawnEmitterAttached(PSTemplate, MeshComp, SocketName, LocationOffset, RotationOffset);
		}

		Received_NotifyBegin(MeshComp, Animation, TotalDuration);
	

	
}

void UCustom_TimedNotify::NotifyTick(USkeletalMeshComponent * MeshComp, class UAnimSequenceBase * Animation, float FrameDeltaTime)
{
	Received_NotifyTick(MeshComp, Animation, FrameDeltaTime);
}

void UCustom_TimedNotify::NotifyEnd(USkeletalMeshComponent * MeshComp, class UAnimSequenceBase * Animation)
{
	TArray<USceneComponent*> Children;
	MeshComp->GetChildrenComponents(false, Children);

	for (USceneComponent* Component : Children)
	{
		if (UParticleSystemComponent* ParticleComponent = Cast<UParticleSystemComponent>(Component))
		{
			bool bSocketMatch = ParticleComponent->GetAttachSocketName() == SocketName;
			bool bTemplateMatch = ParticleComponent->Template == PSTemplate;

			if (bSocketMatch && bTemplateMatch && !ParticleComponent->bWasDeactivated)
			{
				// Either destroy the component or deactivate it to have it's active particles finish.
				// The component will auto destroy once all particle are gone.
				if (bDestroyAtEnd)
				{
					ParticleComponent->DestroyComponent();
				}
				else
				{
					ParticleComponent->bAutoDestroy = true;
					ParticleComponent->DeactivateSystem();
				}
				// Removed a component, no need to continue
				break;
			}
		}
	}

	Received_NotifyEnd(MeshComp, Animation);
}

bool UCustom_TimedNotify::ValidateParameters(USkeletalMeshComponent* MeshComp)
{
	bool bValid = true;

	if (!PSTemplate)
	{
		bValid = false;
	}
	else if (!MeshComp->DoesSocketExist(SocketName) && MeshComp->GetBoneIndex(SocketName) == INDEX_NONE)
	{
		bValid = false;
	}

	return bValid;
}

FString UCustom_TimedNotify::GetNotifyName_Implementation() const
{
	if (PSTemplate)
	{
		return PSTemplate->GetName();
	}

	return UAnimNotifyState::GetNotifyName_Implementation();
}

Then voila, you get your own custom notify class when editing your animation!

231592-customnotify.png