2025-08-31 15:36:48 +08:00
|
|
|
// Fill out your copyright notice in the Description page of Project Settings.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include "Widgets/BagConfigGridWidget.h"
|
|
|
|
|
|
2025-08-31 15:49:07 +08:00
|
|
|
#include "ProjectFish/DataAsset/BagShapeAsset.h"
|
2025-08-31 15:36:48 +08:00
|
|
|
|
2025-08-31 15:49:07 +08:00
|
|
|
const float SBagConfigGridWidget::CellSize = 32.0f;
|
|
|
|
|
const float SBagConfigGridWidget::CellSpacing = 2.0f;
|
2025-08-31 15:36:48 +08:00
|
|
|
|
|
|
|
|
void SBagConfigGridWidget::Construct(const FArguments& InArgs)
|
|
|
|
|
{
|
2025-08-31 15:49:07 +08:00
|
|
|
BagConfig = InArgs._BagConfig;
|
|
|
|
|
OnGridCellClicked = InArgs._OnGridCellClicked;
|
|
|
|
|
PreviewSkill = nullptr;
|
|
|
|
|
PreviewX = -1;
|
|
|
|
|
PreviewY = -1;
|
2025-09-16 13:04:32 +08:00
|
|
|
HoveredSkillIndex = -1;
|
2025-08-31 15:49:07 +08:00
|
|
|
|
|
|
|
|
ChildSlot
|
|
|
|
|
[
|
|
|
|
|
SNew(SOverlay)
|
|
|
|
|
];
|
2025-08-31 15:36:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SBagConfigGridWidget::RefreshGrid()
|
|
|
|
|
{
|
2025-08-31 15:49:07 +08:00
|
|
|
// 强制重绘
|
|
|
|
|
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)
|
|
|
|
|
{
|
2025-09-16 13:04:32 +08:00
|
|
|
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();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-31 15:49:07 +08:00
|
|
|
return FReply::Unhandled();
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-16 13:04:32 +08:00
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-31 15:49:07 +08:00
|
|
|
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);
|
2025-08-31 15:36:48 +08:00
|
|
|
}
|
2025-09-16 13:04:32 +08:00
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
]
|
|
|
|
|
];
|
|
|
|
|
}
|