Hey everyone,
I’m trying to make a simple custom animation node that will return me the Vector position of a bone. I’m currently trying to add the output pin and I can’t find how to do it. I saw on a thread that I should do something similar to this (from this thread):
void UCustomGraphNodeClass::CreateOutputPins()
{
const UAnimationGraphSchema* Schema = GetDefault<UAnimationGraphSchema>();
CreatePin(EGPD_Output, Schema->PC_Struct, Text("Pose", FPoseLink::StaticStruct(), /*bIsArray=*/ false, /*bIsReference=*/ false, TEXT("Pose"));
}
The problem is that there is not StaticStruct() function in FVector. I’m pretty lost here.
A few other questions:
- After I manage to add the output pin to the AnimGraphNode, how do I use it in the AnimNode?
- What does CopyPinDefaultsToNodeData and CopyNodeDataToPreviewNode do? When are they called? How does GET_MEMBER_NAME_STRING_CHECKED and GetDefaultValue work?
I don’t think it’s really relevant, but here is my code in case anyone wants to see it.
[SPOILER]
AnimGraphNode_GetBoneLocation.h
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "AnimGraphNode_Base.h"
#include "AnimNode_GetBoneLocation.h"
#include "AnimGraphNode_GetBoneLocation.generated.h"
/**
*
*/
UCLASS()
class SHOOTERGAME_API UAnimGraphNode_GetBoneLocation : public UAnimGraphNode_Base
{
GENERATED_BODY()
UPROPERTY(EditAnywhere, Category = Settings)
FAnimNode_GetBoneLocation Node;
public:
UAnimGraphNode_GetBoneLocation(const FObjectInitializer& ObjectInitializer);
// UEdGraphNode interface
virtual FText GetNodeTitle(ENodeTitleType::Type TitleType) const override;
virtual FText GetTooltipText() const override;
// End of UEdGraphNode interface
protected:
// UAnimGraphNode_Base interface
virtual void ValidateAnimNodeDuringCompilation(USkeleton* ForSkeleton, FCompilerResultsLog& MessageLog) override;
virtual FEditorModeID GetEditorMode() const override;
virtual void CopyNodeDataToPreviewNode(FAnimNode_Base* InPreviewNode) override;
virtual void CopyPinDefaultsToNodeData(UEdGraphPin* InPin) override;
// End of UAnimGraphNode_Base interface
private:
virtual void CreateOutputPins() override;
};
AnimGraphNode_GetBoneLocation.cpp
// Fill out your copyright notice in the Description page of Project Settings.
#include "AnimGraphNode_GetBoneLocation.h"
#include "AnimNodeEditModes.h"
#include "Kismet2/CompilerResultsLog.h"
#include "EdGraph/EdGraphNodeUtils.h"
#include "UObject/ObjectMacros.h"
#include "UnrealWidget.h"
#include "Classes/AnimationGraphSchema.h"
#define LOCTEXT_NAMESPACE "CustomAnimNodes"
UAnimGraphNode_GetBoneLocation::UAnimGraphNode_GetBoneLocation(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
}
FText UAnimGraphNode_GetBoneLocation::GetNodeTitle(ENodeTitleType::Type TitleType) const
{
if (TitleType == ENodeTitleType::MenuTitle && Node.Bone.BoneName != NAME_None)
{
FFormatNamedArguments args = FFormatNamedArguments();
args.Add(TEXT("BoneName"), FText::FromName(Node.Bone.BoneName));
return FText::Format(LOCTEXT("AnimGraphNode_GetBoneLocation_MenuTitle", "Get Bone Location ({BoneName})"), args);
}
else
{
return LOCTEXT("AnimGraphNode_GetBoneLocation_ListTitle", "Get Bone Location");
}
}
FText UAnimGraphNode_GetBoneLocation::GetTooltipText() const
{
return FText::FromString(TEXT("Get the location of a bone."));
}
void UAnimGraphNode_GetBoneLocation::ValidateAnimNodeDuringCompilation(USkeleton* ForSkeleton, FCompilerResultsLog& MessageLog)
{
if (Node.Bone.BoneName == NAME_None)
{
MessageLog.Warning(*LOCTEXT("AnimGraphNode_GetBoneLocation_NoBoneSelectedWarning", "@@ - No bone selected. Please select a bone to get its location.").ToString(), this);
}
}
FEditorModeID UAnimGraphNode_GetBoneLocation::GetEditorMode() const
{
return AnimNodeEditModes::ObserveBone;
}
void UAnimGraphNode_GetBoneLocation::CopyNodeDataToPreviewNode(FAnimNode_Base* InPreviewNode)
{
FAnimNode_GetBoneLocation* inNode = static_cast<FAnimNode_GetBoneLocation*>(InPreviewNode);
inNode->Bone = Node.Bone;
}
void UAnimGraphNode_GetBoneLocation::CopyPinDefaultsToNodeData(UEdGraphPin* InPin)
{
/*
if (InPin->GetName() == GET_MEMBER_NAME_STRING_CHECKED(FAnimNode_GetBoneLocation, Bone))
{
GetDefaultValue(GET_MEMBER_NAME_STRING_CHECKED(FAnimNode_GetBoneLocation, Bone), Node.Bone);
}
*/
}
void UAnimGraphNode_GetBoneLocation::CreateOutputPins()
{
const UAnimationGraphSchema* Schema = GetDefault<UAnimationGraphSchema>();
FCreatePinParams pinParams = FCreatePinParams();
pinParams.bIsConst = false;
pinParams.bIsReference = false;
//What do I do here?
CreatePin(EGPD_Output, Schema->PC_Struct, TEXT("Bone Location"), pinParams);
}
#undef LOCTEXT_NAMESPACE
AnimNode_GetBoneLocation.h
#pragma once
#include "Core.h"
#include "Engine.h"
#include "Engine/Classes/Animation/AnimNodeBase.h"
#include "AnimNode_GetBoneLocation.generated.h"
USTRUCT(BlueprintInternalUseOnly)
struct SHOOTERGAME_API FAnimNode_GetBoneLocation : public FAnimNode_Base
{
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Links)
FPoseLink LocalPose;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = InputPins)
FVector Location;
UPROPERTY(EditAnywhere, Category = Settings, meta = (PinHiddenByDefault))
FBoneReference Bone;
// FAnimNode_Base interface
virtual void Initialize_AnyThread(const FAnimationInitializeContext& Context) override;
virtual void Update_AnyThread(const FAnimationUpdateContext& Context) override;
virtual void Evaluate_AnyThread(FPoseContext& Output) override;
// End of FAnimNode_Base interface
};
AnimNode_GetBoneLocation.cpp
#include "AnimNode_GetBoneLocation.h"
void FAnimNode_GetBoneLocation::Initialize_AnyThread(const FAnimationInitializeContext& Context)
{
}
void FAnimNode_GetBoneLocation::Update_AnyThread(const FAnimationUpdateContext& Context)
{
}
void FAnimNode_GetBoneLocation::Evaluate_AnyThread(FPoseContext& Output)
{
}
[/SPOILER]
If anyone has any other relevant information or tips on this I’d greatly appreciate it. I’m slowly trying to get this to work, but I haven’t wrapped my head around this quite yet.