Back to Articles

Unreal Engine C++ Notifies: Supercharge Your Animations!

10 min read
unreal enginecppanimationgamedev

Hey everyone! Today, we're diving into a super useful feature in Unreal Engine: Animation Notifies, specifically how to create and use them in C++. If you've ever wanted to trigger events like footsteps, weapon swings, or any gameplay logic directly from your animations, then notifies are your best friends!


What are Animation Notifies?

At their core, Animation Notifies are events that you can place directly onto animation sequences or montages. Think of them as little markers on your animation timeline. When the animation playback hits that marker, Unreal Engine fires off the notify, allowing you to execute custom C++ or Blueprint code.

This is incredibly powerful because it lets you synchronize gameplay events precisely with your animations without messy timer setups or constant checks in your Tick function.


Why Use C++ for Notifies?

While you can create and handle notifies entirely in Blueprints, using C++ offers several advantages:

  • Performance: C++ generally offers better performance, which can be crucial for events that fire rapidly or in performance-intensive situations.
  • Control & Complexity: For more complex logic or interactions with other C++ game systems, handling notifies in C++ can be cleaner and more robust.
  • Modularity: You can create base C++ notify classes that Blueprints can then inherit from, providing a solid foundation while still allowing designers to tweak specifics.

Creating a Custom C++ AnimNotify

