UE4自定义资源编辑器开发-图形化节点

UE4自定义资源编辑器开发-图形化节点

1 概述


创建图表后,则需要创建图形节点来组织图表中的逻辑。


2 图形节点创建

UEdGraphNode 创建自己的节点类。

UCLASS()
class UTestGraphNode : public UEdGraphNode
{
	GENERATED_UCLASS_BODY()

public:
	//~ Begin UEdGraphNode Interface
	virtual void AllocateDefaultPins() override;
	virtual FText GetNodeTitle(ENodeTitleType::Type TitleType) const override;
	virtual FText GetTooltipText() const override;
	//~ End UEdGraphNode Interface
	...
}
//Create pins
void UTestGraphNode::AllocateDefaultPins()
{
	CreatePin(EGPD_Output, UTestEditorTypes::PinCategory_SingleNode, FString(), nullptr, TEXT(""));
}

创建节点实例,并添加到图表中:


UEdGraphNode* CreateGraphNode(class UEdGraph* ParentGraph, const FVector2D Location)
{
	if(ParentGraph == NULL) return NULL;
	UEdGraphNode* ResultNode = NewObject<UTestGraphNode>(ParentGraph);
	ParentGraph->Modify();
	ResultNode->SetFlags(RF_Transactional);
	// set outer to be the graph so it doesn't go away
	ResultNode->Rename(NULL, ParentGraph, REN_NonTransactional);
	ResultNode->AddNode(NodeTemplate, true);
	ResultNode->CreateNewGuid();
	NodeTemplate->NodePosX = Location.X;
	NodeTemplate->NodePosY = Location.Y;
	ResultNode->SnapToGrid(AE_SNAP_GRID);
	// setup pins after placing node
	NodeTemplate->AllocateDefaultPins();
	return ResultNode;
}

GraphNode


3 节点连接


上一节中提到的策略类中,可以控制节点是否可以连接,及连接后的操作,如下:


const FPinConnectionResponse UEdGraphSchema_Test::CanCreateConnection(const UEdGraphPin* PinA, const UEdGraphPin* PinB) const
{
	// Make sure the pins are not on the same node
	if (PinA->GetOwningNode() == PinB->GetOwningNode())
	{
		return FPinConnectionResponse(CONNECT_RESPONSE_DISALLOW, LOCTEXT("PinErrorSameNode", "Both are on the same node"));
	}
	// Make sure the pins are not on the same node
	return FPinConnectionResponse(CONNECT_RESPONSE_MAKE, LOCTEXT("PinConnect", "Connect nodes"));
}

// @return	True if a connection was made/broken (graph was modified); false if the connection failed and had no side effects.
bool UEdGraphSchema_UniversalTask::TryCreateConnection(UEdGraphPin* A, UEdGraphPin* B) const
{
	return Super::TryCreateConnection(A, B);
}


3 节点右键菜单

同样在策略图中,可以控制节点生成右键菜单,如下。

void UEdGraphSchema_Test::GetContextMenuActions(class UToolMenu* Menu, class UGraphNodeContextMenuContext* Context) const
{
	if (Context->Node)
	{
		/* before UE4.24
		MenuBuilder->BeginSection("TestGraphSchemaNodeActions", LOCTEXT("ClassActionsMenuHeader", "Node Actions"));
		{
			MenuBuilder->AddMenuEntry(FGenericCommands::Get().Delete);
			MenuBuilder->AddMenuEntry(FGenericCommands::Get().Cut);
			MenuBuilder->AddMenuEntry(FGenericCommands::Get().Copy);
			MenuBuilder->AddMenuEntry(FGenericCommands::Get().Duplicate);
			MenuBuilder->AddMenuEntry(FGraphEditorCommands::Get().BreakNodeLinks);
		}
		MenuBuilder->EndSection();
		*/
		FToolMenuSection& Section = Menu->AddSection("TestGraphSchemaNodeActions", LOCTEXT("ClassActionsMenuHeader", "Node Actions"));
		{
			MenuBuilder->AddMenuEntry(FGenericCommands::Get().Delete);
			MenuBuilder->AddMenuEntry(FGenericCommands::Get().Cut);
			MenuBuilder->AddMenuEntry(FGenericCommands::Get().Copy);
			MenuBuilder->AddMenuEntry(FGenericCommands::Get().Duplicate);
			MenuBuilder->AddMenuEntry(FGraphEditorCommands::Get().BreakNodeLinks);
		}
	
	}

	Super::GetContextMenuActions(Menu,  Context);
}

