【UE4 C++ 】动画与行为树相关模块初步使用

注意添加模块 "AIModule", "GamePlayTasks", "NavigationSystem"

动画资源 UAnimationAsset

类层级结构

  • UObjectBase
    • UObjectBaseUtility
      • UObject
        • UAnimationAsset
          • UAnimSequenceBase
            • UAnimCompositeBase
              • UAnimComposite 动画合成
              • UAnimMontage 动画蒙太奇
            • UAnimSequence 动画序列 (注意 root motion)
            • UAnimStreamable
          • UBlendSpaceBase
            • UBlendSpace 混合空间
              • UAimOffsetBlendSpace 瞄准偏移混合空间
            • UBlendSpace1D 一维混合空间
              • UAimOffsetBlendSpace1D 一维瞄准偏移混合空间
          • UPoseAsset

C++ 调用

UAnimationAsset

  • 加载的是如动画序列、动画蒙太奇等派生类,可直接播放

    // 加载
    UAnimationAsset* AnimDead_I;
    AnimDead_I = LoadObject<UAnimationAsset>(nullptr, TEXT("AnimSequence'/Game/Res/PolygonAdventure/Mannequin/Enemy/Animation/FightGroup/Enemy_Dead_I.Enemy_Dead_I'"));
    
    // 加载 构造函数使用
    UAnimationAsset* DeadAnim ; 
    static ConstructorHelpers::FObjectFinder<UAnimationAsset> StaticDeadAnim(TEXT("AnimSequence'/Game/Res/PolygonAdventure/Mannequin/Player/Animation/Player_Death.Player_Death'"));
    DeadAnim = StaticDeadAnim.Object;
    
    // 播放,可以保留最后一帧
    GetMesh()->PlayAnimation(DeadAnim, false);
    
    // 获取时长
    AnimDead_I->GetMaxCurrentTime()
    

UAnimSequence

  • 可直接播放

  • 返回的时长可用于行为树等待时间

  • 返回的 transform 可以用于 Modify bone,如果有需要的话

  • 不设置循环播放,可以定格在最后一帧

    // 加载
    static ConstructorHelpers::FObjectFinder<UAnimSequence> StaticAnimAttackSeq_III(TEXT("AnimSequence'/Game/Res/PolygonAdventure/Mannequin/Enemy/Animation/FightGroup/Enemy_Attack_III.Enemy_Attack_III'"));
    UAnimSequence* AnimAttackSeq_III;
    AnimAttackSeq_III = StaticAnimAttackSeq_III.Object;
    
    // 获取时长
    AnimAttackSeq_III->GetPlayLength()
    // 获取 transform
    AnimAttackSeq_III->GetBoneTransform(OutputTrans, 0.f, CurrentPlayTime, true);
    

UAnimMontage

  • 可以通过slot,实现动画融合

  • 如果需要的话,需要设置使其定格最后一帧;或者在属性设置里不勾选 "enable auto blend out"

  • 可配合 对应 UAnimSequence 的长度用于行为树等待时间

  • 可在每帧进行判断后播放;或者想要调用时播放,例如characer、UBTTaskNode

    //播放
    Montage_Play(AnimHurt);
    
    // 判断是否播放
    Montage_IsPlaying(AnimHurt)
    
    //停止蒙太奇
    void Montage_Stop(float InBlendOutTime, const UAnimMontage* Montage = NULL);
    Montage_Stop(0); // 停止所有蒙太奇
    
    // 与定格最后一帧相关的几种方式
    GetMesh()->GlobalAnimRateScale = 0.f;
    GetMesh()->bNoSkeletonUpdate = true;
    GetMesh()->bPauseAnims = true;
    

动画实例UAnimInstance 与 动画蓝图UAnimBlueprint

本文地址 https://www.cnblogs.com/shiroe/p/15634220.html

简述

  • 一般创建动画蓝图时需要选择 UAnimInstance 的Parent Class
  • 因此创建 UAnimInstance 后,在其内部写各种变量和方法,再通过动画蓝图可以实现C++与蓝图之间的通信。比如变量用于动画状态机,事件用于动画通知的调用
  • 刚开始使用 Montage 时,一般会在 character 里调用,后来发现其实也可以放进 UAnimInstance 里面使用

