Started rework of clothing slots and UI

This commit is contained in:
2026-05-26 18:52:37 +03:00
parent 38161ee4a2
commit 878060d7ac
37 changed files with 280 additions and 152 deletions
+7
View File
@@ -4,6 +4,13 @@ bAutoLoadData=True
[/Script/EngineSettings.GeneralProjectSettings]
ProjectID=305A61484AE3739092FF13931B45C2C6
ProjectName=Naked Desire
CompanyName=Naked People Team
CompanyDistinguishedName=Naked People Team
Homepage=naked-people-team.in
CopyrightNotice=© 2025 Naked People Team. All Rights Reserved.
ProjectDisplayedTitle=NSLOCTEXT("[/Script/EngineSettings]", "67F2166BC54742EF9F59D9A524233B35", "Naked Desire")
ProjectDebugTitleInfo=NSLOCTEXT("[/Script/EngineSettings]", "6D0073BB1F41C8C4E21284B87D77ED5C", "Naked Desire")
[/Script/CommonInput.CommonInputSettings]
InputData=/Game/Input/NakedDesireInputData.NakedDesireInputData_C
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1 -1
View File
@@ -77,7 +77,7 @@ public:
FText Name;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
UTexture2D* Icon;
TObjectPtr<UTexture2D> Icon;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
EClothingSlotType SlotType;
@@ -6,6 +6,7 @@
#include "ClothingItemInstance.h"
#include "GameFramework/Character.h"
#include "Kismet/GameplayStatics.h"
#include "NakedDesire/Player/NakedDesireCharacter.h"
#include "NakedDesire/SaveGame/GlobalSaveGameData.h"
#include "NakedDesire/SaveGame/ItemSaveRecord.h"
#include "NakedDesire/SaveGame/SaveSubsystem.h"
@@ -97,6 +98,37 @@ float UClothingManager::GetHeelHeight()
return 0;
}
USkeletalMeshComponent* UClothingManager::GetMeshComponent(const EClothingSlotType SlotType) const
{
const ANakedDesireCharacter* Player = Cast<ANakedDesireCharacter>(GetOwner());
if (!Player)
{
return nullptr;
}
switch (SlotType)
{
case EClothingSlotType::Nipples: return Player->NipplesMeshComponent;
case EClothingSlotType::Anal: return Player->AnalMeshComponent;
case EClothingSlotType::Vagina: return Player->VaginaMeshComponent;
case EClothingSlotType::Head: return Player->HeadMeshComponent;
case EClothingSlotType::Neck: return Player->NeckMeshComponent;
case EClothingSlotType::Face: return Player->FaceMeshComponent;
case EClothingSlotType::Eyes: return Player->EyesMeshComponent;
case EClothingSlotType::Bodysuit: return Player->BodySuitMeshComponent;
case EClothingSlotType::Top: return Player->TopMeshComponent;
case EClothingSlotType::Bottom: return Player->BottomMeshComponent;
case EClothingSlotType::UnderwearTop: return Player->UnderwearTopMeshComponent;
case EClothingSlotType::UnderwearBottom:return Player->UnderwearBottomMeshComponent;
case EClothingSlotType::Socks: return Player->SocksMeshComponent;
case EClothingSlotType::Footwear: return Player->FootwearMeshComponent;
case EClothingSlotType::Outerwear: return Player->OuterwearMeshComponent;
case EClothingSlotType::WristRestraint: return Player->WristRestraintMeshComponent;
case EClothingSlotType::AnkleRestraint: return Player->AnkleRestraintMeshComponent;
case EClothingSlotType::NeckRestraint: return Player->NeckRestraintMeshComponent;
default: return nullptr;
}
}
void UClothingManager::PutOnClothing(UClothingItemInstance* ClothingItemInstance)
{
if (!ClothingItemInstance)
@@ -107,19 +139,20 @@ void UClothingManager::PutOnClothing(UClothingItemInstance* ClothingItemInstance
FClothingSlotData ClothingSlotData;
GetClothingSlotData(ClothingSlotType, ClothingSlotData);
ClothingSlotData.MeshComponent->SetSkeletalMesh(ClothingItemInstance->GetClothingItem()->SkeletalMesh);
USkeletalMeshComponent* MeshComponent = GetMeshComponent(ClothingSlotType);
MeshComponent->SetSkeletalMesh(ClothingItemInstance->GetClothingItem()->SkeletalMesh);
if (!ClothingItemInstance->GetClothingItem()->Materials.IsEmpty())
{
for (const TPair<FName, UMaterialInstance*>& Material : ClothingItemInstance->GetClothingItem()->Materials)
{
ClothingSlotData.MeshComponent->SetMaterialByName(Material.Key, Material.Value);
MeshComponent->SetMaterialByName(Material.Key, Material.Value);
}
}
SetClothingSlotItem(ClothingSlotType, ClothingItemInstance);
if (ClothingItemInstance->GetClothingItem()->UseLeaderPose)
{
ClothingSlotData.MeshComponent->SetLeaderPoseComponent(Cast<ACharacter>(GetOwner())->GetMesh());
MeshComponent->SetLeaderPoseComponent(Cast<ACharacter>(GetOwner())->GetMesh());
}
UClothingItem* ClothingItem = ClothingItemInstance->GetClothingItem();
@@ -178,12 +211,12 @@ UClothingItemInstance* UClothingManager::RemoveClothing(const EClothingSlotType
UClothingItemInstance* ClothingItemInstance = ClothingSlotData.ClothingItemInstance;
SetClothingSlotItem(ClothingSlotType, nullptr);
USkeletalMeshComponent* MeshComponent = ClothingSlotData.MeshComponent;
USkeletalMeshComponent* MeshComponent = GetMeshComponent(ClothingSlotType);
MeshComponent->SetSkeletalMesh(nullptr);
if (ClothingItemInstance->GetClothingItem()->UseLeaderPose)
{
ClothingSlotData.MeshComponent->SetLeaderPoseComponent(nullptr);
MeshComponent->SetLeaderPoseComponent(nullptr);
}
OnClothingUnequip.Broadcast(ClothingItemInstance);
@@ -27,7 +27,7 @@ public:
UPROPERTY(BlueprintReadWrite, Category = "Clothing Manager|Clothing")
USkeletalMeshComponent* RootMesh = nullptr;
UPROPERTY(BlueprintReadWrite, Category = "Clothing Manager|Clothing")
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Clothing Manager|Clothing")
TArray<FClothingSlotData> ClothingSlots;
UPROPERTY(BlueprintAssignable)
@@ -73,4 +73,7 @@ public:
UFUNCTION(BlueprintPure)
float GetHeelHeight();
private:
USkeletalMeshComponent* GetMeshComponent(EClothingSlotType SlotType) const;
};
+8 -13
View File
@@ -9,37 +9,32 @@
class UClothingItemInstance;
enum class EClothingSlotType : uint8;
/**
*
*/
USTRUCT(BlueprintType)
struct NAKEDDESIRE_API FClothingSlotData
{
GENERATED_BODY()
FClothingSlotData()
: MeshComponent(nullptr), ClothingSlotType(EClothingSlotType::Anal), ClothingItemInstance(nullptr), Name(FText::GetEmpty())
{
}
FClothingSlotData(USkeletalMeshComponent* MeshComponent, const EClothingSlotType ClothingSlotType, UClothingItemInstance* ClothingItemInstance, const FText& Name)
FClothingSlotData(const EClothingSlotType ClothingSlotType, const FText& Name, UTexture2D* Icon = nullptr)
{
this->MeshComponent = MeshComponent;
this->ClothingSlotType = ClothingSlotType;
this->ClothingItemInstance = ClothingItemInstance;
this->Name = Name;
this->Icon = Icon;
}
UPROPERTY(BlueprintReadWrite, Category = "Clothing")
TObjectPtr<USkeletalMeshComponent> MeshComponent = nullptr;
UPROPERTY(BlueprintReadWrite, Category = "Clothing")
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Clothing")
EClothingSlotType ClothingSlotType = EClothingSlotType::Anal;
UPROPERTY(BlueprintReadWrite, Category = "Clothing")
UPROPERTY(BlueprintReadOnly, Category = "Clothing")
TObjectPtr<UClothingItemInstance> ClothingItemInstance = nullptr;
UPROPERTY(BlueprintReadWrite, Category = "Clothing")
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Clothing")
FText Name = FText::GetEmpty();
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Clothing")
TObjectPtr<UTexture2D> Icon = nullptr;
};
@@ -0,0 +1,4 @@
// © 2025 Naked People Team. All Rights Reserved.
#include "ClothingSlotsData.h"
@@ -0,0 +1,34 @@
// © 2025 Naked People Team. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "ClothingSlotType.h"
#include "Engine/DataAsset.h"
#include "ClothingSlotsData.generated.h"
USTRUCT()
struct NAKEDDESIRE_API FClothingSlotData
{
GENERATED_BODY()
FClothingSlotData()
{
}
UPROPERTY(EditDefaultsOnly, Category = "Clothing")
UTexture2D Icon;
UPROPERTY(EditDefaultsOnly, Category = "Clothing")
FText Name;
};
UCLASS()
class NAKEDDESIRE_API UClothingSlotsData : public UPrimaryDataAsset
{
GENERATED_BODY()
public:
UPROPERTY(EditDefaultsOnly, Category = "Clothing")
TMap<EClothingSlotType, FClothingSlotData> ClothingSlotsData;
};
@@ -18,6 +18,7 @@
#include "NakedDesire/Global/Constants.h"
#include "NakedDesire/Global/NakedDesireUserSettings.h"
#include "NakedDesire/UI/RadialMenu/RadialMenuController.h"
#include "NakedDesire/Clothing/ClothingSlotWidgetsInfo.h"
#include "Perception/AIPerceptionStimuliSourceComponent.h"
#include "Perception/AISense_Sight.h"
@@ -163,8 +164,6 @@ void ANakedDesireCharacter::BeginPlay()
StimuliSourceComponent->RegisterForSense(TSubclassOf<UAISense_Sight>());
StimuliSourceComponent->RegisterWithPerceptionSystem();
SetupClothingSlots();
ClothingManager->OnClothingEquip.AddUniqueDynamic(this, &ANakedDesireCharacter::OnClothingEquip);
ClothingManager->OnClothingUnequip.AddUniqueDynamic(this, &ANakedDesireCharacter::OnClothingUnequip);
@@ -368,105 +367,25 @@ void ANakedDesireCharacter::OnCrouchToggle(const FInputActionValue& Value)
void ANakedDesireCharacter::OnEquipmentPress(const FInputActionValue& Value)
{
BuildRadialMenuEntries();
RadialMenuController->OpenMenu();
}
void ANakedDesireCharacter::SetupClothingSlots()
void ANakedDesireCharacter::BuildRadialMenuEntries()
{
#define LOCTEXT_NAMESPACE "ClothingSlots"
TArray<FRadialMenuEntry> Entries;
ClothingManager->ClothingSlots.Add(
FClothingSlotData(
NipplesMeshComponent, EClothingSlotType::Nipples,
nullptr,
LOCTEXT("Nipples", "Nipples")));
ClothingManager->ClothingSlots.Add(
FClothingSlotData(
AnalMeshComponent, EClothingSlotType::Anal,
nullptr,
LOCTEXT("Anal", "Anal")));
ClothingManager->ClothingSlots.Add(
FClothingSlotData(
VaginaMeshComponent, EClothingSlotType::Vagina,
nullptr,
LOCTEXT("Vagina", "Vagina")));
ClothingManager->ClothingSlots.Add(
FClothingSlotData(
HeadMeshComponent, EClothingSlotType::Head,
nullptr,
LOCTEXT("Head", "Head")));
ClothingManager->ClothingSlots.Add(
FClothingSlotData(
NeckMeshComponent, EClothingSlotType::Neck,
nullptr,
LOCTEXT("Neck", "Neck")));
ClothingManager->ClothingSlots.Add(
FClothingSlotData(
FaceMeshComponent, EClothingSlotType::Face,
nullptr,
LOCTEXT("Face", "Face")));
ClothingManager->ClothingSlots.Add(
FClothingSlotData(
EyesMeshComponent, EClothingSlotType::Eyes,
nullptr,
LOCTEXT("Eyes", "Eyes")));
ClothingManager->ClothingSlots.Add(
FClothingSlotData(
BodySuitMeshComponent, EClothingSlotType::Bodysuit,
nullptr,
LOCTEXT("Bodysuit", "Bodysuit")));
ClothingManager->ClothingSlots.Add(
FClothingSlotData(
TopMeshComponent, EClothingSlotType::Top,
nullptr,
LOCTEXT("Top", "Top")));
ClothingManager->ClothingSlots.Add(
FClothingSlotData(
BottomMeshComponent, EClothingSlotType::Bottom,
nullptr,
LOCTEXT("Bottom", "Bottom")));
ClothingManager->ClothingSlots.Add(
FClothingSlotData(
UnderwearTopMeshComponent, EClothingSlotType::UnderwearTop,
nullptr,
LOCTEXT("UnderwearTop", "UnderwearTop")));
ClothingManager->ClothingSlots.Add(
FClothingSlotData(
UnderwearBottomMeshComponent, EClothingSlotType::UnderwearBottom,
nullptr,
LOCTEXT("UnderwearBottom", "UnderwearBottom")));
ClothingManager->ClothingSlots.Add(
FClothingSlotData(
SocksMeshComponent, EClothingSlotType::Socks,
nullptr,
LOCTEXT("Socks", "Socks")));
ClothingManager->ClothingSlots.Add(
FClothingSlotData(
FootwearMeshComponent, EClothingSlotType::Footwear,
nullptr,
LOCTEXT("Footwear", "Footwear")));
ClothingManager->ClothingSlots.Add(
FClothingSlotData(
FootwearMeshComponent, EClothingSlotType::Outerwear,
nullptr,
LOCTEXT("Outerwear", "Outerwear")));
ClothingManager->ClothingSlots.Add(
FClothingSlotData(
FootwearMeshComponent, EClothingSlotType::WristRestraint,
nullptr,
LOCTEXT("WristRestraint", "WristRestraint")));
ClothingManager->ClothingSlots.Add(
FClothingSlotData(
FootwearMeshComponent, EClothingSlotType::AnkleRestraint,
nullptr,
LOCTEXT("AnkleRestraint", "AnkleRestraint")));
ClothingManager->ClothingSlots.Add(
FClothingSlotData(
FootwearMeshComponent, EClothingSlotType::NeckRestraint,
nullptr,
LOCTEXT("NeckRestraint", "NeckRestraint")));
for (const FClothingSlotData& SlotData : ClothingManager->ClothingSlots)
{
FRadialMenuEntry Entry;
Entry.bEnabled = SlotData.ClothingItemInstance != nullptr;
Entry.DisplayName = SlotData.Name;
Entry.Icon = SlotData.ClothingItemInstance ? SlotData.ClothingItemInstance->GetClothingItem()->Icon : SlotData.Icon;
Entry.ItemId = FName(SlotData.Name.ToString());
Entries.Push(Entry);
}
#undef LOCTEXT_NAMESPACE
RadialMenuController->Entries = Entries;
}
void ANakedDesireCharacter::NotifyNoticed(ANPCAIController* NPCController)
@@ -20,6 +20,7 @@ struct FClothingSlotData;
class UInteractionManager;
class UClothingPickerWidget;
class UClothingManager;
class UClothingSlotInfo;
class UStatsManager;
class UMissionsManager;
class ANPCAIController;
@@ -122,6 +123,9 @@ public:
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Censorship")
UStaticMeshComponent* AnalCensorship;
UPROPERTY(EditDefaultsOnly, Category = "Clothing")
TObjectPtr<UClothingSlotInfo> SlotInfo;
// Components
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Clothing")
UClothingManager* ClothingManager;
@@ -201,7 +205,7 @@ private:
void OnCrouchToggle(const FInputActionValue& Value);
void OnEquipmentPress(const FInputActionValue& Value);
void SetupClothingSlots();
void BuildRadialMenuEntries();
bool CheckSight(const FVector& StartLocation, const FVector& EndLocation, FHitResult& HitResult, const AActor* IgnoreActor);
};
@@ -0,0 +1,4 @@
// © 2025 Naked People Team. All Rights Reserved.
#include "EquipmentPanelWidget.h"
@@ -0,0 +1,16 @@
// © 2025 Naked People Team. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "CommonUserWidget.h"
#include "EquipmentPanelWidget.generated.h"
/**
*
*/
UCLASS()
class NAKEDDESIRE_API UEquipmentPanelWidget : public UCommonUserWidget
{
GENERATED_BODY()
};
@@ -0,0 +1,35 @@
// © 2025 Naked People Team. All Rights Reserved.
#include "EquipmentSlotWidget.h"
#include "NakedDesire/Clothing/ClothingItem.h"
#include "NakedDesire/Clothing/ClothingItemInstance.h"
#include "NakedDesire/Clothing/ClothingSlotsData.h"
void UEquipmentSlotWidget::SetItem(UClothingItemInstance* InItem)
{
ClothingItemInstance = InItem;
IconImage->SetBrushFromTexture(InItem->GetClothingItem()->Icon);
}
void UEquipmentSlotWidget::ClearItem()
{
ClothingItemInstance = nullptr;
}
void UEquipmentSlotWidget::NativeOnClicked()
{
Super::NativeOnClicked();
}
void UEquipmentSlotWidget::NativePreConstruct()
{
Super::NativePreConstruct();
if (!ClothingSlotsData->ClothingSlotsData.Contains(SlotType))
return;
FClothingSlotData& SlotData = ClothingSlotsData->ClothingSlotsData[SlotType];
PlaceholderImage->SetBrushFromTexture(&SlotData.Icon);
}
@@ -0,0 +1,43 @@
// © 2025 Naked People Team. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "CommonButtonBase.h"
#include "Components/Image.h"
#include "NakedDesire/Clothing/BodyPart.h"
#include "NakedDesire/Clothing/ClothingSlotType.h"
#include "EquipmentSlotWidget.generated.h"
class UClothingSlotsData;
class UClothingItemInstance;
UCLASS(Abstract)
class NAKEDDESIRE_API UEquipmentSlotWidget : public UCommonButtonBase
{
GENERATED_BODY()
public:
void SetItem(UClothingItemInstance* InItem);
void ClearItem();
protected:
virtual void NativeOnClicked() override;
virtual void NativePreConstruct() override;
UPROPERTY(EditDefaultsOnly)
TObjectPtr<UClothingSlotsData> ClothingSlotsData;
private:
UPROPERTY(meta = (BindWIdget))
TObjectPtr<UImage> PlaceholderImage;
UPROPERTY(meta = (BindWIdget))
TObjectPtr<UImage> IconImage;
UPROPERTY()
TObjectPtr<UClothingItemInstance> ClothingItemInstance = nullptr;
UPROPERTY()
EClothingSlotType SlotType = EClothingSlotType::Anal;
};
@@ -0,0 +1,4 @@
// © 2025 Naked People Team. All Rights Reserved.
#include "InventoryPanelWidget.h"
@@ -0,0 +1,16 @@
// © 2025 Naked People Team. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "CommonUserWidget.h"
#include "InventoryPanelWidget.generated.h"
/**
*
*/
UCLASS()
class NAKEDDESIRE_API UInventoryPanelWidget : public UCommonUserWidget
{
GENERATED_BODY()
};
@@ -0,0 +1 @@
#include "InventoryScreenWidget.h"
@@ -0,0 +1,11 @@
#pragma once
#include "CoreMinimal.h"
#include "CommonActivatableWidget.h"
#include "InventoryScreenWidget.generated.h"
UCLASS()
class NAKEDDESIRE_API UInventoryScreenWidget : public UCommonActivatableWidget
{
GENERATED_BODY()
};
@@ -103,7 +103,6 @@ public:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Radial Menu|Tuning")
TSubclassOf<URadialMenuWidget> WidgetClass;
protected:
virtual void TickComponent(float DeltaTime, ELevelTick TickType,
FActorComponentTickFunction* ThisTickFunction) override;