GraphNodeContextMenu


4 节点、连线及引脚样式


若需要定制样式,则可以添加样式工厂类来实现。

GraphNodeStyle

如 (AnimationGraph):

struct ANIMATIONBLUEPRINTEDITOR_API FAnimationGraphNodeFactory : public FGraphPanelNodeFactory
{
	virtual TSharedPtr<class SGraphNode> CreateNode(class UEdGraphNode* InNode) const override;
};

struct ANIMATIONBLUEPRINTEDITOR_API FAnimationGraphPinFactory : public FGraphPanelPinFactory
{
public:
	virtual TSharedPtr<class SGraphPin> CreatePin(class UEdGraphPin* Pin) const override;
};

struct ANIMATIONBLUEPRINTEDITOR_API FAnimationGraphPinConnectionFactory : public FGraphPanelPinConnectionFactory
{
public:
	virtual class FConnectionDrawingPolicy* CreateConnectionPolicy(const class UEdGraphSchema* Schema, int32 InBackLayerID, int32 InFrontLayerID, float ZoomFactor, const class FSlateRect& InClippingRect, class FSlateWindowElementList& InDrawElements, class UEdGraph* InGraphObj) const override;
};

在模块启动时StartupModule(),注册这些工厂类即可。

void FAnimationBlueprintEditorModule::StartupModule()
{
	...
	AnimGraphNodeFactory = MakeShareable(new FAnimationGraphNodeFactory());
	FEdGraphUtilities::RegisterVisualNodeFactory(AnimGraphNodeFactory);

	AnimGraphPinFactory = MakeShareable(new FAnimationGraphPinFactory());
	FEdGraphUtilities::RegisterVisualPinFactory(AnimGraphPinFactory);

	AnimGraphPinConnectionFactory = MakeShareable(new FAnimationGraphPinConnectionFactory());
	FEdGraphUtilities::RegisterVisualPinConnectionFactory(AnimGraphPinConnectionFactory);
	...
}

4.1 节点样式


若要定制节点样式,需要派生SGraphNode类来创建自己的节点样式类。

class SGraphNodeAnimState : public SGraphNode
{
public:
	SLATE_BEGIN_ARGS(SGraphNodeAnimState){}
	SLATE_END_ARGS()
	void Construct(const FArguments& InArgs, UAnimStateNodeBase* InNode);
	// SNodePanel::SNode interface
	virtual void GetNodeInfoPopups(FNodeInfoContext* Context, TArray<FGraphInformationPopupInfo>& Popups) const override;
	// End of SNodePanel::SNode interface

	// SGraphNode interface
	virtual void UpdateGraphNode() override;
	virtual void CreatePinWidgets() override;
	virtual void AddPin(const TSharedRef<SGraphPin>& PinToAdd) override;
	virtual TSharedPtr<SToolTip> GetComplexTooltip() override;
	// End of SGraphNode interface
	...
};

在节点样式工厂类中选择使用哪种显示样式,如:

TSharedPtr<class SGraphNode> FAnimationGraphNodeFactory::CreateNode(class UEdGraphNode* InNode) const 
{
	...
	if (UAnimStateNode* StateNode = Cast<UAnimStateNode>(InNode))
	{
		return SNew(SGraphNodeAnimState, StateNode);
	}
	return nullptr;
}

UAnimStateNode 即对应前面章节的 UTestGraphNode类。


4.2 连线样式


