// Fill out your copyright notice in the Description page of Project Settings. #include "Thumbnail/BagConfigThumbnailRenderer.h" #include "CanvasItem.h" #include "CanvasTypes.h" #include "ProjectFish/DataAsset/BagConfigAsset.h" #include "ProjectFish/DataAsset/ShapeAsset.h" bool UBagConfigThumbnailRenderer::CanVisualizeAsset(UObject* Object) { return Cast(Object) != nullptr; } void UBagConfigThumbnailRenderer::Draw(UObject* Object, int32 X, int32 Y, uint32 Width, uint32 Height, FRenderTarget* RenderTarget, FCanvas* Canvas, bool bAdditionalViewFamily) { UBagConfigAsset* BagConfig= Cast(Object); if (!BagConfig || !Canvas) { return; } DrawBag(BagConfig, Canvas, X, Y, Width, Height); } void UBagConfigThumbnailRenderer::DrawBag(UBagConfigAsset* BagConfig, FCanvas* Canvas, int32 X, int32 Y, uint32 Width, uint32 Height) { if (!BagConfig || !Canvas) { return; } // 检查是否有背包形状资源 if (!BagConfig->BagShapeAsset) { // 绘制错误状态 FCanvasBoxItem ErrorBox(FVector2D(X, Y), FVector2D(Width, Height)); ErrorBox.SetColor(FLinearColor(0.5f, 0.1f, 0.1f, 1.0f)); Canvas->DrawItem(ErrorBox); return; } UShapeAsset* BagShapeAsset = BagConfig->BagShapeAsset; // Clear the background FCanvasBoxItem BackgroundBox(FVector2D(X, Y), FVector2D(Width, Height)); BackgroundBox.SetColor(FLinearColor(0.1f, 0.1f, 0.1f, 1.0f)); Canvas->DrawItem(BackgroundBox); // Calculate the best fit scale with spacing for separators float SeparatorWidth = 2.0f; // White separator width float Scale = GetBestFitScale(BagShapeAsset->ShapeWidth, BagShapeAsset->ShapeHeight, Width, Height); float CellSize = Scale - SeparatorWidth; // Reduce cell size to make room for separators // Calculate starting position to center the grid (including separators) float GridWidth = BagShapeAsset->ShapeWidth * Scale - SeparatorWidth; float GridHeight = BagShapeAsset->ShapeHeight * Scale - SeparatorWidth; float StartX = X + (Width - GridWidth) * 0.5f; float StartY = Y + (Height - GridHeight) * 0.5f; // Draw the bag slots (background) with separators for (int32 GridY = 0; GridY < BagShapeAsset->ShapeHeight; GridY++) { for (int32 GridX = 0; GridX < BagShapeAsset->ShapeWidth; GridX++) { float CellStartX = StartX + GridX * Scale; float CellStartY = StartY + GridY * Scale; bool bIsActive = BagShapeAsset->IsSlotActive(GridX, GridY); // Draw filled cell (smaller to leave space for separators) FCanvasTileItem CellTile(FVector2D(CellStartX, CellStartY), FVector2D(CellSize, CellSize), bIsActive ? FLinearColor(0.3f, 0.3f, 0.3f, 1.0f) : FLinearColor(0.15f, 0.15f, 0.15f, 1.0f)); CellTile.BlendMode = SE_BLEND_Opaque; Canvas->DrawItem(CellTile); } } // Draw white separators // Vertical separators for (int32 GridX = 1; GridX < BagShapeAsset->ShapeWidth; GridX++) { float SeparatorX = StartX + GridX * Scale - SeparatorWidth; FCanvasTileItem VerticalSeparator(FVector2D(SeparatorX, StartY), FVector2D(SeparatorWidth, GridHeight), FLinearColor::White); VerticalSeparator.BlendMode = SE_BLEND_Opaque; Canvas->DrawItem(VerticalSeparator); } // Horizontal separators for (int32 GridY = 1; GridY < BagShapeAsset->ShapeHeight; GridY++) { float SeparatorY = StartY + GridY * Scale - SeparatorWidth; FCanvasTileItem HorizontalSeparator(FVector2D(StartX, SeparatorY), FVector2D(GridWidth, SeparatorWidth), FLinearColor::White); HorizontalSeparator.BlendMode = SE_BLEND_Opaque; Canvas->DrawItem(HorizontalSeparator); } // Draw skills on top for (const FPlacedSkillInfo& PlacedSkill : BagConfig->PlacedSkills) { DrawSkill(PlacedSkill, Canvas, StartX, StartY, Scale, SeparatorWidth); } // Draw outer border FCanvasBoxItem OuterBorder(FVector2D(StartX, StartY), FVector2D(GridWidth, GridHeight)); OuterBorder.SetColor(FLinearColor::White); OuterBorder.LineThickness = 3.0f; Canvas->DrawItem(OuterBorder); } float UBagConfigThumbnailRenderer::GetBestFitScale(int32 ShapeWidth, int32 ShapeHeight, uint32 CanvasWidth, uint32 CanvasHeight) const { if (ShapeWidth == 0 || ShapeHeight == 0) { return 1.0f; } // Leave some padding float PaddedWidth = CanvasWidth * 0.85f; float PaddedHeight = CanvasHeight * 0.85f; float ScaleX = PaddedWidth / ShapeWidth; float ScaleY = PaddedHeight / ShapeHeight; // Use the smaller scale to ensure everything fits float Scale = FMath::Min(ScaleX, ScaleY); // Ensure minimum cell size for visibility Scale = FMath::Max(Scale, 3.0f); return Scale; } void UBagConfigThumbnailRenderer::DrawSkill(const struct FPlacedSkillInfo& PlacedSkill, FCanvas* Canvas, float StartX, float StartY, float Scale, float SeparatorWidth) { if (!PlacedSkill.SkillAsset) { return; } USkillAsset* SkillObject = PlacedSkill.SkillAsset; float CellSize = Scale - SeparatorWidth; float SkillStartX = StartX + PlacedSkill.PositionX * Scale; float SkillStartY = StartY + PlacedSkill.PositionY * Scale; float SkillWidth = GetSkillSizeValue(SkillObject->SkillSize).X * Scale - SeparatorWidth; float SkillHeight = GetSkillSizeValue(SkillObject->SkillSize).Y * Scale - SeparatorWidth; // Draw skill background FCanvasTileItem SkillTile(FVector2D(SkillStartX, SkillStartY), FVector2D(SkillWidth, SkillHeight), FLinearColor::Blue); SkillTile.BlendMode = SE_BLEND_Opaque; Canvas->DrawItem(SkillTile); // Draw skill border FCanvasBoxItem SkillBorder(FVector2D(SkillStartX, SkillStartY), FVector2D(SkillWidth, SkillHeight)); SkillBorder.SetColor(FLinearColor::White); SkillBorder.LineThickness = 2.0f; Canvas->DrawItem(SkillBorder); // Draw skill name (if there's enough space) if (CellSize >= 12.0f && !SkillObject->SkillName.ToString().IsEmpty()) { FString DisplayName = SkillObject->SkillName.ToString(); if (DisplayName.Len() > 8) { DisplayName = DisplayName.Left(6) + TEXT(".."); } FCanvasTextItem TextItem(FVector2D(SkillStartX + 2, SkillStartY + 2), FText::FromString(DisplayName), GEngine->GetSmallFont(), FLinearColor::White); TextItem.Scale = FVector2D(0.7f, 0.7f); Canvas->DrawItem(TextItem); } }