1.按照前面的教程创建模块,将我们的自定义节点类 这里注意 需要在.build.cs 添加KismetCompiler 模块
PrivateDependencyModuleNames.AddRange(new string[] { "UnrealEd", "KismetCompiler" });
2.定义功能函数 我这里是创建一个object
.h
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "TestItemObject.h"
#include "Kismet/BlueprintFunctionLibrary.h"
#include "MyBlueprintFunctionLibrary.generated.h"
/**
*
*/
UCLASS()
class MYNODE_API UMyBlueprintFunctionLibrary : public UBlueprintFunctionLibrary
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintCallable, Category = Test)
static UTestItemObject* CreateItemObject(TSubclassOf<UTestItemObject> ItemClass);
};
.cpp
// Fill out your copyright notice in the Description page of Project Settings.
#include "MyBlueprintFunctionLibrary.h"
#include "TestItemObject.h"
UTestItemObject* UMyBlueprintFunctionLibrary::CreateItemObject(TSubclassOf<UTestItemObject> ItemClass)
{
return NewObject<UTestItemObject>();
}
3..添加TestNode类 继承自UK2Node_ConstructObjectFromClass
具体的注释在代码里 这里主要需要重载的是AllocateDefaultPins和 ExpandNode函数
AllocateDefaultPins是主要用来创建你自定义的pin口 根据你的功能 可以自定义接口类型。
ExpandNode就是实现功能
主要过程说一下 就是首先 你可以获得你当前node 输入 输入节点对应的pin
然后将对应pin根据需要传递到你需要使用的函数
比如这里我的函数CreateItemObject 需要ItemClass这个参数,那么我就需要将node中的class pin口的值传递到函数绑定的node几点中
//连接class pin
UEdGraphPin* CallCreateClass = CallCreateNode->FindPin(TEXT("ItemClass"));
if (SpawnClassPin->LinkedTo.Num() > 0)
{
//如果node有链接
CompilerContext.MovePinLinksToIntermediate(*SpawnClassPin, *CallCreateClass);
}
else
{
//没有指定链接 使用默认class
CallCreateClass->DefaultObject = SpawnClass;
}
具体代码看下面
.h
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "K2Node_ConstructObjectFromClass.h"
#include "TestNode.generated.h"
/**
*
*/
UCLASS()
class MYNODE_API UTestNode : public UK2Node_ConstructObjectFromClass
{
GENERATED_BODY()
UTestNode();
virtual void AllocateDefaultPins() override;
virtual FLinearColor GetNodeTitleColor() const override;
virtual FText GetMenuCategory() const override;
UEdGraphPin* GetOwningPlayerPin() const;
virtual void ExpandNode(class FKismetCompilerContext& CompilerContext, UEdGraph* SourceGraph) override;
void BreakAllNodeLinks();
protected:
virtual FText GetBaseNodeTitle() const override;
virtual FText GetNodeTitleFormat() const override;
virtual UClass* GetClassPinBaseClass() const override;
};
// Fill out your copyright notice in the Description page of Project Settings.
#include "TestNode.h"
#include "GameFramework/PlayerController.h"
#include "TestItemObject.h"
#include "MyBlueprintFunctionLibrary.h"
#include "KismetCompiler.h"
#include "K2Node_CallFunction.h"
#define LOCTEXT_NAMESPACE "TestNode"
struct FBPNode_CreateItemDataHepler
{
static FString OwningPlayerPinName;
};
FString FBPNode_CreateItemDataHepler::OwningPlayerPinName(TEXT("PinName"));
UTestNode::UTestNode()
{
int a = 2;
}
void UTestNode::AllocateDefaultPins()
{
Super::AllocateDefaultPins();
//创建一个Pin 口 类型是playercontroller Object类型
UEdGraphPin* OwningPlayerPin = CreatePin(EGPD_Input, UEdGraphSchema_K2::PC_Object, TEXT(""), APlayerController::StaticClass(), false, false,
FBPNode_CreateItemDataHepler::OwningPlayerPinName);
SetPinToolTip(*OwningPlayerPin, LOCTEXT("PlayerPinDes", "PinToolTip"));
}
//修改标题颜色
FLinearColor UTestNode::GetNodeTitleColor() const
{
return FLinearColor(1.0, 0.f, 0.f, 1.0f);
}
FText UTestNode::GetMenuCategory() const
{
return FText::FromString("TestNode Menu");
}
UEdGraphPin* UTestNode::GetOwningPlayerPin() const
{
UEdGraphPin* Pin = FindPin(FBPNode_CreateItemDataHepler::OwningPlayerPinName);
check(Pin == NULL || Pin->Direction == EGPD_Input);
return Pin;
}
//具体实现功能函数 重现创建一个新的node 并将原node先关连接转移到新node上
void UTestNode::ExpandNode(FKismetCompilerContext& CompilerContext, UEdGraph* SourceGraph)
{
Super::ExpandNode(CompilerContext, SourceGraph);
static FName Create_FunctionName = GET_FUNCTION_NAME_CHECKED(UMyBlueprintFunctionLibrary, CreateItemObject); //返回函数的名称
//获得原node 各个pin指针 后续如有需要进行连接
UEdGraphPin* SpawnNodeExec = this->GetExecPin();
UEdGraphPin* SpawnWorldContextPin = this->GetWorldContextPin();
UEdGraphPin* SpawnOwningPlayerPin = this->GetOwningPlayerPin();
UEdGraphPin* SpawnClassPin = this->GetClassPin();
UEdGraphPin* SpawnNodeThen = this->GetThenPin();
UEdGraphPin* SpawnNodeResult = this->GetResultPin();
//检测节点的class是否为空 并且没有连接
UClass* SpawnClass = (SpawnClassPin != NULL) ? Cast<UClass>(SpawnClassPin->DefaultObject) : NULL;
if ((0 == SpawnClassPin->LinkedTo.Num()) && (NULL == SpawnClass))
{
CompilerContext.MessageLog.Error(*LOCTEXT("CreateItemDAtaNodeMissingClass_Error", "Spawn node @@ must have a class specified.").ToString(), this);
// we break exec links so this is the only error we get, don't want the CreateItemData node being considered and giving 'unexpected node' type warnings
BreakAllNodeLinks();
return;
}
//执行创建步骤
//创建执行函数
UK2Node_CallFunction* CallCreateNode = CompilerContext.SpawnIntermediateNode<UK2Node_CallFunction>(this, SourceGraph);
CallCreateNode->FunctionReference.SetExternalMember(Create_FunctionName, UMyBlueprintFunctionLibrary::StaticClass());
CallCreateNode->AllocateDefaultPins();
//连接exe pin
UEdGraphPin* CallCreateExec = CallCreateNode->GetExecPin();
CompilerContext.MovePinLinksToIntermediate(*SpawnNodeExec, *CallCreateExec);
//根据你的函数参数名称 传入指定的pin 这里我的CreateItemObject函数只有ItemClass一个参数 所以我只需要将原node的class传入到CreateClassPin节点
//连接class pin
UEdGraphPin* CallCreateClass = CallCreateNode->FindPin(TEXT("ItemClass"));
if (SpawnClassPin->LinkedTo.Num() > 0)
{
//如果node有链接
CompilerContext.MovePinLinksToIntermediate(*SpawnClassPin, *CallCreateClass);
}
else
{
//没有指定链接 使用默认class
CallCreateClass->DefaultObject = SpawnClass;
}
//连接结果
UEdGraphPin* CallCreateResult = CallCreateNode->GetReturnValuePin();
CallCreateResult->PinType = SpawnNodeResult->PinType; //使用原来的类型
CompilerContext.MovePinLinksToIntermediate(*SpawnNodeResult, *CallCreateResult);
//运行上面绑定的函数 返回then pin
UEdGraphPin* CallCreateThen = FKismetCompilerUtilities::GenerateAssignmentNodes(CompilerContext, SourceGraph, CallCreateNode, this, CallCreateResult, GetClassToSpawn());
CompilerContext.MovePinLinksToIntermediate(*SpawnNodeThen, *CallCreateThen);
BreakAllNodeLinks();
}
void UTestNode::BreakAllNodeLinks()
{
TSet<UEdGraphNode*> NodeList;
NodeList.Add(this);
Iterate over each pin and break all links
//for (int32 PinIdx = 0; PinIdx < Pins.Num(); PinIdx++)
//{
// Pins[PinIdx]->BreakAllPinLinks();
// NodeList.Add(Pins[PinIdx]->GetOwningNode());
//}
Send all nodes that received a new pin connection a notification
//for (UEdGraphNode* Node : NodeList)
//{
// Node->NodeConnectionListChanged();
//}
}
//在Editor搜索框中的名称
FText UTestNode::GetBaseNodeTitle() const
{
return LOCTEXT("SearchTitle", "Search Node");
}
//节点在event graph上显示的名称
FText UTestNode::GetNodeTitleFormat() const
{
return LOCTEXT("NodeTitle", "Node Title");
}
//默认的pin口 class类型
UClass* UTestNode::GetClassPinBaseClass() const
{
return UObject::StaticClass();
}
#undef LOCTEXT_NAMESPACE