352 lines
10 KiB
C++

// Fill out your copyright notice in the Description page of Project Settings.
#include "Widgets/BagConfigGridWidget.h"
#include "ProjectFish/DataAsset/BagShapeAsset.h"
const float SBagConfigGridWidget::CellSize = 32.0f;
const float SBagConfigGridWidget::CellSpacing = 2.0f;
void SBagConfigGridWidget::Construct(const FArguments& InArgs)
{
BagConfig = InArgs._BagConfig;
OnGridCellClicked = InArgs._OnGridCellClicked;
PreviewSkill = nullptr;
PreviewX = -1;
PreviewY = -1;
HoveredSkillIndex = -1;
ChildSlot
[
SNew(SOverlay)
];
}
void SBagConfigGridWidget::RefreshGrid()
{
// 强制重绘
Invalidate(EInvalidateWidget::Paint);
}
FReply SBagConfigGridWidget::OnMouseButtonDown(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
{
if (MouseEvent.GetEffectingButton() == EKeys::LeftMouseButton && BagConfig.IsValid())
{
FVector2D LocalPosition = MyGeometry.AbsoluteToLocal(MouseEvent.GetScreenSpacePosition());
FVector2D GridCell = GetGridCellFromPosition(LocalPosition);
int32 GridX = FMath::FloorToInt(GridCell.X);
int32 GridY = FMath::FloorToInt(GridCell.Y);
if (IsValidGridPosition(GridX, GridY))
{
OnGridCellClicked.ExecuteIfBound(GridX, GridY);
return FReply::Handled();
}
}
return FReply::Unhandled();
}
FReply SBagConfigGridWidget::OnMouseMove(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
{
if (BagConfig.IsValid())
{
FVector2D LocalPosition = MyGeometry.AbsoluteToLocal(MouseEvent.GetScreenSpacePosition());
FVector2D GridCell = GetGridCellFromPosition(LocalPosition);
int32 GridX = FMath::FloorToInt(GridCell.X);
int32 GridY = FMath::FloorToInt(GridCell.Y);
if (IsValidGridPosition(GridX, GridY))
{
USkillAsset* HoveredSkill = GetSkillAtPosition(GridX, GridY);
if (HoveredSkill)
{
int32 NewHoveredIndex = BagConfig->GetSkillAtPosition(GridX, GridY);
if (NewHoveredIndex != HoveredSkillIndex)
{
HoveredSkillIndex = NewHoveredIndex;
HoveredSkillTooltip = CreateSkillTooltip(HoveredSkill);
if (HoveredSkillTooltip.IsValid())
{
FSlateApplication::Get().PushMenu(
AsShared(),
FWidgetPath(),
HoveredSkillTooltip.ToSharedRef(),
MouseEvent.GetScreenSpacePosition(),
FPopupTransitionEffect::None
);
}
}
return FReply::Handled();
}
}
// 清除悬停状态
if (HoveredSkillIndex != -1)
{
HoveredSkillIndex = -1;
if (HoveredSkillTooltip.IsValid())
{
FSlateApplication::Get().DismissAllMenus();
HoveredSkillTooltip.Reset();
}
}
}
return FReply::Unhandled();
}
void SBagConfigGridWidget::OnMouseEnter(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
{
SCompoundWidget::OnMouseEnter(MyGeometry, MouseEvent);
}
void SBagConfigGridWidget::OnMouseLeave(const FPointerEvent& MouseEvent)
{
// 清除悬停状态
if (HoveredSkillIndex != -1)
{
HoveredSkillIndex = -1;
if (HoveredSkillTooltip.IsValid())
{
FSlateApplication::Get().DismissAllMenus();
HoveredSkillTooltip.Reset();
}
}
SCompoundWidget::OnMouseLeave(MouseEvent);
}
int32 SBagConfigGridWidget::OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry,
const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId,
const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const
{
if (!BagConfig.IsValid() || !BagConfig->BagShapeAsset)
{
return LayerId;
}
UBagShapeAsset* BagShapeAsset = BagConfig->BagShapeAsset;
// 绘制背包格子
for (int32 Y = 0; Y < BagShapeAsset->BagHeight; Y++)
{
for (int32 X = 0; X < BagShapeAsset->BagWidth; X++)
{
FVector2D CellPos = GetCellPosition(X, Y);
FVector2D CellSizeVec(CellSize, CellSize);
// 获取格子颜色
FLinearColor CellColor = GetCellColor(X, Y);
// 绘制格子背景
FSlateDrawElement::MakeBox(
OutDrawElements,
LayerId,
AllottedGeometry.ToPaintGeometry(CellSizeVec, FSlateLayoutTransform(CellPos)),
FCoreStyle::Get().GetBrush("WhiteBrush"),
ESlateDrawEffect::None,
CellColor
);
// 绘制格子边框
FSlateDrawElement::MakeBox(
OutDrawElements,
LayerId + 1,
AllottedGeometry.ToPaintGeometry(CellSizeVec, FSlateLayoutTransform(CellPos)),
FCoreStyle::Get().GetBrush("Border"),
ESlateDrawEffect::None,
FLinearColor::Black
);
}
}
// 绘制已放置的技能
for (int32 i = 0; i < BagConfig->PlacedSkills.Num(); i++)
{
const FPlacedSkillInfo& PlacedSkill = BagConfig->PlacedSkills[i];
FVector2D SkillPos = GetCellPosition(PlacedSkill.PositionX, PlacedSkill.PositionY);
FVector2D SkillSizeVec(GetSkillSizeValue(PlacedSkill.SkillAsset->SkillSize).X * (CellSize + CellSpacing) - CellSpacing,
GetSkillSizeValue(PlacedSkill.SkillAsset->SkillSize).Y* (CellSize + CellSpacing) - CellSpacing);
// 绘制技能背景
FSlateDrawElement::MakeBox(
OutDrawElements,
LayerId + 2,
AllottedGeometry.ToPaintGeometry(SkillSizeVec, FSlateLayoutTransform(SkillPos)),
FCoreStyle::Get().GetBrush("WhiteBrush"),
ESlateDrawEffect::None,
FLinearColor::Blue
);
// 绘制技能边框
FSlateDrawElement::MakeBox(
OutDrawElements,
LayerId + 3,
AllottedGeometry.ToPaintGeometry(SkillSizeVec, FSlateLayoutTransform(SkillPos)),
FCoreStyle::Get().GetBrush("Border"),
ESlateDrawEffect::None,
FLinearColor::White
);
// 绘制技能名称
if (!PlacedSkill.SkillAsset->SkillName.IsEmpty())
{
FSlateDrawElement::MakeText(
OutDrawElements,
LayerId + 4,
AllottedGeometry.ToPaintGeometry(SkillSizeVec, FSlateLayoutTransform(SkillPos + FVector2D(4, 4))),
PlacedSkill.SkillAsset->SkillName,
FCoreStyle::GetDefaultFontStyle("Regular", 10),
ESlateDrawEffect::None,
FLinearColor::White
);
}
}
// 绘制预览技能
if (PreviewSkill.IsValid() && PreviewX >= 0 && PreviewY >= 0)
{
FVector2D PreviewPos = GetCellPosition(PreviewX, PreviewY);
FVector2D PreviewSizeVec(GetSkillSizeValue(PreviewSkill->SkillSize).X * (CellSize + CellSpacing) - CellSpacing,
GetSkillSizeValue(PreviewSkill->SkillSize).Y * (CellSize + CellSpacing) - CellSpacing);
FLinearColor PreviewColor = FLinearColor::Blue;
PreviewColor.A = 0.5f; // 半透明
// 绘制预览背景
FSlateDrawElement::MakeBox(
OutDrawElements,
LayerId + 5,
AllottedGeometry.ToPaintGeometry(PreviewSizeVec, FSlateLayoutTransform(PreviewPos)),
FCoreStyle::Get().GetBrush("WhiteBrush"),
ESlateDrawEffect::None,
PreviewColor
);
// 绘制预览边框(虚线效果)
FSlateDrawElement::MakeBox(
OutDrawElements,
LayerId + 6,
AllottedGeometry.ToPaintGeometry(PreviewSizeVec, FSlateLayoutTransform(PreviewPos)),
FCoreStyle::Get().GetBrush("Border"),
ESlateDrawEffect::None,
FLinearColor::Yellow
);
}
return LayerId + 7;
}
FVector2D SBagConfigGridWidget::ComputeDesiredSize(float X) const
{
if (!BagConfig.IsValid() || !BagConfig->BagShapeAsset)
{
return FVector2D(100, 100);
}
UBagShapeAsset* BagShapeAsset = BagConfig->BagShapeAsset;
return FVector2D(
BagShapeAsset->BagWidth * (CellSize + CellSpacing) - CellSpacing,
BagShapeAsset->BagHeight * (CellSize + CellSpacing) - CellSpacing
);
}
FVector2D SBagConfigGridWidget::GetGridCellFromPosition(const FVector2D& Position) const
{
return FVector2D(
Position.X / (CellSize + CellSpacing),
Position.Y / (CellSize + CellSpacing)
);
}
bool SBagConfigGridWidget::IsValidGridPosition(int32 X, int32 Y) const
{
if (!BagConfig.IsValid() || !BagConfig->BagShapeAsset)
{
return false;
}
return X >= 0 && X < BagConfig->BagShapeAsset->BagWidth &&
Y >= 0 && Y < BagConfig->BagShapeAsset->BagHeight;
}
FLinearColor SBagConfigGridWidget::GetCellColor(int32 X, int32 Y) const
{
if (!BagConfig.IsValid() || !BagConfig->BagShapeAsset)
{
return FLinearColor::Gray;
}
// 检查格子是否激活
if (!BagConfig->BagShapeAsset->IsSlotActive(X, Y))
{
return FLinearColor(0.2f, 0.2f, 0.2f, 1.0f); // 非激活格子为深灰色
}
// 检查是否被技能占用
int32 SkillIndex = BagConfig->GetSkillAtPosition(X, Y);
if (SkillIndex >= 0)
{
return FLinearColor(0, 0, 1, 1);
}
// 空闲格子为浅灰色
return FLinearColor(0.7f, 0.7f, 0.7f, 1.0f);
}
USkillAsset* SBagConfigGridWidget::GetSkillAtPosition(int32 X, int32 Y) const
{
if (!BagConfig.IsValid())
{
return nullptr;
}
int32 SkillIndex = BagConfig->GetSkillAtPosition(X, Y);
if (SkillIndex >= 0 && SkillIndex < BagConfig->PlacedSkills.Num())
{
return BagConfig->PlacedSkills[SkillIndex].SkillAsset;
}
return nullptr;
}
TSharedRef<SWidget> SBagConfigGridWidget::CreateSkillTooltip(USkillAsset* SkillAsset) const
{
if (!SkillAsset)
{
return SNullWidget::NullWidget;
}
return SNew(SBorder)
.BorderImage(FCoreStyle::Get().GetBrush("ToolTip.Background"))
.Padding(FMargin(8.0f))
[
SNew(SVerticalBox)
+ SVerticalBox::Slot()
.AutoHeight()
[
SNew(STextBlock)
.Text(SkillAsset->SkillName)
.Font(FCoreStyle::GetDefaultFontStyle("Bold", 12))
.ColorAndOpacity(FLinearColor::White)
]
+ SVerticalBox::Slot()
.AutoHeight()
.Padding(0, 4, 0, 0)
[
SNew(STextBlock)
.Text(SkillAsset->SkillDescription)
.Font(FCoreStyle::GetDefaultFontStyle("Regular", 10))
.ColorAndOpacity(FLinearColor(0.9f, 0.9f, 0.9f, 1.0f))
.WrapTextAt(250.0f)
]
];
}