41d6e6a7f3
Coffres : AStorageContainer, un UInventoryComponent configure en conteneur, affiche comme panneau de WBP_InventoryScreen plutot que dans un ecran a lui. Deplacement unifie par UInventoryComponent::TransferSlot / TransferAllTo. Panneau de detail : UItemDetailsWidget, pose DANS WBP_Inventory a droite de la grille. Icone, nom, separation, description, barre d'usure. Il recoit un couple (inventaire, index) et s'abonne a OnInventoryChanged, donc une charge consommee sous le curseur se voit. Une case ne connait plus sa grille : elle diffuse OnHoverChanged. La barre rapide s'y abonne aussi et relaie par le PlayerController, seul a posseder a la fois le HUD et l'ecran. Le panneau efface la case qu'on QUITTE et non lui-meme, sinon passer de la barre a la grille viderait ce qui vient d'etre affiche. L'ecran allume et eteint le panneau (SetItemDetailsEnabled) : WBP_Inventory etant instancie deux fois en mode coffre, une case a cocher par instance serait un bug qui attend qu'on oublie de la decocher. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
188 lines
6.7 KiB
C++
188 lines
6.7 KiB
C++
// Fill out your copyright notice in the Description page of Project Settings.
|
|
|
|
#pragma once
|
|
|
|
#include "CoreMinimal.h"
|
|
#include "Blueprint/UserWidget.h"
|
|
#include "InventoryWidget.generated.h"
|
|
|
|
class UInventoryComponent;
|
|
class UInventorySlotWidget;
|
|
class UItemDetailsWidget;
|
|
class UUniformGridPanel;
|
|
|
|
/**
|
|
* Grille de cases. Cree ses cases dynamiquement a partir du nombre de slots du
|
|
* composant, et se remet a jour uniquement quand l'inventaire change.
|
|
*
|
|
* Elle ne suppose PLUS qu'elle affiche le sac du joueur : le meme widget sert
|
|
* de grille de coffre en lui donnant simplement un autre UInventoryComponent.
|
|
* C'est ce qui permet d'avoir un seul WBP_Inventory pose des deux cotes de
|
|
* l'ecran de coffre -- et donc la meme apparence, sans duplication.
|
|
*
|
|
* Le nombre de cases n'est pas fige : quand un sac ajoutera des slots, la
|
|
* grille s'agrandira toute seule au prochain rafraichissement.
|
|
*/
|
|
UCLASS(Abstract)
|
|
class SURVIVAL_PROJET_API UInventoryWidget : public UUserWidget
|
|
{
|
|
GENERATED_BODY()
|
|
|
|
public:
|
|
virtual void NativeConstruct() override;
|
|
virtual void NativeDestruct() override;
|
|
|
|
/** Reconstruit si necessaire, puis pousse le contenu dans chaque case. */
|
|
UFUNCTION(BlueprintCallable, Category = "Inventaire")
|
|
void Refresh();
|
|
|
|
/** Index de la case sous le curseur, ou INDEX_NONE. */
|
|
UFUNCTION(BlueprintPure, Category = "Inventaire")
|
|
int32 GetHoveredSlotIndex() const { return HoveredSlotIndex; }
|
|
|
|
/**
|
|
* Case survolee ET inventaire auquel elle appartient.
|
|
*
|
|
* L'index seul ne suffit plus : la touche "jeter" doit savoir de quel
|
|
* conteneur sortir l'objet, et la case 3 existe aussi bien dans le sac que
|
|
* dans le coffre.
|
|
*/
|
|
bool GetHoveredSlot(UInventoryComponent*& OutInventory, int32& OutIndex) const;
|
|
|
|
/** Abonne aux cases : le curseur entre ou sort de l'une d'elles. */
|
|
UFUNCTION()
|
|
void NotifySlotHovered(int32 Index, bool bHovered);
|
|
|
|
/**
|
|
* Survol d'une case qui n'appartient PAS a cette grille -- la barre rapide.
|
|
*
|
|
* Ne touche pas a HoveredSlotIndex : celui-ci sert a la touche "jeter", qui
|
|
* doit continuer de viser la grille et elle seule. Seul le panneau de detail
|
|
* repond, parce qu'il n'y en a qu'un a l'ecran et qu'il appartient a la
|
|
* grille du sac.
|
|
*/
|
|
void NotifyExternalSlotHovered(UInventoryComponent* InInventory, int32 InSlotIndex, bool bHovered);
|
|
|
|
/**
|
|
* Autorise ou coupe le panneau de detail de cette grille.
|
|
*
|
|
* C'est l'ECRAN qui decide, jamais une case a cocher dans la Designer : le
|
|
* WBP_Inventory est instancie deux fois sur l'ecran de coffre, et un reglage
|
|
* qu'on peut oublier de decocher sur l'une des deux instances est un bug qui
|
|
* attend. Coupe : la grille de coffre n'en a jamais, et le sac perd le sien
|
|
* tant qu'un coffre est ouvert -- l'ecran est deja assez large a trois
|
|
* colonnes.
|
|
*/
|
|
void SetItemDetailsEnabled(bool bEnabled);
|
|
|
|
/**
|
|
* (Re)branche le widget sur l'inventaire du pawn actuellement possede.
|
|
* Indispensable apres un respawn : le nouveau pawn a un nouveau composant,
|
|
* et l'ancien abonnement pointerait vers un objet detruit.
|
|
*/
|
|
void BindToOwningPawn();
|
|
|
|
/**
|
|
* (Re)branche le widget sur un inventaire quelconque -- celui d'un coffre,
|
|
* typiquement. nullptr vide la grille : une grille de coffre referme ne doit
|
|
* pas continuer d'afficher un contenu qu'on ne pilote plus.
|
|
*/
|
|
void BindToInventory(UInventoryComponent* InInventory);
|
|
|
|
UFUNCTION(BlueprintPure, Category = "Inventaire")
|
|
UInventoryComponent* GetBoundInventory() const { return BoundInventory.Get(); }
|
|
|
|
/** Destination du clic droit pour toutes les cases de cette grille. */
|
|
void SetQuickTransferTarget(UInventoryComponent* InTarget);
|
|
|
|
/**
|
|
* Change le nombre de colonnes et redispose les cases.
|
|
*
|
|
* Sert a la grille de coffre : c'est le coffre pose dans le niveau qui
|
|
* decide de sa forme, pas le Widget Blueprint -- un coffre de 12 cases et
|
|
* un de 30 ne se lisent pas bien avec le meme nombre de colonnes.
|
|
*/
|
|
UFUNCTION(BlueprintCallable, Category = "Inventaire")
|
|
void SetColumnCount(int32 NewColumnCount);
|
|
|
|
protected:
|
|
/** A nommer exactement "SlotGrid" dans le Widget Blueprint. */
|
|
UPROPERTY(meta = (BindWidget))
|
|
TObjectPtr<UUniformGridPanel> SlotGrid;
|
|
|
|
/** Le widget de case a instancier : ton WBP_InventorySlot. */
|
|
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Inventaire")
|
|
TSubclassOf<UInventorySlotWidget> SlotWidgetClass;
|
|
|
|
/** Nombre de cases par ligne. */
|
|
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Inventaire", meta = (ClampMin = "1"))
|
|
int32 ColumnCount = 6;
|
|
|
|
/**
|
|
* La grille va chercher toute seule l'inventaire du pawn a sa construction.
|
|
*
|
|
* DECOCHE-LE sur la grille de coffre. Sans ca elle s'accrocherait au pawn
|
|
* dans son NativeConstruct -- qui s'execute avant que l'ecran ait eu le
|
|
* temps de lui donner le conteneur -- et afficherait le sac du joueur des
|
|
* deux cotes de l'ecran.
|
|
*/
|
|
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Inventaire")
|
|
bool bAutoBindToPawn = true;
|
|
|
|
/**
|
|
* Le panneau de detail pose a cote de la grille, dans le meme Widget
|
|
* Blueprint. A nommer "ItemDetailsPanel".
|
|
*
|
|
* Optionnel : la grille doit rester valide dans un WBP_Inventory ou ce
|
|
* panneau n'existe pas encore, sinon ajouter cette fonctionnalite casserait
|
|
* la compilation de l'inventaire entier tant que la mise en page n'est pas
|
|
* faite.
|
|
*/
|
|
UPROPERTY(meta = (BindWidgetOptional))
|
|
TObjectPtr<UItemDetailsWidget> ItemDetailsPanel;
|
|
|
|
protected:
|
|
/**
|
|
* Absorbe les depots qui ne visent aucune case. Sans ca, lacher un objet
|
|
* sur le fond du panneau declencherait OnDragCancelled -- et si un jour on
|
|
* y branche le drop au sol, le joueur jetterait son butin par accident.
|
|
*/
|
|
virtual bool NativeOnDrop(const FGeometry& InGeometry, const FDragDropEvent& InDragDropEvent, UDragDropOperation* InOperation) override;
|
|
|
|
private:
|
|
UFUNCTION()
|
|
void HandleInventoryChanged();
|
|
|
|
/** Cree ou supprime des cases pour coller au nombre de slots. */
|
|
void RebuildGrid(int32 DesiredCount);
|
|
|
|
/** Detruit toutes les cases : leur inventaire a change, elles sont perimees. */
|
|
void ClearSlotWidgets();
|
|
|
|
/** Retrouve l'inventaire du pawn possede. */
|
|
UInventoryComponent* ResolveInventory() const;
|
|
|
|
/**
|
|
* Point de passage UNIQUE du survol : met a jour l'index et le panneau de
|
|
* detail. Ne fait rien si l'index ne change pas.
|
|
*/
|
|
void SetHoveredSlot(int32 NewIndex);
|
|
|
|
/** Pousse la case survolee dans le panneau, ou l'efface. */
|
|
void UpdateItemDetails();
|
|
|
|
TWeakObjectPtr<UInventoryComponent> BoundInventory;
|
|
|
|
/** Destination du clic droit, recopiee sur chaque case creee. */
|
|
TWeakObjectPtr<UInventoryComponent> QuickTransferTarget;
|
|
|
|
int32 HoveredSlotIndex = INDEX_NONE;
|
|
|
|
/** Voir SetItemDetailsEnabled(). */
|
|
bool bItemDetailsEnabled = true;
|
|
|
|
/** UPROPERTY obligatoire : sans ca le GC collecterait les cases. */
|
|
UPROPERTY(Transient)
|
|
TArray<TObjectPtr<UInventorySlotWidget>> SlotWidgets;
|
|
};
|