Let's get our hands dirty and create a simple C++ AnimNotify. This notify will just print a message to the log, but you can extend it to do anything!

  1. Create a New C++ Class: In the Unreal Editor, go to Tools -> New C++ Class. Choose AnimNotify as the parent class. Let's name it MyCustomAnimNotify.

  2. The Header File (MyCustomAnimNotify.h):

    // MyCustomAnimNotify.h
    #pragma once
    
    #include "CoreMinimal.h"
    #include "Animation/AnimNotifies/AnimNotify.h"
    #include "MyCustomAnimNotify.generated.h"
    
    UCLASS()
    class YOURPROJECT_API UMyCustomAnimNotify : public UAnimNotify
    {
        GENERATED_BODY()
    
    public:
        // This is the function that will be called when the notify is triggered
        virtual void Notify(USkeletalMeshComponent* MeshComp, UAnimSequenceBase* Animation, const FAnimNotifyEventReference& EventReference) override;
    
        // You can add properties here that can be set in the editor!
        UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Notify Properties")
        FString MessageToLog = TEXT("Default Notify Message!");
    
        UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Notify Properties")
        int32 LogVerbosity = 0; // 0 for Log, 1 for Warning, 2 for Error
    };
    
  3. The Source File (MyCustomAnimNotify.cpp):

    // MyCustomAnimNotify.cpp
    #include "MyCustomAnimNotify.h"
    #include "Components/SkeletalMeshComponent.h" // Required for USkeletalMeshComponent
    #include "Animation/AnimSequenceBase.h"    // Required for UAnimSequenceBase
    #include "Engine/Engine.h" // For GEngine
    
    void UMyCustomAnimNotify::Notify(USkeletalMeshComponent* MeshComp, UAnimSequenceBase* Animation, const FAnimNotifyEventReference& EventReference)
    {
        Super::Notify(MeshComp, Animation, EventReference); // Good practice to call parent implementation
    
        if (MeshComp && MeshComp->GetOwner())
        {
            FString OwnerName = MeshComp->GetOwner()->GetName();
            FString AnimName = Animation ? Animation->GetName() : TEXT("Unknown Animation");
    
            FString FinalMessage = FString::Printf(TEXT("Notify '%s' triggered on '%s' playing animation '%s'"),
                                                   *MessageToLog, *OwnerName, *AnimName);
    
            switch (LogVerbosity)
            {
            case 1:
                UE_LOG(LogTemp, Warning, TEXT("%s"), *FinalMessage);
                if (GEngine) GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Yellow, FinalMessage);
                break;
            case 2:
                UE_LOG(LogTemp, Error, TEXT("%s"), *FinalMessage);
                if (GEngine) GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FinalMessage);
                break;
            default:
                UE_LOG(LogTemp, Log, TEXT("%s"), *FinalMessage);
                if (GEngine) GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Green, FinalMessage);
                break;
            }
        }
        else
        {
            UE_LOG(LogTemp, Warning, TEXT("MyCustomAnimNotify: MeshComp or its Owner is null."));
        }
    }
    
  4. Compile! Close the editor, compile your C++ code (either from Visual Studio/Rider or by hitting "Compile" in the editor if it's still open and you have live coding enabled, though a full recompile is safer for new classes).


Adding Your C++ Notify in the Editor

Once compiled, you can add your shiny new notify to any animation sequence or montage:

  1. Open an Animation Sequence or Montage.
  2. In the Notifies track, right-click where you want the notify to occur.
  3. Select Add Notify... and you should find your MyCustomAnimNotify (or whatever you named it) in the list, likely under a category matching your project name or "Uncategorized".
  4. Select it. You'll see it appear on the timeline.
  5. Click on the newly added notify instance in the timeline. In the Details panel, you can now edit the Message To Log and Log Verbosity properties we exposed!

Example of adding a notify in the Unreal Animation Editor (Ideally, replace this with an actual image link or an embedded image if your MDX setup supports it)


When Do Notifies Fire? (And Anim Notify States)

  • AnimNotify: Fires as a single event when the animation playback reaches its position on the timeline. The code in Notify() is executed once.
  • AnimNotifyState: These are slightly different. They have a duration. They fire an event at the beginning of their duration (NotifyBegin), can fire an event every tick they are active (NotifyTick), and fire an event at the end of their duration (NotifyEnd). These are great for things like enabling/disabling collision for a weapon swing over a period of time. Creating a C++ UAnimNotifyState is very similar to UAnimNotify, just inherit from UAnimNotifyState and override its respective virtual functions.

Receiving Notify Events in Other C++ Classes (e.g., AnimInstance or Character)

While the UAnimNotify class itself handles the direct event, sometimes you want the AnimInstance or the Character Actor to react to these notifies in a more gameplay-specific way.

You can achieve this by:

  1. Defining a matching function in your AnimInstance: In your UAnimInstance derived class, you can create functions that follow a specific naming convention: AnimNotify_[NotifyName]. For example, if you create a notify in the editor named Footstep, you can have:

    // In YourAnimInstance.h
    UFUNCTION() // Important!
    void AnimNotify_Footstep();
    
    // In YourAnimInstance.cpp
    void UYourAnimInstance::AnimNotify_Footstep()
    {
        // Play footstep sound, spawn particle, etc.
        UE_LOG(LogTemp, Warning, TEXT("AnimInstance received Footstep Notify!"));
        // You can get the owning actor (your character) like this:
        // AActor* OwningActor = GetOwningActor();
        // if (AMyCharacter* MyChar = Cast<AMyCharacter>(OwningActor)) {
        //     MyChar->PlayFootstepEffect();
        // }
    }
    
  2. Using the Notify function in your C++ AnimNotify to call an interface or directly access the owner: In your UMyCustomAnimNotify::Notify function, you can get the owner of the MeshComp and try to cast it to your character class or call an interface function on it.

    // Inside UMyCustomAnimNotify::Notify
    AActor* OwnerActor = MeshComp->GetOwner();
    if (IMyGameplayInterface* GameplayInterface = Cast<IMyGameplayInterface>(OwnerActor))
    {
        GameplayInterface->Execute_OnCustomNotify(OwnerActor, MessageToLog); // Assuming an interface function
    }
    else if (AMyCharacter* MyChar = Cast<AMyCharacter>(OwnerActor))
    {
        // MyChar->HandleMyCustomNotify(MessageToLog); // Call a specific function on your character
    }
    

Conclusion

C++ Animation Notifies are a robust way to bridge the gap between animation and gameplay logic in Unreal Engine. They offer precision, performance, and the full power of C++ to trigger complex behaviors.

Start simple, experiment, and see how they can streamline your animation-driven events!

Happy coding!


Enjoyed this article? Share it!

Back to All Articles