创建图表后,则需要创建图形节点来组织图表中的逻辑。
由 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;
}
在上一节中提到的策略类中,可以控制节点是否可以连接,及连接后的操作,如下:
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);
}
同样在策略图中,可以控制节点生成右键菜单,如下。
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);
}
若需要定制样式,则可以添加样式工厂类来实现。
如 (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);
...
}
若要定制节点样式,需要派生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类。
若要定制连线的样式,则需要从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;
...
};
若要定制引脚样式,则派生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;
}
上面函数返回空,则使用默认样式。