2025-11-18 15:37:21 +08:00

356 lines
13 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 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