356 lines
13 KiB
C++
356 lines
13 KiB
C++
// Fill out your copyright notice in the Description page of Project Settings.
|
||
|
||
#include "DialogueGraphSchema.h"
|
||
#include "Node/DialogueGraphNode_Base.h"
|
||
#include "Node/DialogueGraphNode_NPC.h"
|
||
#include "Node/DialogueGraphNode_Player.h"
|
||
#include "Node/DialogueGraphNode_Root.h"
|
||
|
||
#define LOCTEXT_NAMESPACE "DialogueGraphSchema"
|
||
|
||
UEdGraphNode* FDialogueGraphSchemaAction_NewNode::PerformAction(UEdGraph* ParentGraph, UEdGraphPin* FromPin, const FVector2D Location, bool bSelectNewNode)
|
||
{
|
||
UDialogueGraphNode_Base* NewNode = NewObject<UDialogueGraphNode_Base>(ParentGraph, ClassTemplate);
|
||
NewNode->CreateNewGuid();
|
||
NewNode->SetPostion(Location);
|
||
NewNode->InitializeNodeData();
|
||
NewNode->AllocateDefaultPins();
|
||
|
||
ParentGraph->Modify();
|
||
ParentGraph->AddNode(NewNode, true, bSelectNewNode);
|
||
|
||
// 如果从某个Pin拖拽创建,自动连接
|
||
if (FromPin && NewNode->Pins.Num() > 0)
|
||
{
|
||
for (UEdGraphPin* Pin : NewNode->Pins)
|
||
{
|
||
if (Pin->Direction != FromPin->Direction)
|
||
{
|
||
GetDefault<UDialogueGraphSchema>()->TryCreateConnection(FromPin, Pin);
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
return NewNode;
|
||
}
|
||
|
||
FVerticalConnectionDrawingPolicy::FVerticalConnectionDrawingPolicy(int32 InBackLayerID, int32 InFrontLayerID,
|
||
float InZoomFactor, const FSlateRect& InClippingRect, FSlateWindowElementList& InDrawElements)
|
||
: FConnectionDrawingPolicy(InBackLayerID, InFrontLayerID, InZoomFactor, InClippingRect, InDrawElements)
|
||
{
|
||
}
|
||
|
||
void FVerticalConnectionDrawingPolicy::DrawSplineWithArrow(const FVector2D& StartPoint, const FVector2D& EndPoint,
|
||
const FConnectionParams& Params)
|
||
{
|
||
// Draw the spline
|
||
DrawConnection(
|
||
WireLayerID,
|
||
StartPoint,
|
||
EndPoint,
|
||
Params);
|
||
|
||
// Draw the arrow
|
||
if (ArrowImage != nullptr)
|
||
{
|
||
FVector2D ArrowPoint = EndPoint - ArrowRadius;
|
||
|
||
FSlateDrawElement::MakeRotatedBox(
|
||
DrawElementsList,
|
||
ArrowLayerID,
|
||
FPaintGeometry(ArrowPoint, ArrowImage->ImageSize * ZoomFactor, ZoomFactor),
|
||
ArrowImage,
|
||
ESlateDrawEffect::None,
|
||
FMath::DegreesToRadians(90), // 旋转角度(弧度)
|
||
ArrowImage->ImageSize * 0.5f * ZoomFactor, // 旋转中心
|
||
FSlateDrawElement::RelativeToElement,
|
||
Params.WireColor
|
||
);
|
||
}
|
||
}
|
||
|
||
void FVerticalConnectionDrawingPolicy::DrawSplineWithArrow(const FGeometry& StartGeom, const FGeometry& EndGeom,
|
||
const FConnectionParams& Params)
|
||
{
|
||
//@TODO: These values should be pushed into the Slate style, they are compensating for a bit of
|
||
// empty space inside of the pin brush images.
|
||
const float StartFudgeX = 4.0f;
|
||
const float EndFudgeX = 4.0f;
|
||
const FVector2D StartPoint = FGeometryHelper::CenterOf(StartGeom) - FVector2D(ArrowRadius.X, StartFudgeX);
|
||
const FVector2D EndPoint = FGeometryHelper::CenterOf(EndGeom) - FVector2D(0, ArrowRadius.Y - EndFudgeX);
|
||
|
||
DrawSplineWithArrow(StartPoint, EndPoint, Params);
|
||
}
|
||
|
||
// void FVerticalConnectionDrawingPolicy::DrawConnection(int32 LayerId, const FVector2D& Start, const FVector2D& End,
|
||
// const FConnectionParams& Params)
|
||
// {
|
||
// const FVector2D& P0 = Start;
|
||
// const FVector2D& P1 = End;
|
||
// // FVector2D P0 = GetCorrectedPinPosition(Start, Params.AssociatedPin1, Params.StartDirection);
|
||
// // FVector2D P1 = GetCorrectedPinPosition(End, Params.AssociatedPin2, Params.EndDirection);
|
||
//
|
||
// // 计算连线方向
|
||
// const FVector2D Delta = P1 - P0;
|
||
// const bool bIsVerticalConnection = FMath::Abs(Delta.Y) > FMath::Abs(Delta.X);
|
||
//
|
||
// // 根据连线方向计算切线
|
||
// FVector2D SplineTangent;
|
||
// if (bIsVerticalConnection)
|
||
// {
|
||
// // 垂直连线:主要控制垂直方向的弯曲
|
||
// SplineTangent = FVector2D(0, FMath::Abs(Delta.Y) * 0.5f);
|
||
// }
|
||
// else
|
||
// {
|
||
// // 水平连线:保持原有逻辑
|
||
// SplineTangent = FVector2D(FMath::Abs(Delta.X) * 0.5f, 0);
|
||
// }
|
||
//
|
||
// // 修改切线方向计算,适应垂直连线
|
||
// FVector2D P0Tangent, P1Tangent;
|
||
//
|
||
// if (bIsVerticalConnection)
|
||
// {
|
||
// // 垂直连线的切线逻辑
|
||
// if (Params.StartDirection == EGPD_Output)
|
||
// {
|
||
// // 输出引脚:根据连线方向调整
|
||
// P0Tangent = (Delta.Y >= 0) ? SplineTangent : -SplineTangent;
|
||
// }
|
||
// else
|
||
// {
|
||
// // 输入引脚:根据连线方向调整
|
||
// P0Tangent = (Delta.Y >= 0) ? -SplineTangent : SplineTangent;
|
||
// }
|
||
//
|
||
// if (Params.EndDirection == EGPD_Input)
|
||
// {
|
||
// // 输入引脚:根据连线方向调整
|
||
// P1Tangent = (Delta.Y >= 0) ? SplineTangent : -SplineTangent;
|
||
// }
|
||
// else
|
||
// {
|
||
// // 输出引脚:根据连线方向调整
|
||
// P1Tangent = (Delta.Y >= 0) ? -SplineTangent : SplineTangent;
|
||
// }
|
||
// }
|
||
// else
|
||
// {
|
||
// // 水平连线保持原有逻辑
|
||
// P0Tangent = (Params.StartDirection == EGPD_Output) ? SplineTangent : -SplineTangent;
|
||
// P1Tangent = (Params.EndDirection == EGPD_Input) ? SplineTangent : -SplineTangent;
|
||
// }
|
||
//
|
||
// // 使用自定义切线(如果提供了的话)
|
||
// if (!Params.StartTangent.IsNearlyZero())
|
||
// {
|
||
// P0Tangent = Params.StartTangent;
|
||
// }
|
||
// if (!Params.EndTangent.IsNearlyZero())
|
||
// {
|
||
// P1Tangent = Params.EndTangent;
|
||
// }
|
||
//
|
||
// // 后面的碰撞检测等逻辑保持不变...
|
||
// if (Settings->bTreatSplinesLikePins)
|
||
// {
|
||
// // [保持原有的碰撞检测逻辑不变]
|
||
// // ... 这里是你原有的碰撞检测代码 ...
|
||
// }
|
||
//
|
||
// // 绘制连线(这部分保持不变)
|
||
// FSlateDrawElement::MakeDrawSpaceSpline(
|
||
// DrawElementsList,
|
||
// LayerId,
|
||
// P0, P0Tangent,
|
||
// P1, P1Tangent,
|
||
// Params.WireThickness,
|
||
// ESlateDrawEffect::None,
|
||
// Params.WireColor
|
||
// );
|
||
//
|
||
// // 修改中点的方向计算
|
||
// if (Params.bDrawBubbles || (MidpointImage != nullptr))
|
||
// {
|
||
// // 重新参数化表计算(保持不变)
|
||
// FInterpCurve<float> SplineReparamTable;
|
||
// const float SplineLength = MakeSplineReparamTable(P0, P0Tangent, P1, P1Tangent, SplineReparamTable);
|
||
//
|
||
// // 气泡绘制逻辑(保持不变)
|
||
// if (Params.bDrawBubbles)
|
||
// {
|
||
// // [保持原有的气泡绘制逻辑]
|
||
// // ... 这里是你原有的气泡绘制代码 ...
|
||
// }
|
||
//
|
||
// // 修改中点图标的旋转逻辑
|
||
// if (MidpointImage != nullptr)
|
||
// {
|
||
// const float MidpointAlpha = SplineReparamTable.Eval(SplineLength * 0.5f, 0.f);
|
||
// const FVector2D Midpoint = FMath::CubicInterp(P0, P0Tangent, P1, P1Tangent, MidpointAlpha);
|
||
//
|
||
// const FVector2D MidpointPlusE = FMath::CubicInterp(P0, P0Tangent, P1, P1Tangent, MidpointAlpha + KINDA_SMALL_NUMBER);
|
||
// const FVector2D MidpointMinusE = FMath::CubicInterp(P0, P0Tangent, P1, P1Tangent, MidpointAlpha - KINDA_SMALL_NUMBER);
|
||
// FVector2D SlopeUnnormalized = MidpointPlusE - MidpointMinusE;
|
||
//
|
||
// // 如果是垂直连线,调整角度计算
|
||
// float AngleInRadians;
|
||
// if (bIsVerticalConnection)
|
||
// {
|
||
// // 垂直连线:主要考虑Y轴方向
|
||
// if (FMath::Abs(SlopeUnnormalized.Y) > FMath::Abs(SlopeUnnormalized.X))
|
||
// {
|
||
// // 主要垂直方向,旋转90度
|
||
// AngleInRadians = FMath::Atan2(SlopeUnnormalized.Y, SlopeUnnormalized.X) + FMath::DegreesToRadians(90.0f);
|
||
// }
|
||
// else
|
||
// {
|
||
// AngleInRadians = FMath::Atan2(SlopeUnnormalized.Y, SlopeUnnormalized.X);
|
||
// }
|
||
// }
|
||
// else
|
||
// {
|
||
// AngleInRadians = SlopeUnnormalized.IsNearlyZero() ? 0.0f : FMath::Atan2(SlopeUnnormalized.Y, SlopeUnnormalized.X);
|
||
// }
|
||
//
|
||
// const FVector2D MidpointDrawPos = Midpoint - MidpointRadius;
|
||
//
|
||
// FSlateDrawElement::MakeRotatedBox(
|
||
// DrawElementsList,
|
||
// LayerId,
|
||
// FPaintGeometry(MidpointDrawPos, MidpointImage->ImageSize * ZoomFactor, ZoomFactor),
|
||
// MidpointImage,
|
||
// ESlateDrawEffect::None,
|
||
// AngleInRadians,
|
||
// TOptional<FVector2D>(),
|
||
// FSlateDrawElement::RelativeToElement,
|
||
// Params.WireColor
|
||
// );
|
||
// }
|
||
// }
|
||
// }
|
||
|
||
FVector2D FVerticalConnectionDrawingPolicy::ComputeSplineTangent(const FVector2D& Start, const FVector2D& End) const
|
||
{
|
||
// 修改为垂直方向:
|
||
const FVector2D Delta = End - Start;
|
||
|
||
// 如果是主要垂直方向的连线,使用垂直切线
|
||
if (FMath::Abs(Delta.Y) > FMath::Abs(Delta.X))
|
||
{
|
||
// 垂直连线:主要控制垂直曲线
|
||
return FVector2D(0, FMath::Abs(Delta.Y) * 0.5f);
|
||
}
|
||
else
|
||
{
|
||
// 水平连线:保持原有逻辑
|
||
return FVector2D(FMath::Abs(Delta.X) * 0.5f, 0);
|
||
}
|
||
}
|
||
|
||
FVector2D FVerticalConnectionDrawingPolicy::GetPinPos(const UEdGraphPin* Pin) const
|
||
{
|
||
// const FVector2D NodeSize = GetDesiredSize();
|
||
// FVector2D NodePosition;
|
||
// if (Pin->Direction == EGPD_Input)
|
||
// {
|
||
// // 输入引脚:位于节点顶部中央
|
||
// NodePosition = FVector2D(NodeWidth * 0.5f, 0.0f);
|
||
// }
|
||
// else
|
||
// {
|
||
// // 输出引脚:位于节点底部中央
|
||
// NodePosition = FVector2D(NodeWidth * 0.5f, NodeHeight);
|
||
// }
|
||
//
|
||
//
|
||
// if (Pin->Direction == EGPD_Input)
|
||
// {
|
||
// // 输入引脚在顶部中央
|
||
// return NodePosition + FVector2D(NodeSize.X * 0.5f, 0.0f);
|
||
// }
|
||
// else
|
||
// {
|
||
// // 输出引脚在底部中央
|
||
// return NodePosition + FVector2D(NodeSize.X * 0.5f, NodeSize.Y);
|
||
// }
|
||
return FVector2D();
|
||
}
|
||
|
||
// FVector2D FVerticalConnectionDrawingPolicy::GetCorrectedPinPosition(const FVector2D& OriginalPosition, UEdGraphPin* Pin,
|
||
// EEdGraphPinDirection Direction)
|
||
// {
|
||
// if (!Pin)
|
||
// return OriginalPosition;
|
||
//
|
||
// // 获取引脚的视觉widget
|
||
// TSharedPtr<SGraphPin> GraphPin = GetPinWidget(Pin);
|
||
// if (!GraphPin.IsValid())
|
||
// return OriginalPosition;
|
||
//
|
||
// // 计算引脚的真正中心点
|
||
// FGeometry PinGeometry = GraphPin->GetCachedGeometry();
|
||
// FVector2D PinCenter = PinGeometry.GetAbsolutePosition() + PinGeometry.GetAbsoluteSize() * 0.5f;
|
||
//
|
||
// // 转换为绘制空间坐标
|
||
// return PinCenter;
|
||
// }
|
||
|
||
void UDialogueGraphSchema::CreateDefaultNodesForGraph(UEdGraph& Graph) const
|
||
{
|
||
FGraphNodeCreator<UDialogueGraphNode_Root> NodeCreator(Graph);
|
||
UDialogueGraphNode_Root* MyNode = NodeCreator.CreateNode(true, UDialogueGraphNode_Root::StaticClass());
|
||
NodeCreator.Finalize();
|
||
SetNodeMetaData(MyNode, FNodeMetadata::DefaultGraphNode);
|
||
}
|
||
|
||
void UDialogueGraphSchema::GetGraphContextActions(FGraphContextMenuBuilder& ContextMenuBuilder) const
|
||
{
|
||
// 添加npc对话节点
|
||
TSharedPtr<FDialogueGraphSchemaAction_NewNode> NPCNodeAction = MakeShareable(new FDialogueGraphSchemaAction_NewNode(
|
||
UDialogueGraphNode_NPC::StaticClass(),
|
||
LOCTEXT("DialogueNode_NPC_Category", "NPC Dialogue"),
|
||
LOCTEXT("DialogueNode_NPC_Desc", "NPC Dialogue Node"),
|
||
LOCTEXT("DialogueNode_NPC_Tooltip", "Create a npc dialogue node")
|
||
));
|
||
ContextMenuBuilder.AddAction(NPCNodeAction);
|
||
// 添加npc对话节点
|
||
TSharedPtr<FDialogueGraphSchemaAction_NewNode> PlayerNodeAction = MakeShareable(new FDialogueGraphSchemaAction_NewNode(
|
||
UDialogueGraphNode_Player::StaticClass(),
|
||
LOCTEXT("DialogueNode_Player_Category", "Player Dialogue"),
|
||
LOCTEXT("DialogueNode_Player_Desc", "Player Dialogue Node"),
|
||
LOCTEXT("DialogueNode_Player_Tooltip", "Create a Player dialogue node")
|
||
));
|
||
ContextMenuBuilder.AddAction(PlayerNodeAction);
|
||
|
||
}
|
||
|
||
const FPinConnectionResponse UDialogueGraphSchema::CanCreateConnection(const UEdGraphPin* A, const UEdGraphPin* B) const
|
||
{
|
||
// 不能连接自己
|
||
if (A->GetOwningNode() == B->GetOwningNode())
|
||
{
|
||
return FPinConnectionResponse(CONNECT_RESPONSE_DISALLOW, LOCTEXT("ConnectionSameNode", "Cannot connect to self"));
|
||
}
|
||
|
||
// 必须一个输入一个输出
|
||
if (A->Direction == B->Direction)
|
||
{
|
||
return FPinConnectionResponse(CONNECT_RESPONSE_DISALLOW, LOCTEXT("ConnectionSameDirection", "Must connect input to output"));
|
||
}
|
||
|
||
return FPinConnectionResponse(CONNECT_RESPONSE_MAKE, TEXT(""));
|
||
}
|
||
|
||
FConnectionDrawingPolicy* UDialogueGraphSchema::CreateConnectionDrawingPolicy(int32 InBackLayerID, int32 InFrontLayerID,
|
||
float InZoomFactor, const FSlateRect& InClippingRect, FSlateWindowElementList& InDrawElements,
|
||
class UEdGraph* InGraphObj) const
|
||
{
|
||
return new FVerticalConnectionDrawingPolicy(InBackLayerID, InFrontLayerID, InZoomFactor,
|
||
InClippingRect, InDrawElements);
|
||
}
|
||
|
||
#undef LOCTEXT_NAMESPACE
|