C++ 调用

  • 重写 NativeUpdateAnimation 函数,类似Tick

    virtual void NativeUpdateAnimation(float DeltaSeconds) override;
    
  • 加载动画蓝图

    // 加载与设置
    static  ConstructorHelpers::FClassFinder<UAnimInstance> StaticEnemyAnim(TEXT("AnimBlueprint'/Game/Blueprints/Enemy/BPA_Eneymy.BPA_Eneymy_C'"));
    // GetMesh()->SetAnimationMode(EAnimationMode::AnimationBlueprint);
    GetMesh()->SetAnimClass(StaticEnemyAnim.Class);
    
    // character 获取**UAnimInstance** 
    SEAnim = Cast<UEnemyAnim>(GetMesh()->GetAnimInstance());
    
    

行为树相关模块

  • UBTService 可用于数据更新

  • UBTDecorator

  • UBlackboardData 黑板数据,Editor下可以使用 Data Asset 继承之

    • 可重载

      virtual void PostLoad() override;
      
    • 添加数据,几种类型

      //等待时长
      FBlackboardEntry WaitTime;
      WaitTime.EntryName = FName(TEXT("WaitTime"));
      UBlackboardKeyType_Float* WaitTimeKeyType = NewObject<UBlackboardKeyType_Float>();
      WaitTime.KeyType = WaitTimeKeyType;
      Keys.Add(WaitTime);
      
      //敌人攻击类型
      FBlackboardEntry AttackType;
      AttackType.EntryName = FName(TEXT("AttackType"));
      UBlackboardKeyType_Enum* EnemyAttackTypeKeyType = NewObject<UBlackboardKeyType_Enum>();
      // 通过反射获取枚举类型
      EnemyAttackTypeKeyType->EnumType = FindObject<UEnum>(ANY_PACKAGE, *FString("EEnemyAttackType"), true);
      EnemyAttackTypeKeyType->EnumName = FString("EEnemyAttackType");
      AttackType.KeyType = EnemyAttackTypeKeyType;
      Keys.Add(AttackType);
      
      // 玩家指针
      FBlackboardEntry PlayerPawn;
      PlayerPawn.EntryName = FName(TEXT("PlayerPawn"));
      UBlackboardKeyType_Object* PlayerPawnKeyType = NewObject<UBlackboardKeyType_Object>();
      PlayerPawnKeyType->BaseClass = ASLAiPlayerCharacter::StaticClass();
      PlayerPawn.KeyType = PlayerPawnKeyType;
      Keys.Add(PlayerPawn);
      
      //某一个动作是否完成
      FBlackboardEntry ProcessFinish;
      ProcessFinish.EntryName = FName(TEXT("ProcessFinish"));
      ProcessFinish.KeyType = NewObject<UBlackboardKeyType_Bool>();
      Keys.Add(ProcessFinish);
      
  • UBTTaskNode

    • 可重写函数

      // 重写执行函数
      virtual EBTNodeResult::Type ExecuteTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory) override;
      //重写终止函数
      virtual EBTNodeResult::Type AbortTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory) override;
      
      // 设置要关联的黑板数据
      UPROPERTY(EditAnywhere,Category="Blackboard")
      		struct FBlackboardKeySelector WaitTime;
      UPROPERTY(EditAnywhere,Category="Blackboard")
      		struct FBlackboardKeySelector Destination;
      UPROPERTY(EditAnywhere,Category="Blackboard")
      		struct FBlackboardKeySelector IsActionFinish;
      
    • ExecuteTask

      • 可通过参数 OwnerComp获取 character 和 controller,进而访问相关函数或数据
      • 可更改黑板数据
      SEController = Cast<AEnemyController>(OwnerComp.GetAIOwner());
      SECharacter = Cast<AEnemyCharacter>(SEController->GetPawn());
      
      // 使用导航系统获取随机点
      UNavigationSystemV1::K2_GetRandomReachablePointInRadius(SEController, WanderOrigin,DesLoc, WanderRadius);
      OwnerComp.GetBlackboardComponent()->SetValueAsVector(Destination.SelectedKeyName, DesLoc);
      
      // 播放动画,返回时长
      float AttackDuration = SECharacter->PlayAttackAction(EEnemyAttackType::EA_Normal);
      OwnerComp.GetBlackboardComponent()->SetValueAsFloat(WaitTime.SelectedKeyName, AttackDuration);
      
    • AbortTask

      • 一般用于收尾工作,比如清除定时器
    • 返回值 EBTNodeResult

      • 根据返回值,让行为树继续执行子节点或者跳出返回父节点
      // 返回值
      return EBTNodeResult::Failed;
      return EBTNodeResult::Succeeded;
      return EBTNodeResult::Aborted;
      
posted @ 2021-12-02 17:13  砥才人  阅读(1514)  评论(0编辑  收藏  举报