找回密码
 立即注册
查看: 319|回复: 0

unreal自定义蓝图节点1

[复制链接]
发表于 2022-7-19 10:25 | 显示全部楼层 |阅读模式
前提配置

因为蓝图的节点是仅仅在Editor中使用的,并不需要打包的,为了和项目的代码做好区分处理,所以我使用了module的形式去处理!
module创建
现在是我们希望在Editor的模块下创建自定义的蓝图节点,该节点调用的是运行时的节点! 我们需要在module声明中将该模块改为UncookedOnly(Editor也可以!)
"Modules": [
        ...
        {
            "Name": "MyEditorTools",
            "Type": "UncookedOnly",
            "LoadingPhase": "Default",
            "AdditionalDependencies": [
                "UnrealGameDemo"
            ]
        }
    ]在 MyEditorTools.Build.cs 中添加一些必须的依赖,要不然在后续的使用和编译中会有报错!

  • KismetCompiler
无法解析的外部符号 "declspec(dllimport) public: struct FPinConnectionResponse cdecl FKismetCompilerContext::MovePinLinksToIntermediate(class UEdGraphPin &,class UEdGraphPin &)" (imp_?MovePinLinksToIntermediate@FKismetCompilerContext@@QEAA?AUFPinConnectionResponse@@AEAVUEdGraphPin@@0@Z),函数 "public: virtual void cdecl UCustomNode::ExpandNode(class FKismetCompilerContext &,class UEdGraph *)" (?ExpandNode@UCustomNode@@UEAAXAEAVFKismetCompilerContext@@PEAVUEdGraph@@@Z) 中引用了该符号


  • BlueprintGraph
无法解析的外部符号 "declspec(dllimport) public: cdecl FBlueprintNodeSignature::FBlueprintNodeSignature(class TSubclassOf)" (imp_??0FBlueprintNodeSignature@@QEAA@V?$TSubclassOf@VUEdGraphNode@@@@@Z),函数 "public: virtual struct FBlueprintNodeSignature cdecl UK2Node::GetSignature(void)const " (?GetSignature@UK2Node@@UEBA?AUFBlueprintNodeSignature@@XZ) 中引用了该符号


  • UnrealEd
无法解析的外部符号 "declspec(dllimport) public: void cdecl FCompilerResultsLog::NotifyIntermediateObjectCreation(class UObject ,class UObject )" (imp_?NotifyIntermediateObjectCreation@FCompilerResultsLog@@QEAAXPEAVUObject@@0@Z),函数 "public: virtual void cdecl UCustomNode::ExpandNode(class FKismetCompilerContext &,class UEdGraph *)" (?ExpandNode@UCustomNode@@UEAAXAEAVFKismetCompilerContext@@PEAVUEdGraph@@@Z) 中引用了该符号
PrivateDependencyModuleNames.AddRange(new string[]{"KismetCompiler", "BlueprintGraph", "UnrealEd"});
具体的蓝图节点实现


  • 直接使用UFUNCTION
  • 自定义蓝图节点
直接使用UFUNCTION

UCLASS()
class UNREALGAMEDEMO_API UCustomRunningNode : public UObject
{
public:
    GENERATED_BODY()
    UFUNCTION(BlueprintCallable, Category="Custom|CustomRunningNode", meta=(ToolTip="this is a tooltip"))
    static void TestBlueprintNode1(FString arg1)
    {
        UE_LOG(LogUnrealGameDemo, Display, TEXT("UCustomRunningNode::TestBlueprintNode1"));
    }
};






自定义蓝图节点

这里使用的是继承UK2Node实现的! 在MyEditorTools的模块中添加节点类,并继承UK2Node
#pragma once
#include "K2Node.h"
#include "CustomNode.generated.h"

UCLASS()
class UCustomNode : public UK2Node
{
public:
    GENERATED_BODY()
    virtual FText GetTooltipText() const override {return FText::FromString(TEXT("This is a test case"));};
    virtual FText GetNodeTitle(ENodeTitleType::Type TitleType) const override {return  FText::FromString(TEXT("Custom Node"));};
    virtual FText GetMenuCategory() const override{return FText::FromString(TEXT("Custom|CustomNode"));};
    virtual void GetMenuActions(FBlueprintActionDatabaseRegistrar& ActionRegistrar) const override;

    virtual void ExpandNode(FKismetCompilerContext& CompilerContext, UEdGraph* SourceGraph) override;
    virtual void AllocateDefaultPins() override;
    UEdGraphPin* GetThenPin() const;
};
cpp
#include "CustomNode.h"
#include "BlueprintActionDatabaseRegistrar.h"
#include "BlueprintNodeSpawner.h"
#include "EdGraphSchema_K2.h"
#include "K2Node_CallFunction.h"
#include "KismetCompiler.h"

