转自:https://forums.unrealengine.com/development-discussion/c-gameplay-programming/104831-creating-and-using-a-blendspace-in-c
creating and using a blendspace in c++
i'm trying to automatize the animation of (a lot of) pawns and would like not to have to define ~100 blendspaces and animblueprint by hand in the editor.
If i can get it to work, i'll just have to create blueprints inheriting from this class and set the skeletal mesh and animations.
This subject seems to pop up every now and then, there are a few post on the answerhub, and even a wiki by Rama, but all of them seem to assume that the BlendSpace is created in the editor.
As you can see, i'm trying several methods (via the skeletal mesh component and the anim instance) to animate the mesh with the blendspace, none of them works so far.
I tried everything i could find related to animation and blendspace in the api documentation.
I can spawn the blueprint, but the mesh remains static so obviously i miss something.
I tried to set this in the blueprint, and i can see the debuging flow correctly going through everything.
I can't check visually the blendspace, so i'm a bit lost and dry now.
Here's the code:
void AYagPawn::BeginPlay() { Super::BeginPlay(); [...] // creating the BS (SMC_00 is a USkeletalMeshComponent) ThisBlendSpace1D = NewObject<UBlendSpace1D>(this, UBlendSpace1D::StaticClass()); ThisBlendSpace1D->SetSkeleton(SMC_00->SkeletalMesh->Skeleton); // setting a parameter for the BS FBlendParameter BP_Speed; BP_Speed.DisplayName = "Speed"; BP_Speed.GridNum = 4; BP_Speed.Min = 0.f; BP_Speed.Max = 100.f; ThisBlendSpace1D->UpdateParameter(0, BP_Speed); // adding two sample (at 0 and 100) // IdleSequence and MoveSequence are UAnimSequence to be set in the BP inheriting this pawn class FBlendSample IdleSample = FBlendSample(IdleSequence, FVector(0.f, 0.f, 0.f), false); FBlendSample MoveSample = FBlendSample(MoveSequence, FVector(100.f, 0.f, 0.f), false); ThisBlendSpace1D->AddSample(IdleSample); ThisBlendSpace1D->AddSample(MoveSample); // first method SMC_00->PlayAnimation(ThisBlendSpace1D, true); // second method SMC_00->SetAnimation(ThisBlendSpace1D); SMC_00->Play(true); // third method SMC_00->OverrideAnimationData(ThisBlendSpace1D, true, true, 0.f, 1.f); // fourth method BS_AnimInstance = Cast<UAnimSingleNodeInstance>(SMC_00->GetAnimInstance()); BS_AnimInstance->SetAnimationAsset(ThisBlendSpace1D); BS_AnimInstance->PlayAnim(true, 1.f, 0.f); } void AYagPawn::Tick( float DeltaSeconds) { Super::Tick(DeltaSeconds); [...] // update BS with Speed (a float) BS_AnimInstance->SetBlendSpaceInput(FVector(Speed, 0.f, 0.f)); // useless in principle but i tried SMC_00->OverrideAnimationData(ThisBlendSpace1D, true, true, 0.f, 1.f); }
And here is the variables section in the BP:
As you can see, the BS is still empty (normal, it will be created in the begin play function at runtime) and both animations have default values.
Any idea ?
Thanks
Cedric
EDIT: i realized i wasn't setting the animation mode, so i added this in the constructor:
SMC_00->SetAnimationMode(EAnimationMode::AnimationSingleNode);
But it still doesn't work.
Answers:
Edit: I should have read your entire question. I'm interested in this so I'm going to help you get the bottom of it! You're probably missing an update call somewhere, or you need to serialize the result to an asset or something. I'll report back.
Here's a compiled simple animation blueprint. It uses a blendspace called "Strafe_IP" and has two variables: Right, Forward. Note that the Character class doesn't appear to call or update the animation - it only sets it initially.
UCLASS(config=Engine, Blueprintable, BlueprintType, meta=(ReplaceConverted="/Game/Blueprints/BPA_Test.BPA_Test_C", OverrideNativeName="BPA_Test_C")) class UBPA_Test : public UAnimInstance { public: GENERATED_BODY() UPROPERTY(meta=(OverrideNativeName="AnimGraphNode_Root_6D3BF226443B80030387A5AADD092A5D")) FAnimNode_Root Root; UPROPERTY(meta=(OverrideNativeName="AnimGraphNode_BlendSpacePlayer_44691A814B28B34EF79F7B8F71402E07")) FAnimNode_BlendSpacePlayer BlendSpacePlayer; UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, meta=(DisplayName="Right", Category="Default", OverrideNativeName="Right")) float Right; UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, meta=(DisplayName="Forward", Category="Default", OverrideNativeName="Forward")) float Forward; UBPA_Test(const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get()); static void __CustomDynamicClassInitialization(UDynamicClass* InDynamicClass); static void __StaticDependencies_CommonAssets(TArray<FBlueprintDependencyData>& AssetsToLoad); };
UBPA_Test::UBPA_Test(const FObjectInitializer& ObjectInitializer) : Super() { if(HasAnyFlags(RF_ClassDefaultObject) && (UBPA_Test::StaticClass() == GetClass())) UBPA_Test::__CustomDynamicClassInitialization(CastChecked<UDynamicClass>(GetClass())); Root.Result.LinkID = 1; BlendSpacePlayer.BlendSpace = CastChecked<UBlendSpaceBase>(CastChecked<UDynamicClass>(UBPA_Test::StaticClass())->UsedAssets[0], ECastCheckedType::NullAllowed); BlendSpacePlayer.EvaluateGraphExposedInputs.CopyRecords = TArray<FExposedValueCopyRecord> (); BlendSpacePlayer.EvaluateGraphExposedInputs.CopyRecords.AddUninitialized(2); FExposedValueCopyRecord::StaticStruct()->InitializeStruct(BlendSpacePlayer.EvaluateGraphExposedInputs.CopyRecords.GetData(), 2); auto& _Right = BlendSpacePlayer.EvaluateGraphExposedInputs.CopyRecords[0]; _Right.SourcePropertyName = FName(TEXT("Right")); _Right.DestProperty = FindFieldChecked<UFloatProperty>(FAnimNode_BlendSpacePlayer::StaticStruct(), TEXT("X")); _Right.Size = 4; auto& _Forward = BlendSpacePlayer.EvaluateGraphExposedInputs.CopyRecords[1]; _Forward.SourcePropertyName = FName(TEXT("Forward")); _Forward.DestProperty = FindFieldChecked<UFloatProperty>(FAnimNode_BlendSpacePlayer::StaticStruct(), TEXT("Y")); _Forward.Size = 4; Right = 0.000000f; Forward = 0.000000f; } void UBPA_Test::__CustomDynamicClassInitialization(UDynamicClass* InDynamicClass) { ensure(0 == InDynamicClass->ReferencedConvertedFields.Num()); ensure(0 == InDynamicClass->MiscConvertedSubobjects.Num()); ensure(0 == InDynamicClass->DynamicBindingObjects.Num()); ensure(0 == InDynamicClass->ComponentTemplates.Num()); ensure(0 == InDynamicClass->Timelines.Num()); ensure(nullptr == InDynamicClass->AnimClassImplementation); InDynamicClass->AssembleReferenceTokenStream(); FConvertedBlueprintsDependencies::FillUsedAssetsInDynamicClass(InDynamicClass, &__StaticDependencies_DirectlyUsedAssets); auto AnimClassData = NewObject<UAnimClassData>(InDynamicClass, TEXT("AnimClassData")); AnimClassData->TargetSkeleton = CastChecked<USkeleton>(CastChecked<UDynamicClass>(UBPA_Test::StaticClass())->UsedAssets[1], ECastCheckedType::NullAllowed); AnimClassData->RootAnimNodeIndex = 1; AnimClassData->RootAnimNodeProperty = InDynamicClass->FindStructPropertyChecked(TEXT("Root")); AnimClassData->AnimNodeProperties = TArray<UStructProperty*> (); AnimClassData->AnimNodeProperties.Reserve(2); AnimClassData->AnimNodeProperties.Add(InDynamicClass->FindStructPropertyChecked(TEXT("Root"))); AnimClassData->AnimNodeProperties.Add(InDynamicClass->FindStructPropertyChecked(TEXT("BlendSpacePlayer"))); InDynamicClass->AnimClassImplementation = AnimClassData; } void UBPA_Test::__StaticDependencies_CommonAssets(TArray<FBlueprintDependencyData>& AssetsToLoad) { const TCHAR* __Local__3 = TEXT("/Game/MovementAnimsetPro/BlendSpaces"); const TCHAR* __Local__4 = TEXT("/Game/Mannequin/Character/Mesh"); FBlueprintDependencyData LocAssets[] = { FBlueprintDependencyData(__Local__3, TEXT("Strafe_IP"), TEXT("Strafe_IP"), TEXT("/Script/Engine"), TEXT("BlendSpace")), FBlueprintDependencyData(__Local__4, TEXT("UE4_Mannequin_Skeleton"), TEXT("UE4_Mannequin_Skeleton"), TEXT("/Script/Engine"), TEXT("Skeleton")), }; for(auto& LocAsset : LocAssets) { AssetsToLoad.Add(LocAsset); } } struct FRegisterHelper__UBPA_Test { FRegisterHelper__UBPA_Test() { FConvertedBlueprintsDependencies::Get().RegisterClass(TEXT("/Game/Blueprints/BPA_Test"), &UBPA_Test::__StaticDependenciesAssets); } static FRegisterHelper__UBPA_Test Instance; }; FRegisterHelper__UBPA_Test FRegisterHelper__UBPA_Test::Instance;
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· .NET周刊【3月第1期 2025-03-02】
· [AI/GPT/综述] AI Agent的设计模式综述
2017-10-25 游戏记录
2017-10-25 2016乐高迷们不能错过的十大乐高模型
2017-10-25 UI相关教程:HUD、UMG和Widget
2017-10-25 [UE4]C++中SpawnActor用法(动态创建Actor)
2017-10-25 [UE4][Canvas]用C++代码绘制血条(HealthBar)
2017-10-25 [UE4]C++代码实现播放粒子特效
2017-10-25 [UE4]C++实现动态加载的问题:LoadClass<T>()和LoadObject<T>() 及 静态加载问题:ConstructorHelpers::FClassFinder()和FObjectFinder()