添加背包形状编辑器UI

This commit is contained in:
997146918 2025-08-30 18:03:42 +08:00
parent 445f21fe7b
commit bd75d739f1
5 changed files with 474 additions and 1 deletions

View File

@ -2,9 +2,238 @@
#include "Widgets/BagShapeEditorWidget.h" #include "Widgets/BagShapeEditorWidget.h"
#include "Widgets/Input/SSpinBox.h"
#include "EditorStyleSet.h"
void SBagShapeEditorWidget::Construct(const FArguments& InArgs) void SBagShapeEditorWidget::Construct(const FArguments& InArgs)
{ {
BagShapeAsset = InArgs._BagShapeAsset; BagShapeAsset = InArgs._BagShapeAsset;
ChildSlot
[
SNew(SSplitter)
.Orientation(Orient_Vertical)
+ SSplitter::Slot()
.Value(0.2f)
[
CreateSizeControls()
]
+ SSplitter::Slot()
.Value(0.1f)
[
CreateGridControls()
]
+ SSplitter::Slot()
.Value(0.7f)
[
SNew(SScrollBox)
+ SScrollBox::Slot()
[
SNew(SBorder)
.BorderImage(FEditorStyle::GetBrush("ToolPanel.GroupBorder"))
.Padding(10.0f)
[
SNew(SBox)
.HAlign(HAlign_Center)
.VAlign(VAlign_Center)
[
SAssignNew(GridWidget, SBagShapeGridWidget)
.BagShapeAsset(BagShapeAsset.Get())
.OnSlotClicked(this, &SBagShapeEditorWidget::OnSlotClicked)
]
]
]
]
];
}
void SBagShapeEditorWidget::RefreshGrid()
{
if (GridWidget.IsValid())
{
GridWidget->UpdateBagShapeAsset(BagShapeAsset.Get());
}
}
TSharedRef<SWidget> SBagShapeEditorWidget::CreateSizeControls()
{
return SNew(SBorder)
.BorderImage(FEditorStyle::GetBrush("ToolPanel.GroupBorder"))
.Padding(10.0f)
[
SNew(SVerticalBox)
+ SVerticalBox::Slot()
.AutoHeight()
.Padding(0, 5)
[
SNew(STextBlock)
.Text(FText::FromString("Bag Size Settings"))
.Font(FCoreStyle::GetDefaultFontStyle("Bold", 14))
]
+ SVerticalBox::Slot()
.AutoHeight()
.Padding(0, 5)
[
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.AutoWidth()
.VAlign(VAlign_Center)
.Padding(0, 0, 10, 0)
[
SNew(STextBlock)
.Text(FText::FromString("Width:"))
]
+ SHorizontalBox::Slot()
.AutoWidth()
[
SNew(SBox)
.WidthOverride(100.0f)
[
SNew(SSpinBox<int32>)
.MinValue(1)
.MaxValue(10)
.Value(this, &SBagShapeEditorWidget::GetBagWidth)
.OnValueChanged(this, &SBagShapeEditorWidget::OnWidthChanged)
]
]
+ SHorizontalBox::Slot()
.AutoWidth()
.VAlign(VAlign_Center)
.Padding(20, 0, 10, 0)
[
SNew(STextBlock)
.Text(FText::FromString("Width:"))
]
+ SHorizontalBox::Slot()
.AutoWidth()
[
SNew(SBox)
.WidthOverride(100.0f)
[
SNew(SSpinBox<int32>)
.MinValue(1)
.MaxValue(10)
.Value(this, &SBagShapeEditorWidget::GetBagHeight)
.OnValueChanged(this, &SBagShapeEditorWidget::OnHeightChanged)
]
]
]
];
}
int32 SBagShapeEditorWidget::GetBagWidth() const
{
return BagShapeAsset.IsValid() ? BagShapeAsset->BagWidth : 5;
}
int32 SBagShapeEditorWidget::GetBagHeight() const
{
return BagShapeAsset.IsValid() ? BagShapeAsset->BagHeight : 5;
}
void SBagShapeEditorWidget::OnWidthChanged(int32 NewWidth)
{
if (BagShapeAsset.IsValid() && NewWidth != BagShapeAsset->BagWidth)
{
BagShapeAsset->BagWidth = NewWidth;
BagShapeAsset->InitializeBagShape();
BagShapeAsset->MarkPackageDirty();
RefreshGrid();
}
}
void SBagShapeEditorWidget::OnHeightChanged(int32 NewHeight)
{
if (BagShapeAsset.IsValid() && NewHeight != BagShapeAsset->BagHeight)
{
BagShapeAsset->BagHeight = NewHeight;
BagShapeAsset->InitializeBagShape();
BagShapeAsset->MarkPackageDirty();
RefreshGrid();
}
}
TSharedRef<SWidget> SBagShapeEditorWidget::CreateGridControls()
{
return SNew(SBorder)
.BorderImage(FEditorStyle::GetBrush("ToolPanel.GroupBorder"))
.Padding(10.0f)
[
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.AutoWidth()
.Padding(0, 0, 10, 0)
[
SNew(SButton)
.Text(FText::FromString("All Enable"))
.OnClicked(this, &SBagShapeEditorWidget::OnAllEnableClicked)
]
+ SHorizontalBox::Slot()
.AutoWidth()
.Padding(0, 0, 10, 0)
[
SNew(SButton)
.Text(FText::FromString("All Disable"))
.OnClicked(this, &SBagShapeEditorWidget::OnAllDisableClicked)
]
];
}
FReply SBagShapeEditorWidget::OnAllEnableClicked()
{
if (BagShapeAsset.IsValid())
{
BagShapeAsset->InitializeBagShape();
BagShapeAsset->MarkPackageDirty();
RefreshGrid();
RefreshThumbnail();
}
return FReply::Handled();
}
FReply SBagShapeEditorWidget::OnAllDisableClicked()
{
if (BagShapeAsset.IsValid())
{
for (int32 X = 0; X < BagShapeAsset->BagWidth; X++)
{
for (int32 Y = 0; Y < BagShapeAsset->BagHeight; Y++)
{
BagShapeAsset->SetSlotActive(X, Y, false);
}
}
BagShapeAsset->MarkPackageDirty();
RefreshGrid();
RefreshThumbnail();
}
return FReply::Handled();
}
void SBagShapeEditorWidget::OnSlotClicked(int32 X, int32 Y)
{
if (!BagShapeAsset.IsValid())
{
return;
}
bool bCurrentState = BagShapeAsset->IsSlotActive(X, Y);
BagShapeAsset->SetSlotActive(X, Y, !bCurrentState);
// Refresh the grid widget
if (GridWidget.IsValid())
{
GridWidget->UpdateBagShapeAsset(BagShapeAsset.Get());
}
// Mark the asset as modified
BagShapeAsset->MarkPackageDirty();
// 强制刷新缩略图
RefreshThumbnail();
}
void SBagShapeEditorWidget::RefreshThumbnail()
{
} }

