// Fill out your copyright notice in the Description page of Project Settings. #include "HotbarWidget.h" #include "Components/HorizontalBox.h" #include "Components/HorizontalBoxSlot.h" #include "FpsPlayer.h" #include "GameFramework/PlayerController.h" #include "InventoryComponent.h" #include "InventorySlotWidget.h" void UHotbarWidget::NativeConstruct() { Super::NativeConstruct(); BindToOwningPawn(); } void UHotbarWidget::BindToOwningPawn() { UInventoryComponent* NewInventory = ResolveInventory(); if (BoundInventory.Get() == NewInventory) { return; } if (BoundInventory.IsValid()) { BoundInventory->OnInventoryChanged.RemoveDynamic(this, &UHotbarWidget::HandleInventoryChanged); BoundInventory->OnSelectedHotbarSlotChanged.RemoveDynamic(this, &UHotbarWidget::HandleSelectionChanged); } BoundInventory = NewInventory; if (BoundInventory.IsValid()) { BoundInventory->OnInventoryChanged.AddDynamic(this, &UHotbarWidget::HandleInventoryChanged); BoundInventory->OnSelectedHotbarSlotChanged.AddDynamic(this, &UHotbarWidget::HandleSelectionChanged); } else { UE_LOG(LogTemp, Warning, TEXT("UHotbarWidget : aucun UInventoryComponent trouve sur le pawn possede.")); } // Les cases memorisent l'ancien composant : on les recree. for (UInventorySlotWidget* SlotWidget : SlotWidgets) { if (SlotWidget) { SlotWidget->RemoveFromParent(); } } SlotWidgets.Reset(); Refresh(); } void UHotbarWidget::NativeDestruct() { if (BoundInventory.IsValid()) { BoundInventory->OnInventoryChanged.RemoveDynamic(this, &UHotbarWidget::HandleInventoryChanged); BoundInventory->OnSelectedHotbarSlotChanged.RemoveDynamic(this, &UHotbarWidget::HandleSelectionChanged); } BoundInventory.Reset(); Super::NativeDestruct(); } UInventoryComponent* UHotbarWidget::ResolveInventory() const { const APlayerController* OwningController = GetOwningPlayer(); AFpsPlayer* Player = OwningController ? Cast(OwningController->GetPawn()) : nullptr; return Player ? Player->GetInventoryComponent() : nullptr; } void UHotbarWidget::HandleInventoryChanged() { Refresh(); } void UHotbarWidget::HandleSelectionChanged(int32 NewIndex) { // Seule la surbrillance bouge : inutile de repousser tout le contenu. for (int32 Index = 0; Index < SlotWidgets.Num(); ++Index) { if (SlotWidgets[Index]) { SlotWidgets[Index]->SetSelected(Index == NewIndex); } } } void UHotbarWidget::Refresh() { if (!SlotContainer) { UE_LOG(LogTemp, Warning, TEXT("UHotbarWidget::Refresh : SlotContainer est nul. Le widget nomme 'SlotContainer' manque dans le Blueprint.")); return; } if (!BoundInventory.IsValid()) { return; } const TArray& Slots = BoundInventory->GetSlots(); const int32 Count = BoundInventory->GetHotbarSlotCount(); RebuildSlots(Count); const int32 Selected = BoundInventory->GetSelectedHotbarIndex(); for (int32 Index = 0; Index < SlotWidgets.Num(); ++Index) { if (!SlotWidgets[Index] || !Slots.IsValidIndex(Index)) { continue; } SlotWidgets[Index]->SetSlot(Slots[Index]); SlotWidgets[Index]->SetSelected(Index == Selected); } } void UHotbarWidget::RebuildSlots(int32 DesiredCount) { if (SlotWidgets.Num() == DesiredCount) { return; } if (!SlotWidgetClass) { UE_LOG(LogTemp, Warning, TEXT("UHotbarWidget : SlotWidgetClass n'est pas assignee, la barre restera vide.")); return; } while (SlotWidgets.Num() > DesiredCount) { const int32 Last = SlotWidgets.Num() - 1; if (SlotWidgets[Last]) { SlotWidgets[Last]->RemoveFromParent(); } SlotWidgets.RemoveAt(Last); } while (SlotWidgets.Num() < DesiredCount) { UInventorySlotWidget* NewSlot = CreateWidget(this, SlotWidgetClass); if (!NewSlot) { UE_LOG(LogTemp, Error, TEXT("UHotbarWidget : impossible de creer une case a partir de %s. Recompile ce Widget Blueprint."), *GetNameSafe(SlotWidgetClass)); break; } const int32 Index = SlotWidgets.Num(); // Meme indexation que la grille : la case 0 de la barre EST le slot 0 // de l'inventaire. C'est ce qui rend le glisser-deposer entre les deux // gratuit -- ils manipulent le meme tableau. NewSlot->InitSlot(BoundInventory.Get(), Index, nullptr); if (UHorizontalBoxSlot* BoxSlot = SlotContainer->AddChildToHorizontalBox(NewSlot)) { BoxSlot->SetPadding(FMargin(SlotPadding)); } SlotWidgets.Add(NewSlot); } }