From 1aeaa662a937b5edf43fbe207e5c21610820583b Mon Sep 17 00:00:00 2001 From: 997146918 <997146918@qq.com> Date: Sun, 31 Aug 2025 15:36:48 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E8=83=8C=E5=8C=85=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E4=B8=AD=E7=9A=84=E8=83=8C=E5=8C=85=E9=A2=84=E8=A7=88?= =?UTF-8?q?UI?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Private/Widgets/BagConfigEditorWidget.cpp | 370 +++++++++++------- .../Private/Widgets/BagConfigGridWidget.cpp | 14 + .../Public/Widgets/BagConfigEditorWidget.h | 18 +- .../Public/Widgets/BagConfigGridWidget.h | 65 +++ 4 files changed, 324 insertions(+), 143 deletions(-) create mode 100644 ProjectFish/Source/ProjectFishEditor/Private/Widgets/BagConfigGridWidget.cpp create mode 100644 ProjectFish/Source/ProjectFishEditor/Public/Widgets/BagConfigGridWidget.h diff --git a/ProjectFish/Source/ProjectFishEditor/Private/Widgets/BagConfigEditorWidget.cpp b/ProjectFish/Source/ProjectFishEditor/Private/Widgets/BagConfigEditorWidget.cpp index 88cb0df..38dfe32 100644 --- a/ProjectFish/Source/ProjectFishEditor/Private/Widgets/BagConfigEditorWidget.cpp +++ b/ProjectFish/Source/ProjectFishEditor/Private/Widgets/BagConfigEditorWidget.cpp @@ -6,6 +6,8 @@ #include "PropertyCustomizationHelpers.h" #include "Framework/Notifications/NotificationManager.h" #include "ProjectFish/DataAsset/BagShapeAsset.h" +#include "Widgets/BagConfigGridWidget.h" +#include "Widgets/BagShapeGridWidget.h" #include "Widgets/Notifications/SNotificationList.h" @@ -15,12 +17,12 @@ void SBagConfigEditorWidget::Construct(const FArguments& InArgs) SelectedSkillAsset = nullptr; bIsPlacingSkill = false; SelectedSkillIndex = -1; - + ChildSlot [ SNew(SVerticalBox) - // BagShapeAsset 选择器 + // 背包选择器 + SVerticalBox::Slot() .AutoHeight() .Padding(5.0f) @@ -88,140 +90,191 @@ void SBagConfigEditorWidget::Construct(const FArguments& InArgs) ] ] - // // 工具栏 - // + SVerticalBox::Slot() - // .AutoHeight() - // .Padding(5.0f) - // [ - // SNew(SHorizontalBox) - // - // + SHorizontalBox::Slot() - // .AutoWidth() - // .Padding(2.0f) - // [ - // SNew(SButton) - // .Text(FText::FromString(TEXT("Add Skill"))) - // .OnClicked(this, &SBagClassEditor::OnAddSkillClicked) - // .IsEnabled_Lambda([this]() { return BagClass.IsValid() && BagClass->BagShapeAsset != nullptr && SelectedSkillObject.IsValid(); }) - // ] - // - // + SHorizontalBox::Slot() - // .AutoWidth() - // .Padding(2.0f) - // [ - // SNew(SButton) - // .Text(FText::FromString(TEXT("Remove Selected"))) - // .OnClicked(this, &SBagClassEditor::OnRemoveSkillClicked) - // .IsEnabled_Lambda([this]() { return SelectedSkillObject.IsValid(); }) - // ] - // - // + SHorizontalBox::Slot() - // .AutoWidth() - // .Padding(2.0f) - // [ - // SNew(SButton) - // .Text(FText::FromString(TEXT("Clear All"))) - // .OnClicked(this, &SBagClassEditor::OnClearAllSkillsClicked) - // .IsEnabled_Lambda([this]() { return BagClass.IsValid() && BagClass->GetSkillCount() > 0; }) - // ] - // ] - // - // // 主编辑区域 - // + SVerticalBox::Slot() - // .FillHeight(1.0f) - // [ - // SNew(SSplitter) - // .Orientation(Orient_Horizontal) - // - // // 左侧:背包格子视图 - // + SSplitter::Slot() - // .Value(0.7f) - // [ - // SNew(SBox) - // .HAlign(HAlign_Center) - // .VAlign(VAlign_Center) - // .Padding(10.0f) - // [ - // SNew(SVerticalBox) - // - // + SVerticalBox::Slot() - // .AutoHeight() - // .HAlign(HAlign_Center) - // .Padding(0, 0, 0, 10) - // [ - // SNew(STextBlock) - // .Text_Lambda([this]() - // { - // if (!BagClass.IsValid()) - // { - // return FText::FromString(TEXT("No Bag Class")); - // } - // else if (!BagClass->BagShapeAsset) - // { - // return FText::FromString(TEXT("Please select a Bag Shape Asset above")); - // } - // else - // { - // return FText::FromString(FString::Printf(TEXT("Bag: %s (%dx%d)"), - // *BagClass->BagShapeAsset->GetName(), - // BagClass->BagShapeAsset->BagWidth, - // BagClass->BagShapeAsset->BagHeight)); - // } - // }) - // .Font(FCoreStyle::GetDefaultFontStyle("Bold", 12)) - // .ColorAndOpacity_Lambda([this]() - // { - // return (!BagClass.IsValid() || !BagClass->BagShapeAsset) ? - // FSlateColor(FLinearColor::Red) : FSlateColor(FLinearColor::White); - // }) - // ] - // - // + SVerticalBox::Slot() - // .AutoHeight() - // .HAlign(HAlign_Center) - // [ - // SAssignNew(BagGridWidget, SBagGridWidget) - // .BagClass(BagClass.Get()) - // .OnGridCellClicked(this, &SBagClassEditor::OnGridCellClicked) - // .Visibility_Lambda([this]() - // { - // return (BagClass.IsValid() && BagClass->BagShapeAsset) ? - // EVisibility::Visible : EVisibility::Hidden; - // }) - // ] - // ] - // ] - // - // // 右侧:技能列表 - // + SSplitter::Slot() - // .Value(0.3f) - // [ - // SNew(SVerticalBox) - // - // + SVerticalBox::Slot() - // .AutoHeight() - // .Padding(5.0f) - // [ - // SNew(STextBlock) - // .Text(FText::FromString(TEXT("Placed Skills:"))) - // .Font(FCoreStyle::GetDefaultFontStyle("Bold", 12)) - // ] - // - // + SVerticalBox::Slot() - // .FillHeight(1.0f) - // .Padding(5.0f) - // [ - // SAssignNew(SkillListWidget, SSkillListWidget) - // .BagClass(BagClass.Get()) - // .OnSkillSelected(this, &SBagClassEditor::OnSkillSelected) - // ] - // ] - //] + // 技能按钮 + + SVerticalBox::Slot() + .AutoHeight() + .Padding(5.0f) + [ + SNew(SHorizontalBox) + + + SHorizontalBox::Slot() + .AutoWidth() + .Padding(2.0f) + [ + SNew(SButton) + .Text(FText::FromString(TEXT("点击后,单击背包添加当前选中的技能"))) + .OnClicked(this, &SBagConfigEditorWidget::OnAddSkillClicked) + .IsEnabled_Lambda([this]() { return BagConfig.IsValid() && BagConfig->BagShapeAsset != nullptr && SelectedSkillAsset.IsValid(); }) + ] + + + SHorizontalBox::Slot() + .AutoWidth() + .Padding(2.0f) + [ + SNew(SButton) + .Text(FText::FromString(TEXT("点击后,单击背包移除当前选中的技能"))) + .OnClicked(this, &SBagConfigEditorWidget::OnRemoveSkillClicked) + .IsEnabled_Lambda([this]() { return SelectedSkillAsset.IsValid(); }) + ] + + + SHorizontalBox::Slot() + .AutoWidth() + .Padding(2.0f) + [ + SNew(SButton) + .Text(FText::FromString(TEXT("移除所有技能"))) + .OnClicked(this, &SBagConfigEditorWidget::OnClearAllSkillsClicked) + .IsEnabled_Lambda([this]() { return BagConfig.IsValid() && BagConfig->GetSkillCount() > 0; }) + ] + ] + + // 主编辑区域 + + SVerticalBox::Slot() + .FillHeight(1.0f) + [ + SNew(SSplitter) + .Orientation(Orient_Horizontal) + + // 左侧:背包格子视图 + + SSplitter::Slot() + .Value(0.7f) + [ + SNew(SBox) + .HAlign(HAlign_Center) + .VAlign(VAlign_Center) + .Padding(10.0f) + [ + SNew(SVerticalBox) + + + SVerticalBox::Slot() + .AutoHeight() + .HAlign(HAlign_Center) + .Padding(0, 0, 0, 10) + [ + SNew(STextBlock) + .Text_Lambda([this]() + { + if (!BagConfig.IsValid()) + { + return FText::FromString(TEXT("No Bag Class")); + } + else if (!BagConfig->BagShapeAsset) + { + return FText::FromString(TEXT("Please select a Bag Shape Asset above")); + } + else + { + return FText::FromString(FString::Printf(TEXT("Bag: %s (%dx%d)"), + *BagConfig->BagShapeAsset->GetName(), + BagConfig->BagShapeAsset->BagWidth, + BagConfig->BagShapeAsset->BagHeight)); + } + }) + .Font(FCoreStyle::GetDefaultFontStyle("Bold", 12)) + .ColorAndOpacity_Lambda([this]() + { + return (!BagConfig.IsValid() || !BagConfig->BagShapeAsset) ? + FSlateColor(FLinearColor::Red) : FSlateColor(FLinearColor::White); + }) + ] + + + SVerticalBox::Slot() + .AutoHeight() + .HAlign(HAlign_Center) + [ + SAssignNew(BagGridWidget, SBagConfigGridWidget) + .BagConfig(BagConfig.Get()) + .OnGridCellClicked(this, &SBagConfigEditorWidget::OnGridCellClicked) + .Visibility_Lambda([this]() + { + return (BagConfig.IsValid() && BagConfig->BagShapeAsset) ? + EVisibility::Visible : EVisibility::Hidden; + }) + ] + ] + ] + + // // 右侧:技能列表 + // + SSplitter::Slot() + // .Value(0.3f) + // [ + // SNew(SVerticalBox) + // + // + SVerticalBox::Slot() + // .AutoHeight() + // .Padding(5.0f) + // [ + // SNew(STextBlock) + // .Text(FText::FromString(TEXT("Placed Skills:"))) + // .Font(FCoreStyle::GetDefaultFontStyle("Bold", 12)) + // ] + // + // + SVerticalBox::Slot() + // .FillHeight(1.0f) + // .Padding(5.0f) + // [ + // SAssignNew(SkillListWidget, SSkillListWidget) + // .BagClass(BagClass.Get()) + // .OnSkillSelected(this, &SBagClassEditor::OnSkillSelected) + // ] + // ] + ] ]; RefreshUI(); } +FReply SBagConfigEditorWidget::OnAddSkillClicked() +{ + if (!BagConfig.IsValid() || !BagConfig->BagShapeAsset || !SelectedSkillAsset.IsValid()) + { + ShowWarningMessage(TEXT("Please select a bag shape asset and a skill object first!")); + return FReply::Handled(); + } + + // 进入放置模式 + bIsPlacingSkill = true; + ShowWarningMessage(TEXT("Click on the grid to place the skill")); + + return FReply::Handled(); +} + +FReply SBagConfigEditorWidget::OnRemoveSkillClicked() +{ + if (!BagConfig.IsValid() || SelectedSkillIndex < 0) + { + return FReply::Handled(); + } + + if (BagConfig->RemoveSkill(SelectedSkillIndex)) + { + SelectedSkillIndex = -1; + RefreshUI(); + + // 标记资源为已修改 + BagConfig->MarkPackageDirty(); + } + + return FReply::Handled(); +} + +FReply SBagConfigEditorWidget::OnClearAllSkillsClicked() +{ + if (!BagConfig.IsValid()) + { + return FReply::Handled(); + } + + BagConfig->ClearAllSkills(); + SelectedSkillIndex = -1; + RefreshUI(); + + // 标记资源为已修改 + BagConfig->MarkPackageDirty(); + + return FReply::Handled(); +} + void SBagConfigEditorWidget::OnBagShapeAssetChanged(const FAssetData& AssetData) { if (!BagConfig.IsValid()) @@ -267,13 +320,58 @@ void SBagConfigEditorWidget::OnSkillAssetChanged(const FAssetData& AssetData) SelectedSkillAsset = Cast(AssetData.GetAsset()); } +void SBagConfigEditorWidget::OnGridCellClicked(int32 X, int32 Y) +{ + if (!BagConfig.IsValid()) + { + return; + } + + if (bIsPlacingSkill && SelectedSkillAsset.IsValid()) + { + // 尝试在指定位置放置技能 + if (BagConfig->CanPlaceSkill(SelectedSkillAsset.Get(), X, Y)) + { + if (BagConfig->AddSkill(SelectedSkillAsset.Get(), X, Y)) + { + BagConfig->MarkPackageDirty(); + RefreshUI(); + ShowWarningMessage(FString::Printf(TEXT("Successfully placed skill '%s' at (%d,%d)"), + *SelectedSkillAsset->SkillName.ToString(), X, Y)); + + // 退出放置模式 + bIsPlacingSkill = false; + } + else + { + ShowWarningMessage(TEXT("Failed to place skill!")); + } + } + else + { + ShowWarningMessage(TEXT("Cannot place skill at this position!")); + } + } + else + { + // // 选择现有技能 + // int32 SkillIndex = BagConfig->GetSkillAtPosition(X, Y); + // SelectedSkillIndex = SkillIndex; + // + // if (SkillListWidget.IsValid()) + // { + // SkillListWidget->SetSelectedSkill(SkillIndex); + // } + } +} + void SBagConfigEditorWidget::RefreshUI() { - // if (BagGridWidget.IsValid()) - // { - // BagGridWidget->RefreshGrid(); - // } - // + if (BagGridWidget.IsValid()) + { + BagGridWidget->RefreshGrid(); + } + // if (SkillListWidget.IsValid()) // { // SkillListWidget->RefreshSkillList(); diff --git a/ProjectFish/Source/ProjectFishEditor/Private/Widgets/BagConfigGridWidget.cpp b/ProjectFish/Source/ProjectFishEditor/Private/Widgets/BagConfigGridWidget.cpp new file mode 100644 index 0000000..b6c458e --- /dev/null +++ b/ProjectFish/Source/ProjectFishEditor/Private/Widgets/BagConfigGridWidget.cpp @@ -0,0 +1,14 @@ +// Fill out your copyright notice in the Description page of Project Settings. + + +#include "Widgets/BagConfigGridWidget.h" + + + +void SBagConfigGridWidget::Construct(const FArguments& InArgs) +{ +} + +void SBagConfigGridWidget::RefreshGrid() +{ +} diff --git a/ProjectFish/Source/ProjectFishEditor/Public/Widgets/BagConfigEditorWidget.h b/ProjectFish/Source/ProjectFishEditor/Public/Widgets/BagConfigEditorWidget.h index 4673655..37ca0b1 100644 --- a/ProjectFish/Source/ProjectFishEditor/Public/Widgets/BagConfigEditorWidget.h +++ b/ProjectFish/Source/ProjectFishEditor/Public/Widgets/BagConfigEditorWidget.h @@ -34,13 +34,13 @@ private: int32 SelectedSkillIndex; // UI组件 - TSharedPtr BagGridWidget; + TSharedPtr BagGridWidget; //TSharedPtr SkillListWidget; - // // 回调函数 - // FReply OnAddSkillClicked(); - // FReply OnRemoveSkillClicked(); - // FReply OnClearAllSkillsClicked(); + // 回调函数 + FReply OnAddSkillClicked(); + FReply OnRemoveSkillClicked(); + FReply OnClearAllSkillsClicked(); // BagShapeAsset选择回调 void OnBagShapeAssetChanged(const FAssetData& AssetData); @@ -51,8 +51,8 @@ private: // // 技能选择回调 // void OnSkillSelected(int32 SkillIndex); // - // // 格子点击回调 - // void OnGridCellClicked(int32 X, int32 Y); + // 格子点击回调 + void OnGridCellClicked(int32 X, int32 Y); // 刷新UI void RefreshUI(); @@ -62,3 +62,7 @@ private: }; + + + + diff --git a/ProjectFish/Source/ProjectFishEditor/Public/Widgets/BagConfigGridWidget.h b/ProjectFish/Source/ProjectFishEditor/Public/Widgets/BagConfigGridWidget.h new file mode 100644 index 0000000..1dff9b9 --- /dev/null +++ b/ProjectFish/Source/ProjectFishEditor/Public/Widgets/BagConfigGridWidget.h @@ -0,0 +1,65 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "ProjectFish/DataAsset/BagConfigAsset.h" + +DECLARE_DELEGATE_TwoParams(FOnGridCellClicked, int32, int32); +/** + * + */ +class PROJECTFISHEDITOR_API SBagConfigGridWidget : public SCompoundWidget +{ +public: + SLATE_BEGIN_ARGS(SBagConfigGridWidget) {} + SLATE_ARGUMENT(UBagConfigAsset*, BagConfig) + SLATE_EVENT(FOnGridCellClicked, OnGridCellClicked) +SLATE_END_ARGS() + + void Construct(const FArguments& InArgs); + + // // 设置背包类 + // void UpdateBagConfig(UBagConfigAsset* InBagClass); + // + // // 设置预览技能(用于显示放置预览) + // void SetPreviewSkill(USkillAsset* InPreviewSkill, int32 PreviewX, int32 PreviewY); + // + // // 清除预览 + // void ClearPreview(); + // + // 刷新显示 + void RefreshGrid(); + +protected: + // // Slate重写函数 + // virtual FReply OnMouseButtonDown(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override; + // virtual FReply OnMouseMove(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: + // 背包类引用 + TWeakObjectPtr BagClass; + + // 回调委托 + FOnGridCellClicked OnGridCellClicked; + + // 预览数据 + TWeakObjectPtr PreviewSkill; + int32 PreviewX; + int32 PreviewY; + + // UI参数 + static const float CellSize; + static const float CellSpacing; + + // // 工具函数 + // FVector2D GetCellPosition(int32 X, int32 Y) const; + // FVector2D GetGridCellFromPosition(const FVector2D& Position) const; + // bool IsValidGridPosition(int32 X, int32 Y) const; + // FLinearColor GetCellColor(int32 X, int32 Y) const; + // int32 GetSkillAtPosition(int32 X, int32 Y) const; +};