若要定制连线的样式,则需要从FKismetConnectionDrawingPolicy派生自己的连线绘制策略类。

// This class draws the connections for an UEdGraph with an animation schema
class FAnimGraphConnectionDrawingPolicy : public FKismetConnectionDrawingPolicy
{
public:
	// Constructor
	FAnimGraphConnectionDrawingPolicy(int32 InBackLayerID, int32 InFrontLayerID, float ZoomFactor, const FSlateRect& InClippingRect, FSlateWindowElementList& InDrawElements, UEdGraph* InGraphObj);

	// FKismetConnectionDrawingPolicy interface
	virtual bool TreatWireAsExecutionPin(UEdGraphPin* InputPin, UEdGraphPin* OutputPin) const override;
	virtual void BuildExecutionRoadmap() override;
	virtual void DetermineStyleOfExecWire(float& Thickness, FLinearColor& WireColor, bool& bDrawBubbles, const FTimePair& Times) override;
	// End of FKismetConnectionDrawingPolicy interface
};

在工厂类中选择使用哪个绘制策略:

class FConnectionDrawingPolicy* FAnimationGraphPinConnectionFactory::CreateConnectionPolicy(const class UEdGraphSchema* Schema, int32 InBackLayerID, int32 InFrontLayerID, float ZoomFactor, const class FSlateRect& InClippingRect, class FSlateWindowElementList& InDrawElements, class UEdGraph* InGraphObj) const
{
	if (Schema->IsA(UAnimationGraphSchema::StaticClass()))
	{
		return new FAnimGraphConnectionDrawingPolicy(InBackLayerID, InFrontLayerID, ZoomFactor, InClippingRect, InDrawElements, InGraphObj);
	}
	else if (Schema->IsA(UAnimationStateMachineSchema::StaticClass()))
	{
		return new FStateMachineConnectionDrawingPolicy(InBackLayerID, InFrontLayerID, ZoomFactor, InClippingRect, InDrawElements, InGraphObj);
	}
	return nullptr;
}

另外,开发者也可以直接在图表的schema类中直接重载连接策略:

UCLASS()
class UEdGraphSchema_Test : public UEdGraphSchema
{
	GENERATED_UCLASS_BODY()
	//~ Begin EdGraphSchema Interface
	virtual class FConnectionDrawingPolicy* CreateConnectionDrawingPolicy(int32 InBackLayerID, int32 InFrontLayerID, float InZoomFactor, const FSlateRect& InClippingRect, class FSlateWindowElementList& InDrawElements, class UEdGraph* InGraphObj) const override;
	...
};

4.3 引脚样式


若要定制引脚样式,则派生SGraphPin类来实现。

class SGraphPinPose : public SGraphPin
{
public:
	SLATE_BEGIN_ARGS(SGraphPinPose)	{}
	SLATE_END_ARGS()

	void Construct(const FArguments& InArgs, UEdGraphPin* InPin);

protected:
	//~ Begin SGraphPin Interface
	virtual const FSlateBrush* GetPinIcon() const override;
	//~ End SGraphPin Interface
	mutable const FSlateBrush* CachedImg_Pin_ConnectedHovered;
	mutable const FSlateBrush* CachedImg_Pin_DisconnectedHovered;
};

同样在对应的工厂类中,选择使用哪种样式的引脚。

TSharedPtr<class SGraphPin> FAnimationGraphPinFactory::CreatePin(class UEdGraphPin* InPin) const
{
	if (InPin->PinType.PinCategory == UEdGraphSchema_K2::PC_Struct)
	{
		if ((InPin->PinType.PinSubCategoryObject == FPoseLink::StaticStruct()) || (InPin->PinType.PinSubCategoryObject == FComponentSpacePoseLink::StaticStruct()))
		{
			return SNew(SGraphPinPose, InPin);
		}
	}
	...
	return nullptr;
}

上面函数返回空,则使用默认样式。


链接




Tags: UE4 Editor Vistied:
Share: Twitter Facebook LinkedIn