void UCustomNode::GetMenuActions(FBlueprintActionDatabaseRegistrar& ActionRegistrar) const
{
    Super::GetMenuActions(ActionRegistrar);
    auto Classkey = GetClass();
    if (ActionRegistrar.IsOpenForRegistration(Classkey))
    {
        auto nodeSpawner = UBlueprintNodeSpawner::Create(Classkey);
        check(nodeSpawner!= nullptr);
        ActionRegistrar.AddBlueprintAction(nodeSpawner);
    }
}

void UCustomNode::ExpandNode(FKismetCompilerContext& CompilerContext, UEdGraph* SourceGraph)
{
    Super::ExpandNode(CompilerContext, SourceGraph);
}

void UCustomNode::AllocateDefaultPins()
{
    Super::AllocateDefaultPins();
}

UEdGraphPin* UCustomNode::GetThenPin() const
{
    UEdGraphPin* Pin = FindPin(UEdGraphSchema_K2::PN_Then);
    check(Pin == nullptr || Pin->Direction == EGPD_Output); // If pin exists, it must be input
    return Pin;
}
这个时候编译完成后,我们就能在蓝图里看到新加的节点了!





GetTooltipText方法是鼠标浮在节点上的提示!
GetNodeTitle是节点的名称!
GetMenuCategory是节点的归类目录
GetMenuActions是将节点注册到蓝图的右键菜单中!
注意:如果是plugin或者是独立的module的话,想要生效,需要重新reload或者在ue中compiler!



蓝图节点在构建展示的时候,会默认调用AllocateDefaultPins,所以我们如果想要想其他默认节点那样能接入到流程中,需要在AllocateDefaultPins中添加一些代码
void UCustomNode::AllocateDefaultPins()
{
    CreatePin(EGPD_Input, UEdGraphSchema_K2::PC_Exec, UEdGraphSchema_K2::PN_Execute);
    CreatePin(EGPD_Output, UEdGraphSchema_K2::PC_Exec, UEdGraphSchema_K2::PN_Then);
    Super::AllocateDefaultPins();
}
使用CreatePin去创建流入和流出的pin,需要注意的是,这里的第三个参数是name,但是有不全是!最好是先默认UEdGraphSchema_K2::PN_Execute和UEdGraphSchema_K2::PN_Then;
你可以试试换成中文;eg: TEXT("输入"),TEXT("输出");看看能不能调用和debug!!



试试连接起来编译看看



原因是该节点没有执行的函数!需要在ExpandNode中绑定!
void UCustomNode::ExpandNode(FKismetCompilerContext& CompilerContext, UEdGraph* SourceGraph)
{
    Super::ExpandNode(CompilerContext, SourceGraph);
    // 获取流入的pin
    auto execPin = GetExecPin();
    // 获取流出的pin
    auto thenPin = GetThenPin();
    if (execPin && thenPin)
    {
        // 获取要执行的方法名,需要注意,一定要有UFUNCTION,
        auto functionName = GET_FUNCTION_NAME_CHECKED(UCustomRunningNode, TestBlueprintNode2);
        // 构建要执行的方法节点!
        auto callFunction = CompilerContext.SpawnIntermediateNode<UK2Node_CallFunction>(this, SourceGraph);
        // 设置并绑定执行的方法体
        callFunction->FunctionReference.SetExternalMember(functionName, UCustomRunningNode::StaticClass());
        callFunction->AllocateDefaultPins();

        // 流程转移!
        CompilerContext.MovePinLinksToIntermediate(*execPin, *(callFunction->GetExecPin()));
        CompilerContext.MovePinLinksToIntermediate(*thenPin, *(callFunction->GetThenPin()));
    }
    // 断开所有的link
    BreakAllNodeLinks();
}
这里的UCustomRunningNode是在项目运行时的module中的
UCLASS()
class UNREALGAMEDEMO_API UCustomRunningNode : public UObject
{
public:
    GENERATED_BODY()
    UFUNCTION(BlueprintCallable)
    static void TestBlueprintNode2()
    {
        UE_LOG(LogUnrealGameDemo, Display, TEXT("UCustomRunningNode::TestBlueprintNode2"));
    }
};
执行编译和reload后,一切正常了!debug和执行都没有问题了!
补充


  • PinDefaultValueChanged
当蓝图的节点的内容发生改变的时候,此函数是回调!

  • CreatePin
该节点支持很多种类型的内容
Bool,
Byte,
Class,
SoftClass,
Int,
Int64,
Float,
Name,
Delegate,
Object,
Interface,
SoftObject,
String,
Text,
Struct,
Enumeg : CreatePin(EGPD_Input, TEXT("Struct"), TEXT("AName"));

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-9-22 04:34 , Processed in 0.064680 second(s), 23 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表