You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将TSubclassOf<>对应的子类类型传入FindNotifyByClass模板函数?

问题描述

我定义了以下结构体:

USTRUCT(BlueprintType)
struct FNotifyFunc
{
    GENERATED_USTRUCT_BODY()

    UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "Animation")
    TSubclassOf<UBaseAnimNotify> Notify;
    
    UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "Animation")
    FName FuncName;
};

USTRUCT(BlueprintType)
struct FAnimations
{
    GENERATED_USTRUCT_BODY()

    UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "Animation")
    FName NameOfAnimation;

    UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "Animation")
    UAnimMontage* AnimMontage;

    UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "Animation")
    TArray<FNotifyFunc> AnimNotifies;
};

我有多个UBaseAnimNotify的子类,每个对应不同的通知事件。每个动画都有一组唯一类的通知,希望在游戏启动时遍历结构体完成初始化:

void ABaseRangeWeapon::InitAnimations()
{
    for (const FAnimations AnimationSet : Animations)
    {
        if (!AnimationSet.AnimNotifies.Num()) continue;
        for (const FNotifyFunc NotifySet : AnimationSet.AnimNotifies)
        {
            if (auto Notify = AnimUtils::FindNotifyByClass<decltype(NotifySet.Notify->GetDefaultObject())>(AnimationSet.AnimMontage))
            {
                Notify->GetDefaultObject()->OnNotified.AddUFunction(this, NotifySet.FuncName);
                continue;
            }
            //UE_LOG()
            checkNoEntry();
        }
    }
}

AnimUtils::FindNotifyByClass函数实现如下:

template<typename T>
    static T* FindNotifyByClass(UAnimMontage* Animation)
    {
        if (Animation)
        {
            for (auto NotifyEvent : Animation->Notifies)
            {
                if (auto  AnimationNotify = Cast<T>(NotifyEvent.Notify))
                {
                    return AnimationNotify;
                }
            }
        }
        return nullptr;
    }

尝试传入默认对象并修改FindNotifyByClass来检查UClasses,但无法返回所需类的对象。问题出在TSubclassOf上,希望将子类的类型传递给FindNotifyByClass()。

解决方案

核心问题是decltype(NotifySet.Notify->GetDefaultObject())推导的是UBaseAnimNotify*,无法正确识别子类类型。需要调整工具函数逻辑,直接基于UClass进行匹配,而非依赖模板类型推导。

1. 修改工具函数,新增UClass匹配版本

新增一个非模板重载,直接接收UClass参数来匹配通知类:

static UBaseAnimNotify* FindNotifyByClass(UAnimMontage* Animation, UClass* NotifyClass)
{
    if (!Animation || !NotifyClass)
        return nullptr;

    for (auto& NotifyEvent : Animation->Notifies)
    {
        if (UBaseAnimNotify* Notify = Cast<UBaseAnimNotify>(NotifyEvent.Notify))
        {
            // 检查当前通知类是否为目标类或其子类
            if (Notify->GetClass()->IsChildOf(NotifyClass))
            {
                return Notify;
            }
        }
    }
    return nullptr;
}

2. 更新初始化逻辑

直接传入NotifySet.Notify(TSubclassOf可隐式转换为UClass*),同时修复默认对象调用的错误:

void ABaseRangeWeapon::InitAnimations()
{
    for (const FAnimations& AnimationSet : Animations)  // 用引用避免不必要的结构体拷贝
    {
        if (!AnimationSet.AnimMontage || AnimationSet.AnimNotifies.Num() == 0)
            continue;

        for (const FNotifyFunc& NotifySet : AnimationSet.AnimNotifies)
        {
            if (!NotifySet.Notify || NotifySet.FuncName.IsNone())
                continue;

            if (UBaseAnimNotify* Notify = AnimUtils::FindNotifyByClass(AnimationSet.AnimMontage, NotifySet.Notify))
            {
                // 直接绑定到动画蒙太奇中实际的通知实例,而非默认对象
                Notify->OnNotified.AddUFunction(this, NotifySet.FuncName);
                continue;
            }
            
            UE_LOG(LogTemp, Warning, TEXT("找不到对应通知类 %s,动画:%s"), 
                   *NotifySet.Notify->GetName(), *AnimationSet.NameOfAnimation.ToString());
            // checkNoEntry(); // 建议用日志替代崩溃,方便调试
        }
    }
}

可选:保留模板版本兼容原有调用

如果需要保留模板调用方式,可以新增模板重载,复用上面的UClass匹配逻辑:

template<typename T>
static T* FindNotifyByClass(UAnimMontage* Animation)
{
    return Cast<T>(FindNotifyByClass(Animation, T::StaticClass()));
}

这样既支持通过TSubclassOf传入类对象,也支持直接用子类类型模板调用。

内容的提问来源于stack exchange,提问作者Alexander Odnoromanenko

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 19:10:35