Quick answer: Override Received_NotifyTick (or NotifyTick in newer engine versions). Ensure the AnimNotifyState’s duration in the animation is >0.
A custom AnimNotifyState should emit particles every frame while a sword swings. NotifyBegin fires; NotifyEnd fires; but per-frame work never happens. The wrong method got overridden.
The Three Methods
UCLASS()
class USwingNotifyState : public UAnimNotifyState
{
GENERATED_BODY()
public:
virtual void NotifyBegin(USkeletalMeshComponent* Mesh, UAnimSequenceBase* Anim, float Duration) override;
virtual void NotifyTick(USkeletalMeshComponent* Mesh, UAnimSequenceBase* Anim, float FrameDeltaTime) override;
virtual void NotifyEnd(USkeletalMeshComponent* Mesh, UAnimSequenceBase* Anim) override;
};
Three callbacks. Begin at start; Tick per frame during the duration; End at completion. Override all three for per-frame behavior.
Common Mistake
If you override Notify instead of NotifyTick, you get a one-shot at start, no per-frame ticking. Notify belongs to UAnimNotify (one-shot); NotifyTick belongs to UAnimNotifyState.
Verify Duration
Open the animation. Right-click the Notifies track → Add Notify State → your class. Drag to set duration: visible green bar represents the active span. A 0-width state has no Tick calls.
Blueprint Equivalents
Blueprint AnimNotifyState exposes ReceivedNotifyBegin / ReceivedNotifyTick / ReceivedNotifyEnd as event nodes. Same three callbacks; same caveat about choosing Tick for per-frame behavior.
Verifying
Add UE_LOG in NotifyTick. Play the animation; should log per frame during the green bar duration. If only seeing Begin/End logs, you didn’t override Tick or duration is 0.
“NotifyState has Begin, Tick, End. NotifyTick is per-frame; Notify alone is the one-shot variant. Pick the right base class.”
For state-based effects (trails, particles, ongoing rumble), NotifyState is the right choice over single-frame AnimNotify.