为什么要自定义 AnimNotify

默认的 AnimNotify 只能触发“硬编码”逻辑,无法在编辑器中为同一个 Notify 设置不同数值或名字。自定义 Notify 蓝图后,就可以在不同动画关键帧上配置不同的参数。比如 "攻击伤害值"、"特效名称"、"声音" 等。

使用蓝图实现

1. 创建自定义 Notify(瞬时通知)

  • 新建蓝图类
    • 右键内容浏览器 → Blueprint Class → All Classes → AnimNotify

    • 命名如 BP_AnimNotify_Attack

  • 添加并暴露参数
    • 在 Variables 面板中添加:

      • DamageAmount : Float,勾选 Instance Editable

      • SocketName : Name,勾选 Instance Editable

  • 实现 Received_Notify
    • 在蓝图图表中重载 Received Notify 节点:

Event Received Notify (MeshComp, Animation)
   → Cast To YourCharacter
   → Call Character.TriggerAttack(DamageAmount, SocketName)

  • 使用方式
    • 打开动画序列或蒙太奇

    • 在 Notify Track 上添加 BP_AnimNotify_Attack

    • 在 Details 面板填入各帧的 DamageAmountSocketName

2. 创建自定义 NotifyState(持续通知)

  1. 新建 Blueprint Class → All Classes → AnimNotifyState

  2. 添加变量(同上,勾 Instance Editable)

  3. 重载 NotifyBegin / NotifyEnd,在开始/结束时 Spawn 或 Destroy 特效、切换状态

使用C++实现

1. 自定义瞬时 Notify:UAnimNotify

头文件:MyAnimNotify_Attack.h
#pragma once
#include "CoreMinimal.h"
#include "Animation/AnimNotifies/AnimNotify.h"
#include "MyAnimNotify_Attack.generated.h"

UCLASS()
class YOURGAME_API UMyAnimNotify_Attack : public UAnimNotify
{
    GENERATED_BODY()

public:
    // 可在动画轨道面板中编辑
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Attack")
    float Damage = 10.f;

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Attack")
    FName SocketName = NAME_None;

    virtual bool Received_Notify(USkeletalMeshComponent* MeshComp, UAnimSequenceBase* Animation) override;
};
实现文件:MyAnimNotify_Attack.cpp
#include "MyAnimNotify_Attack.h"
#include "YourGame/MyCharacterBase.h"

bool UMyAnimNotify_Attack::Received_Notify(USkeletalMeshComponent* MeshComp, UAnimSequenceBase* Animation)
{
    if (auto* Char = Cast<AMyCharacterBase>(MeshComp->GetOwner()))
    {
        Char->TriggerAttack(Damage, SocketName);
        return true;
    }
    return false;
}

2. 自定义持续 Notify:UAnimNotifyState

头文件:MyAnimNotifyState_Trail.h
#pragma once
#include "CoreMinimal.h"
#include "Animation/AnimNotifies/AnimNotifyState.h"
#include "MyAnimNotifyState_Trail.generated.h"

UCLASS()
class YOURGAME_API UMyAnimNotifyState_Trail : public UAnimNotifyState
{
    GENERATED_BODY()

public:
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Trail")
    FName SocketName = NAME_None;

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Trail")
    UParticleSystem* TrailFX = nullptr;

    virtual void NotifyBegin(USkeletalMeshComponent* MeshComp, UAnimSequenceBase* Animation, float TotalDuration) override;
    virtual void NotifyEnd(USkeletalMeshComponent* MeshComp, UAnimSequenceBase* Animation) override;
};
实现文件:MyAnimNotifyState_Trail.cpp
#include "MyAnimNotifyState_Trail.h"
#include "Kismet/GameplayStatics.h"

void UMyAnimNotifyState_Trail::NotifyBegin(USkeletalMeshComponent* MeshComp, UAnimSequenceBase* Animation, float TotalDuration)
{
    if (TrailFX && MeshComp)
    {
        UGameplayStatics::SpawnEmitterAttached(
            TrailFX,
            MeshComp,
            SocketName,
            FVector::ZeroVector,
            FRotator::ZeroRotator,
            EAttachLocation::SnapToTarget, true);
    }
}

void UMyAnimNotifyState_Trail::NotifyEnd(USkeletalMeshComponent* MeshComp, UAnimSequenceBase* Animation)
{
    // 可在此清理或停止特效
}

3. 使用方式

  • 编译完成后,打开动画或蒙太奇

  • 在 Notify Track 上添加对应的 C++ Notify 或 NotifyState
  • 在 Details 面板中填写你的 Damage、SocketName、TrailFX 等参数
Logo

分享最新的 NVIDIA AI Software 资源以及活动/会议信息,精选收录AI相关技术内容,欢迎大家加入社区并参与讨论。

更多推荐