View File

@ -0,0 +1,177 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "Widgets/BagShapeGridWidget.h"
const float SBagShapeGridWidget::CellSize = 32.0f;
const float SBagShapeGridWidget::SeparatorWidth = 2.0f;
void SBagShapeGridWidget::Construct(const FArguments& InArgs)
{
BagShapeAsset = InArgs._BagShapeAsset;
OnSlotClicked = InArgs._OnSlotClicked;
}
void SBagShapeGridWidget::UpdateBagShapeAsset(UBagShapeAsset* InBagShapeAsset)
{
BagShapeAsset = InBagShapeAsset;
Invalidate(EInvalidateWidget::Paint);
}
FReply SBagShapeGridWidget::OnMouseButtonDown(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
{
if (MouseEvent.GetEffectingButton() == EKeys::LeftMouseButton && BagShapeAsset.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))
{
OnSlotClicked.ExecuteIfBound(GridX, GridY);
return FReply::Handled();
}
}
return FReply::Unhandled();
}
int32 SBagShapeGridWidget::OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry,
const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId,
const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const
{
if (!BagShapeAsset.IsValid())
{
return LayerId;
}
// Calculate grid dimensions with separators
float Scale = CellSize + SeparatorWidth;
float GridWidth = BagShapeAsset->BagWidth * Scale - SeparatorWidth;
float GridHeight = BagShapeAsset->BagHeight * Scale - SeparatorWidth;
// Center the grid in the available space
FVector2D GridStartPos = FVector2D(
(AllottedGeometry.GetLocalSize().X - GridWidth) * 0.5f,
(AllottedGeometry.GetLocalSize().Y - GridHeight) * 0.5f
);
// Draw background
FSlateDrawElement::MakeBox(
OutDrawElements,
LayerId,
AllottedGeometry.ToPaintGeometry(AllottedGeometry.GetLocalSize(), FSlateLayoutTransform()),
FCoreStyle::Get().GetBrush("WhiteBrush"),
ESlateDrawEffect::None,
FLinearColor(0.1f, 0.1f, 0.1f, 1.0f)
);
// Draw cells
for (int32 Y = 0; Y < BagShapeAsset->BagHeight; Y++)
{
for (int32 X = 0; X < BagShapeAsset->BagWidth; X++)
{
FVector2D CellPos = GridStartPos + FVector2D(X * Scale, Y * Scale);
bool bIsActive = BagShapeAsset->IsSlotActive(X, Y);
// Draw cell background
FLinearColor CellColor = bIsActive ? FLinearColor(0.2f, 0.8f, 0.2f, 1.0f) : FLinearColor(0.15f, 0.15f, 0.15f, 1.0f);
FSlateDrawElement::MakeBox(
OutDrawElements,
LayerId + 1,
AllottedGeometry.ToPaintGeometry(FVector2D(CellSize, CellSize), FSlateLayoutTransform(CellPos)),
FCoreStyle::Get().GetBrush("WhiteBrush"),
ESlateDrawEffect::None,
CellColor
);
}
}
// Draw vertical separators
for (int32 X = 1; X < BagShapeAsset->BagWidth; X++)
{
float SeparatorX = GridStartPos.X + X * Scale - SeparatorWidth;
FSlateDrawElement::MakeBox(
OutDrawElements,
LayerId + 2,
AllottedGeometry.ToPaintGeometry(FVector2D(SeparatorWidth, GridHeight), FSlateLayoutTransform(FVector2D(SeparatorX, GridStartPos.Y))),
FCoreStyle::Get().GetBrush("WhiteBrush"),
ESlateDrawEffect::None,
FLinearColor::White
);
}
// Draw horizontal separators
for (int32 Y = 1; Y < BagShapeAsset->BagHeight; Y++)
{
float SeparatorY = GridStartPos.Y + Y * Scale - SeparatorWidth;
FSlateDrawElement::MakeBox(
OutDrawElements,
LayerId + 2,
AllottedGeometry.ToPaintGeometry(FVector2D(GridWidth, SeparatorWidth), FSlateLayoutTransform(FVector2D(GridStartPos.X, SeparatorY))),
FCoreStyle::Get().GetBrush("WhiteBrush"),
ESlateDrawEffect::None,
FLinearColor::White
);
}
// Draw outer border
FSlateDrawElement::MakeBox(
OutDrawElements,
LayerId + 3,
AllottedGeometry.ToPaintGeometry(FVector2D(GridWidth, GridHeight), FSlateLayoutTransform(GridStartPos)),
FCoreStyle::Get().GetBrush("Border"),
ESlateDrawEffect::None,
FLinearColor::White
);
return LayerId + 4;
}
FVector2D SBagShapeGridWidget::ComputeDesiredSize(float X) const
{
if (!BagShapeAsset.IsValid())
{
return FVector2D(200, 200);
}
float Scale = CellSize + SeparatorWidth;
return FVector2D(
BagShapeAsset->BagWidth * Scale - SeparatorWidth + 20.0f, // Add padding
BagShapeAsset->BagHeight * Scale - SeparatorWidth + 20.0f
);
}
FVector2D SBagShapeGridWidget::GetGridCellFromPosition(const FVector2D& Position) const
{
if (!BagShapeAsset.IsValid())
{
return FVector2D(-1, -1);
}
float Scale = CellSize + SeparatorWidth;
float GridWidth = BagShapeAsset->BagWidth * Scale - SeparatorWidth;
float GridHeight = BagShapeAsset->BagHeight * Scale - SeparatorWidth;
FVector2D GridStartPos = FVector2D(
(GetCachedGeometry().GetLocalSize().X - GridWidth) * 0.5f,
(GetCachedGeometry().GetLocalSize().Y - GridHeight) * 0.5f
);
FVector2D RelativePos = Position - GridStartPos;
return FVector2D(
RelativePos.X / Scale,
RelativePos.Y / Scale
);
}
bool SBagShapeGridWidget::IsValidGridPosition(int32 X, int32 Y) const
{
if (!BagShapeAsset.IsValid())
{
return false;
}
return X >= 0 && X < BagShapeAsset->BagWidth && Y >= 0 && Y < BagShapeAsset->BagHeight;
}

