前言 本文记录一下蓝图泛型节点的实现, 主要分为CustomThunk
方式和K2Node
的方式
对比一下两者的优点
CustomThunk: 代码少, 调试方便
UK2Node: 动态的节点数量, 更灵活的动态类型
本文代码在如下项目中
BlueprintLibraryUtility
CustomThunk 此函数分为3部分
带有UFUNCTION
宏的函数声明;
自定义Thunk
函数体DECLARE_FUNCTION(execFunctionName)
;
真正执行泛型逻辑的Generic_FunctionName()
泛型函数。
函数声明
需要加入字段CustomThunk
meta数据内指定哪些参数为泛型类型,如普通便变量的meta = (CustomStructureParam = "Value1,Value2,Value")
特殊情况
用CustomStructureParam = "变量1,变量2"
的方式
只能用符号","
meta = (ArrayParm = "Array1,Array2,Array3", ArrayTypeDependentParams = "Array1,Array2,Array3")
ArrayTypeDependentParams
表示多个类型的相互依赖, 参考引擎文件KismetArrayLibrary.h
meta = (MapParam = "TargetMap", MapKeyParam = "Key", MapValueParam = "Value")
Map只能指定一个TMap
类型的泛型类型,多个泛型无法正常工作
meta = (SetParam = "Set1|Set2,Set3")
TSet
比较特殊, 用","
分隔多个泛型, 用"|"
表示类型依赖
实现 用DECLARE_FUNCTION
来手动定义函数实现(取代的*.\Intermediate\Build\Win64\UE4Editor\Inc**.gen.cpp内的代码), 一般需要声明前缀为Generic
的同名函数(参数可以不同)
如我们实现一个结构体转Json
的函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 UFUNCTION (BlueprintPure, CustomThunk, meta = (CustomStructureParam = "StructReference" , DisplayName = "Struct to JSON String" ), Category = "File|Json" ) static void UStructToJsonObjectString (const int32& StructReference, FString& JSONString) ; static void GenericUStructToJsonObjectString (const UStruct* StructDefinition, const void * Struct, FString& OutJsonString, int64 CheckFlags, int64 SkipFlags) ;DECLARE_FUNCTION (execUStructToJsonObjectString){ Stack.StepCompiledIn<FStructProperty>(NULL ); FStructProperty* StructProperty = CastField<FStructProperty>(Stack.MostRecentProperty); void * StructPtr = Stack.MostRecentPropertyAddress; P_GET_PROPERTY_REF (FStrProperty, JSONString); P_FINISH; P_NATIVE_BEGIN; GenericUStructToJsonObjectString (StructProperty->Struct,StructPtr,JSONString,0 ,0 ); P_NATIVE_END; }
在P_FINISH;
之前是获取属性
获取属性的先后次序应与函数声明时变量在参数列表中出现的次序保持一致
P_NATIVE_BEGIN;
与P_NATIVE_END;
之间是定义函数的实现
获取属性的方式
1 2 3 Stack.StepCompiledIn<UStructProperty>(NULL ); void * SrcPropertyAddr = Stack.MostRecentPropertyAddress;UProperty* SrcProperty = Cast<UProperty>(Stack.MostRecentProperty);
1 2 3 Stack.StepCompiledIn<UArrayProperty>(NULL ); void * SrcArrayAddr = Stack.MostRecentPropertyAddress;UArrayProperty* SrcArrayProperty = Cast<UArrayProperty>(Stack.MostRecentProperty);
1 2 3 4 Stack.MostRecentProperty = nullptr ; Stack.StepCompiledIn<UMapProperty>(NULL ); void * SrcMapAddr = Stack.MostRecentPropertyAddress;UMapProperty* SrcMapProperty = Cast<UMapProperty>(Stack.MostRecentProperty);
1 2 3 4 Stack.MostRecentProperty = nullptr ; Stack.StepCompiledIn<USetProperty>(NULL ); void * SetAddr = Stack.MostRecentPropertyAddress;USetProperty* SetProperty = Cast<USetProperty>(Stack.MostRecentProperty);
K2Node 继承于UK2Node
一般会重写如下几个函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 virtual FText GetTooltipText () const override ;virtual FText GetNodeTitle (ENodeTitleType::Type TitleType) const override ;virtual void GetMenuActions (FBlueprintActionDatabaseRegistrar& ActionRegister) const override ;virtual FText GetMenuCategory () const ;virtual void ExpandNode (FKismetCompilerContext& CompilerContext, UEdGraph* SourceGraph) override ;virtual void AllocateDefaultPins () override ;virtual void PinDefaultValueChanged (UEdGraphPin* ChangedPin) override ;virtual void NotifyPinConnectionListChanged (UEdGraphPin* Pin) override ;
还有一些特殊情况会需要重写的函数, 比如
1 2 3 4 5 6 virtual TSharedPtr<SGraphNode> CreateVisualWidget () { return TSharedPtr<SGraphNode>(); } virtual TSharedPtr<SWidget> CreateNodeImage () const { return TSharedPtr<SWidget>(); } virtual void GetNodeContextMenuActions (class UToolMenu* Menu, class UGraphNodeContextMenuContext* Context) const override ;
更多请参考 EdGraphNode.h
和K2Node.h
下面我们创建几个K2Node
K2Node_Print
由于平时用蓝图的PrintString
打印字符串经常需要输入Append
,不方便, 那么我们就借此尝试做一个K2Node
版本的可以动态添加引脚的Print
直接上代码,重点加注释
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 #pragma once #include "CoreMinimal.h" #include "K2Node.h" #include "K2Node_CallFunction.h" #include "KismetCompiler.h" #include "BlueprintActionDatabaseRegistrar.h" #include "BlueprintNodeSpawner.h" #include "Kismet2/BlueprintEditorUtils.h" #include "K2Node_Print.generated.h" UCLASS ()class BLUEPRINTLIBRARYUTILITYEDITOR_API UK2Node_Print : public UK2Node{ GENERATED_BODY () public : virtual FText GetTooltipText () const override { return FText::FromString ("Printf" ); } virtual FText GetNodeTitle (ENodeTitleType::Type TitleType) const override { return FText::FromString (TEXT ("Printf" )); } virtual void GetMenuActions (FBlueprintActionDatabaseRegistrar& ActionRegister) const override { UClass* ActionKey = GetClass (); if (ActionRegister.IsOpenForRegistration (ActionKey)) { UBlueprintNodeSpawner* NodeSpawner = UBlueprintNodeSpawner::Create (GetClass ()); check (NodeSpawner); ActionRegister.AddBlueprintAction (ActionKey, NodeSpawner); } } virtual void GetNodeContextMenuActions (class UToolMenu* Menu, class UGraphNodeContextMenuContext* Context) const override ; virtual FText GetMenuCategory () const { return FText::FromString (TEXT ("BlueprintLibraryUtility|IO" )); } UEdGraphPin* GetThenPin () const { UEdGraphPin* Pin = FindPin (UEdGraphSchema_K2::PN_Then); check (Pin == nullptr || Pin->Direction == EGPD_Output); return Pin; } virtual void ExpandNode (FKismetCompilerContext& CompilerContext, UEdGraph* SourceGraph) override ; virtual void AllocateDefaultPins () override ; virtual void PinDefaultValueChanged (UEdGraphPin* ChangedPin) override ; void AddPinToNode () ; void RemoveInputPin (UEdGraphPin* Pin) ; UFUNCTION (BlueprintCallable, meta = ( CallableWithoutWorldContext = true , WorldContext = "context" )) virtual TSharedPtr<SGraphNode> CreateVisualWidget () override ; private : UPROPERTY () TArray<FName> ArgPinNames; static FName PN_PrintToSreen; static FName PN_PrintToLog; static FName PN_Color; static FName PN_Duration; };
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 #include "Node/K2Node_Print.h" #include "Kismet/KismetStringLibrary.h" #include "Kismet/KismetSystemLibrary.h" #include "K2Node_MakeArray.h" #include "Node/GraphNode_Printf.h" #include "ToolMenu.h" #include "ToolMenuSection.h" #define LOCTEXT_NAMESPACE "K2Node_Print" FName UK2Node_Print::PN_Color = TEXT ("Color" ); FName UK2Node_Print::PN_PrintToLog = TEXT ("PrintToLog" ); FName UK2Node_Print::PN_PrintToSreen = TEXT ("PrintToScreen" ); FName UK2Node_Print::PN_Duration = TEXT ("Duration" ); void UK2Node_Print::GetNodeContextMenuActions (class UToolMenu* Menu, class UGraphNodeContextMenuContext* Context) const { Super::GetNodeContextMenuActions (Menu,Context); if (!Context->bIsDebugging) { if (Context->Pin != FindPin (UK2Node_Print::PN_PrintToSreen) && Context->Pin != FindPin (UK2Node_Print::PN_Color) && Context->Pin != FindPin (UK2Node_Print::PN_PrintToLog) && Context->Pin != FindPin (UK2Node_Print::PN_Duration)) { FToolMenuSection& Section = Menu->AddSection (FName (TEXT ("UK2Node_Print" )), LOCTEXT ("UK2Node_Print" ,"Action" )); Section.AddMenuEntry ( "RemovePin" , LOCTEXT ("RemovePin" , "Remove pin" ), LOCTEXT ("RemovePinTooltip" , "Remove this input pin" ), FSlateIcon (), FUIAction ( FExecuteAction::CreateUObject (const_cast <UK2Node_Print*>(this ), &UK2Node_Print::RemoveInputPin, const_cast <UEdGraphPin*>(Context->Pin)) ) ); } } } void UK2Node_Print::ExpandNode (FKismetCompilerContext& CompilerContext, UEdGraph* SourceGraph) { UEdGraphPin* ExecPin = GetExecPin (); UEdGraphPin* ThenPin = GetThenPin (); if (ExecPin && ThenPin) { UFunction* Function = UFlib_IO::StaticClass ()->FindFunctionByName (FName ("PrintArray" )); if (Function == NULL ) { CompilerContext.MessageLog.Error (*LOCTEXT ("InvalidFunctionName" , "BaseAsyncTask: Type not supported or not initialized. @@" ).ToString (), this ); return ; } UK2Node_CallFunction* CallFuncNode = CompilerContext.SpawnIntermediateNode<UK2Node_CallFunction>(this , SourceGraph); CallFuncNode->SetFromFunction (Function); CallFuncNode->AllocateDefaultPins (); CompilerContext.MovePinLinksToIntermediate (*ExecPin, *(CallFuncNode->GetExecPin ())); CompilerContext.MovePinLinksToIntermediate (*ThenPin, *(CallFuncNode->GetThenPin ())); CompilerContext.MovePinLinksToIntermediate (*FindPin (UK2Node_Print::PN_PrintToSreen), *CallFuncNode->FindPin (TEXT ("bScreen" ))); CompilerContext.MovePinLinksToIntermediate (*FindPin (UK2Node_Print::PN_PrintToLog), *CallFuncNode->FindPin (TEXT ("bLog" ))); CompilerContext.MovePinLinksToIntermediate (*FindPin (UK2Node_Print::PN_Color), *CallFuncNode->FindPin (TEXT ("Color" ))); CompilerContext.MovePinLinksToIntermediate (*FindPin (UK2Node_Print::PN_Duration), *CallFuncNode->FindPin (TEXT ("Duration" ))); UK2Node_MakeArray* MakeArrayNode = CompilerContext.SpawnIntermediateNode<UK2Node_MakeArray>(this , SourceGraph); MakeArrayNode->AllocateDefaultPins (); UEdGraphPin* ArrayOut = MakeArrayNode->GetOutputPin (); UEdGraphPin* FuncArgPin = CallFuncNode->FindPinChecked (TEXT ("InStrings" )); ArrayOut->MakeLinkTo (FuncArgPin); MakeArrayNode->PinConnectionListChanged (ArrayOut); for (int32 i = 0 ; i < ArgPinNames.Num (); i++) { if (i > 0 ) MakeArrayNode->AddInputPin (); const FString PinName = FString::Printf (TEXT ("[%d]" ), i); UEdGraphPin* ArrayInputPin = MakeArrayNode->FindPinChecked (PinName); UEdGraphPin* MyInputPin = FindPinChecked (ArgPinNames[i], EGPD_Input); CompilerContext.MovePinLinksToIntermediate (*MyInputPin, *ArrayInputPin); } } BreakAllNodeLinks (); } void UK2Node_Print::AllocateDefaultPins () { Super::AllocateDefaultPins (); CreatePin (EGPD_Input, UEdGraphSchema_K2::PC_Exec, UEdGraphSchema_K2::PN_Execute); CreatePin (EGPD_Output, UEdGraphSchema_K2::PC_Exec, UEdGraphSchema_K2::PN_Then); UEdGraphPin* PinScreen = CreatePin (EGPD_Input, UEdGraphSchema_K2::PC_Boolean, UK2Node_Print::PN_PrintToSreen); PinScreen->DefaultValue = "True" ; UEdGraphPin* PinLog = CreatePin (EGPD_Input, UEdGraphSchema_K2::PC_Boolean, UK2Node_Print::PN_PrintToLog); PinLog->DefaultValue = "True" ; UScriptStruct* ColorStruct = TBaseStructure<FLinearColor>::Get (); UEdGraphPin* PinColor = CreatePin (EGPD_Input, UEdGraphSchema_K2::PC_Struct, ColorStruct, UK2Node_Print::PN_Color); FLinearColor color = FLinearColor::Green; PinColor->DefaultValue = color.ToString (); UEdGraphPin* PinDuration = CreatePin (EGPD_Input, UEdGraphSchema_K2::PC_Float, UK2Node_Print::PN_Duration); PinDuration->DefaultValue = "2.0" ; for (const FName& PinName : ArgPinNames) { CreatePin (EGPD_Input, UEdGraphSchema_K2::PC_String, PinName); } } void UK2Node_Print::PinDefaultValueChanged (UEdGraphPin* ChangedPin) { Super::PinDefaultValueChanged (ChangedPin); } void UK2Node_Print::AddPinToNode () { Modify (); TMap<FString, FStringFormatArg> FormatArgs = { {TEXT ("Count" ), ArgPinNames.Num ()} }; FName NewPinName (*FString::Format(TEXT("{Count}" ), FormatArgs)) ; ArgPinNames.Add (NewPinName); CreatePin (EGPD_Input, UEdGraphSchema_K2::PC_String, NewPinName); } void UK2Node_Print::RemoveInputPin (UEdGraphPin* Pin) { FScopedTransaction Transaction (FText::FromString("Printf_RemoveInputPin" )) ; Modify (); ArgPinNames.Remove (Pin->GetFName ()); RemovePin (Pin); FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified (GetBlueprint ()); } TSharedPtr<SGraphNode> UK2Node_Print::CreateVisualWidget () { return SNew (SGraphNode_Printf, this ); } #undef LOCTEXT_NAMESPACE
1 2 3 4 5 6 7 8 void UFlib_IO::PrintArray (UObject* context, const TArray<FString>& InStrings, bool bScreen, bool bLog, FLinearColor Color, float Duration) { FString OutString (TEXT("" )) ; for (const auto & Word : InStrings) OutString += Word; UKismetSystemLibrary::PrintString (context,OutString,bScreen,bLog,Color,Duration); }
辅助类 我们还需要一个继承于SGraphNodeK2Base
的辅助类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 #pragma once #include "CoreMinimal.h" #include "KismetNodes/SGraphNodeK2Base.h" class UK2Node_Print ;class SVerticalBox ;class BLUEPRINTLIBRARYUTILITYEDITOR_API SGraphNode_Printf : public SGraphNodeK2Base{ public : SLATE_BEGIN_ARGS (SGraphNode_Printf) {} SLATE_END_ARGS () void Construct (const FArguments& InArgs, UEdGraphNode* InNode) ; protected : virtual void CreateInputSideAddButton (TSharedPtr<SVerticalBox> InputBox) override ; virtual FReply OnAddPin () override ; };
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 #include "Node/GraphNode_Printf.h" #include "GraphEditorSettings.h" #include "SGraphNode.h" #include "Node/K2Node_Print.h" void SGraphNode_Printf::Construct (const FArguments& InArgs, UEdGraphNode* InNode) { this ->GraphNode = InNode; this ->SetCursor (EMouseCursor::CardinalCross); this ->UpdateGraphNode (); } void SGraphNode_Printf::CreateInputSideAddButton (TSharedPtr<SVerticalBox> InputBox) { FText AddPinName = FText::FromString (TEXT ("Add Pin" )); FText RemovePinName = FText::FromString (TEXT ("Remove Pin" )); TSharedRef<SWidget> AddPinButton = AddPinButtonContent (AddPinName, AddPinName); TSharedRef<SWidget> RemovePinButton = AddPinButtonContent (RemovePinName, RemovePinName); FMargin AddPinPadding = Settings->GetInputPinPadding (); AddPinPadding.Top += 6.0f ; InputBox->AddSlot () .AutoHeight () .VAlign (VAlign_Center) .Padding (AddPinPadding) [ AddPinButton ]; } FReply SGraphNode_Printf::OnAddPin () { UK2Node_Print* BPNode = CastChecked<UK2Node_Print>(GraphNode); const FScopedTransaction Transaction (NSLOCTEXT("Kismet" , "AddArgumentPin" , "Add Argument Pin" )) ; BPNode->Modify (); BPNode->AddPinToNode (); FBlueprintEditorUtils::MarkBlueprintAsModified (BPNode->GetBlueprint ()); UpdateGraphNode (); GraphNode->GetGraph ()->NotifyGraphChanged (); return FReply::Handled (); }
K2Node_GetMatProperty
这个是基于assimp
开源库制作的从外部文件获取模型材质球的节点, 关于assimp
库的内容参考 开源图形库Assimp
此节点特殊点有几个
输入参数根据枚举的变化, 会动态增加/删除输入引脚
返回参数类型是动态的,根据输入枚举
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 void UK2Node_GetMatProperty::ExpandNode (FKismetCompilerContext& CompilerContext, UEdGraph* SourceGraph) { Super::ExpandNode (CompilerContext, SourceGraph); UEdGraphPin* ExecPin = GetExecPin (); UEdGraphPin* ThenPin = GetThenPin (); if (ExecPin && ThenPin) { UFunction* Function = UFlib_IO::StaticClass ()->FindFunctionByName (FunctionName); if (Function == NULL ) { CompilerContext.MessageLog.Error (*LOCTEXT ("InvalidFunctionName" , "BaseAsyncTask: Type not supported or not initialized. @@" ).ToString (), this ); return ; } UK2Node_CallFunction* CallFuncNode = CompilerContext.SpawnIntermediateNode<UK2Node_CallFunction>(this , SourceGraph); CallFuncNode->SetFromFunction (Function); CallFuncNode->AllocateDefaultPins (); CompilerContext.MovePinLinksToIntermediate (*ExecPin, *(CallFuncNode->GetExecPin ())); CompilerContext.MovePinLinksToIntermediate (*ThenPin, *(CallFuncNode->GetThenPin ())); CompilerContext.MovePinLinksToIntermediate (*FindPin (UK2Node_GetMatProperty::PinName_File), *(CallFuncNode->FindPin (UK2Node_GetMatProperty::PinName_File))); CompilerContext.MovePinLinksToIntermediate (*FindPin (UK2Node_GetMatProperty::PinName_Key), *(CallFuncNode->FindPin (UK2Node_GetMatProperty::PinName_Key))); CompilerContext.MovePinLinksToIntermediate (*FindPin (UK2Node_GetMatProperty::PinName_Return), *(CallFuncNode->FindPin (UK2Node_GetMatProperty::PinName_Return))); UEdGraphPin* tPin = FindPin (UK2Node_GetMatProperty::PinName_T); if (tPin && !tPin->bHidden) { CompilerContext.MovePinLinksToIntermediate (*FindPin (UK2Node_GetMatProperty::PinName_T), *(CallFuncNode->FindPin (UK2Node_GetMatProperty::PinName_T))); } UEdGraphPin* nPin = FindPin (UK2Node_GetMatProperty::PinName_N); if (nPin && !nPin->bHidden) { CompilerContext.MovePinLinksToIntermediate (*FindPin (UK2Node_GetMatProperty::PinName_N), *(CallFuncNode->FindPin (UK2Node_GetMatProperty::PinName_N))); } } BreakAllNodeLinks (); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 void UK2Node_GetMatProperty::RefreshExtraPin (EMatPropertyKeyType key) { bool bHasExtraPin = key == EMatPropertyKeyType::TEXTURE || key == EMatPropertyKeyType::TEXBLEND || key == EMatPropertyKeyType::TEXOP || key == EMatPropertyKeyType::MAPPING || key == EMatPropertyKeyType::UVWSRC || key == EMatPropertyKeyType::MAPPINGMODE_U || key == EMatPropertyKeyType::MAPPINGMODE_V || key == EMatPropertyKeyType::TEXMAP_AXIS || key == EMatPropertyKeyType::TEXFLAGS; UEdGraphPin* typePin = FindPin (UK2Node_GetMatProperty::PinName_T); UEdGraphPin* nPin = FindPin (UK2Node_GetMatProperty::PinName_N); if (typePin) { typePin->bHidden = !bHasExtraPin; if (!bHasExtraPin) { typePin->BreakAllPinLinks (); } } if (nPin) { nPin->bHidden = !bHasExtraPin; if (!bHasExtraPin) { nPin->BreakAllPinLinks (); } } }
上面函数根据枚举类型来选择是否隐藏/显示对应的Pin
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 void UK2Node_GetMatProperty::ExpandNode (FKismetCompilerContext& CompilerContext, UEdGraph* SourceGraph) { ................... UFunction* Function = UFlib_IO::StaticClass ()->FindFunctionByName (FunctionName); ................... } void UK2Node_GetMatProperty::RefreshReturnPin (EReturnType newType) { UEdGraph* Graph = GetGraph (); if (Graph) { UEdGraphPin* oldRetPin = FindPin (UK2Node_GetMatProperty::PinName_Return); if (oldRetPin) { RemovePin (oldRetPin); Graph->NotifyGraphChanged (); } Graph->NotifyGraphChanged (); } switch (newType) { case EReturnType::Color: { FunctionName = GetFunctionName (EReturnType::Color); CreatePin (EGPD_Output, UEdGraphSchema_K2::PC_Struct, ColorStruct, UK2Node_GetMatProperty::PinName_Return); break ; } case EReturnType::Vector: { FunctionName = GetFunctionName (EReturnType::Vector); CreatePin (EGPD_Output, UEdGraphSchema_K2::PC_Struct, VectorStruct, UK2Node_GetMatProperty::PinName_Return); break ; } case EReturnType::Int: { FunctionName = GetFunctionName (EReturnType::Int); CreatePin (EGPD_Output, UEdGraphSchema_K2::PC_Int, UK2Node_GetMatProperty::PinName_Return); break ; } case EReturnType::Float: { FunctionName = GetFunctionName (EReturnType::Float); CreatePin (EGPD_Output, UEdGraphSchema_K2::PC_Float, UK2Node_GetMatProperty::PinName_Return); break ; } case EReturnType::String: { FunctionName = GetFunctionName (EReturnType::String); CreatePin (EGPD_Output, UEdGraphSchema_K2::PC_String, UK2Node_GetMatProperty::PinName_Return); break ; } default : FunctionName = GetFunctionName (EReturnType::String); CreatePin (EGPD_Output, UEdGraphSchema_K2::PC_String, UK2Node_GetMatProperty::PinName_Return); break ; } }
根据类型设置不同的FunctionName
然后来获取函数指针
K2Node的泛型
我们顺路在上面节点加入一个泛型的输入变量
1 2 3 4 5 void UK2Node_GetMatProperty::AllocateDefaultPins () { .............. UEdGraphPin* testPin = CreatePin (EGPD_Input, UEdGraphSchema_K2::PC_Wildcard, TEXT ("TEST" )); }
然后重写virtual void PinTypeChanged(UEdGraphPin* Pin) override;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 void UK2Node_GetMatProperty::PinTypeChanged (UEdGraphPin* Pin) { if (Pin->PinName == TEXT ("TEST" )) { UEdGraphPin* testPin = FindPin (TEXT ("TEST" )); if (Pin->LinkedTo.Num ()>0 ) { UEdGraphPin* InstigatorPin = Pin->LinkedTo[0 ]; if (testPin->PinType != InstigatorPin->PinType) { testPin->PinType = InstigatorPin->PinType; } } else { testPin->PinType.PinCategory = UEdGraphSchema_K2::PC_Wildcard; testPin->PinType.PinSubCategory = NAME_None; testPin->PinType.PinSubCategoryObject = nullptr ; } GetGraph ()->NotifyGraphChanged (); UBlueprint* Blueprint = GetBlueprint (); if (!Blueprint->bBeingCompiled) { FBlueprintEditorUtils::MarkBlueprintAsModified (Blueprint); Blueprint->BroadcastChanged (); } } Super::PinTypeChanged (Pin); }
然后在Pin
链接改变以后就调用
1 2 3 4 5 void UK2Node_GetMatProperty::NotifyPinConnectionListChanged (UEdGraphPin* Pin) { Super::NotifyPinConnectionListChanged (Pin); PinTypeChanged (Pin); }