View File

@ -23,7 +23,8 @@ public class ProjectFishEditor : ModuleRules
"ProjectFish", "ProjectFish",
"InputCore", "InputCore",
"AssetTools", "AssetTools",
"UnrealEd" "UnrealEd",
"EditorStyle"
} }
); );
} }

View File

@ -3,6 +3,7 @@
#pragma once #pragma once
#include "CoreMinimal.h" #include "CoreMinimal.h"
#include "BagShapeGridWidget.h"
#include "ProjectFish/DataAsset/BagShapeAsset.h" #include "ProjectFish/DataAsset/BagShapeAsset.h"
/** /**
@ -16,6 +17,32 @@ public:
SLATE_END_ARGS() SLATE_END_ARGS()
void Construct(const FArguments& InArgs); void Construct(const FArguments& InArgs);
private:
/** Refresh the grid display */
void RefreshGrid();
//背包大小UI
TSharedRef<SWidget> CreateSizeControls();
/** Get the current bag width */
int32 GetBagWidth() const;
/** Get the current bag height */
int32 GetBagHeight() const;
/** Handle width spin box value change */
void OnWidthChanged(int32 NewWidth);
/** Handle height spin box value change */
void OnHeightChanged(int32 NewHeight);
//重置背包状态
TSharedRef<SWidget> CreateGridControls();
FReply OnAllEnableClicked();
FReply OnAllDisableClicked();
//点击背包格子
void OnSlotClicked(int32 X, int32 Y);
//刷新图标
void RefreshThumbnail();
private: private:
TWeakObjectPtr<class UBagShapeAsset> BagShapeAsset; TWeakObjectPtr<class UBagShapeAsset> BagShapeAsset;
TSharedPtr<SBagShapeGridWidget> GridWidget;
}; };

View File

@ -0,0 +1,39 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "ProjectFish/DataAsset/BagShapeAsset.h"
DECLARE_DELEGATE_TwoParams(FOnSlotClicked, int32, int32);
/**
*
*/
class SBagShapeGridWidget : public SCompoundWidget
{
public:
SLATE_BEGIN_ARGS(SBagShapeGridWidget) {}
SLATE_ARGUMENT(UBagShapeAsset*, BagShapeAsset)
SLATE_EVENT(FOnSlotClicked, OnSlotClicked)
SLATE_END_ARGS()
void Construct(const FArguments& InArgs);
void UpdateBagShapeAsset(UBagShapeAsset* InBagShapeAsset);
// SWidget interface
virtual FReply OnMouseButtonDown(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override;
virtual int32 OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyCullingRect,
FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const override;
virtual FVector2D ComputeDesiredSize(float) const override;
private:
static const float CellSize;
static const float SeparatorWidth;
TWeakObjectPtr<UBagShapeAsset> BagShapeAsset;
FOnSlotClicked OnSlotClicked;
FVector2D GetGridCellFromPosition(const FVector2D& Position) const;
bool IsValidGridPosition(int32 X, int32 Y) const;
};