ed7c7fd991
Boucle de jeu complète : récolte, inventaire, consommation, stats de survie, mort et respawn. Gameplay en C++, Blueprints réservés au câblage d'assets. Assets binaires (.uasset, .umap, textures, audio) suivis via Git LFS. Binaries/, Intermediate/, Saved/ et DerivedDataCache/ sont ignorés : régénérés au build, ils pèsent 3 Go pour 1,3 Go de contenu utile. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
136 lines
3.8 KiB
C++
136 lines
3.8 KiB
C++
// Fill out your copyright notice in the Description page of Project Settings.
|
|
|
|
|
|
#include "PickupItem.h"
|
|
|
|
#include "Components/SphereComponent.h"
|
|
#include "Components/StaticMeshComponent.h"
|
|
#include "InventoryComponent.h"
|
|
#include "ItemDataAsset.h"
|
|
|
|
#define LOCTEXT_NAMESPACE "PickupItem"
|
|
|
|
APickupItem::APickupItem()
|
|
{
|
|
PrimaryActorTick.bCanEverTick = false;
|
|
|
|
Mesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Mesh"));
|
|
SetRootComponent(Mesh);
|
|
// Purement decoratif : c'est la sphere qui porte la collision.
|
|
Mesh->SetCollisionEnabled(ECollisionEnabled::NoCollision);
|
|
|
|
// Le trace d'interaction passe par le canal Visibility. On ne bloque QUE
|
|
// ce canal : le pickup reste traversable par le joueur et les projectiles.
|
|
InteractionSphere = CreateDefaultSubobject<USphereComponent>(TEXT("InteractionSphere"));
|
|
InteractionSphere->SetupAttachment(Mesh);
|
|
InteractionSphere->InitSphereRadius(50.f);
|
|
InteractionSphere->SetCollisionEnabled(ECollisionEnabled::QueryOnly);
|
|
InteractionSphere->SetCollisionResponseToAllChannels(ECR_Ignore);
|
|
InteractionSphere->SetCollisionResponseToChannel(ECC_Visibility, ECR_Block);
|
|
}
|
|
|
|
void APickupItem::InitPickup(UItemDataAsset* InItemData, int32 InQuantity, int32 InRemainingUses)
|
|
{
|
|
ItemData = InItemData;
|
|
Quantity = FMath::Max(1, InQuantity);
|
|
RemainingUses = InRemainingUses;
|
|
}
|
|
|
|
void APickupItem::OnConstruction(const FTransform& Transform)
|
|
{
|
|
Super::OnConstruction(Transform);
|
|
|
|
// Confort d'edition : le mesh suit l'objet choisi, tu vois immediatement
|
|
// dans le viewport ce que tu es en train de poser. Vaut aussi a l'execution
|
|
// pour les objets jetes, puisque OnConstruction s'execute a FinishSpawning.
|
|
if (bUseMeshFromItemData && ItemData && ItemData->WorldMesh)
|
|
{
|
|
Mesh->SetStaticMesh(ItemData->WorldMesh);
|
|
}
|
|
}
|
|
|
|
FText APickupItem::GetInteractionPrompt_Implementation() const
|
|
{
|
|
if (!ItemData)
|
|
{
|
|
return LOCTEXT("PickupUnconfigured", "Objet non configure");
|
|
}
|
|
|
|
if (Quantity > 1)
|
|
{
|
|
return FText::Format(LOCTEXT("PickupPromptStack", "Ramasser {0} x{1}"),
|
|
ItemData->DisplayName, FText::AsNumber(Quantity));
|
|
}
|
|
|
|
return FText::Format(LOCTEXT("PickupPrompt", "Ramasser {0}"), ItemData->DisplayName);
|
|
}
|
|
|
|
bool APickupItem::CanInteract_Implementation(AActor* Interactor) const
|
|
{
|
|
// Un pickup sans donnee est une erreur de configuration : on le rend
|
|
// inerte plutot que de laisser le joueur ramasser du vide.
|
|
return ItemData != nullptr;
|
|
}
|
|
|
|
void APickupItem::Interact_Implementation(AActor* Interactor)
|
|
{
|
|
UInventoryComponent* Inventory = Interactor ? Interactor->FindComponentByClass<UInventoryComponent>() : nullptr;
|
|
if (!Inventory)
|
|
{
|
|
UE_LOG(LogTemp, Warning, TEXT("APickupItem : %s n'a pas d'UInventoryComponent."), *GetNameSafe(Interactor));
|
|
return;
|
|
}
|
|
|
|
const int32 Leftover = Inventory->AddItem(ItemData, Quantity, RemainingUses);
|
|
const int32 Added = Quantity - Leftover;
|
|
|
|
// Inventaire plein : on ne detruit surtout pas le tas, on retire seulement
|
|
// ce qui est rentre. Le joueur peut revenir chercher le reste.
|
|
if (Added <= 0)
|
|
{
|
|
if (GEngine)
|
|
{
|
|
GEngine->AddOnScreenDebugMessage(-1, 2.f, FColor::Red, TEXT("Inventaire plein"));
|
|
}
|
|
return;
|
|
}
|
|
|
|
// Retour temporaire, le temps que l'UI d'inventaire existe.
|
|
if (GEngine)
|
|
{
|
|
GEngine->AddOnScreenDebugMessage(-1, 2.f, FColor::Green,
|
|
FString::Printf(TEXT("+%d %s (total : %d, slots : %d/%d)"),
|
|
Added,
|
|
*ItemData->DisplayName.ToString(),
|
|
Inventory->GetItemCount(ItemData),
|
|
Inventory->GetUsedSlotCount(),
|
|
Inventory->GetTotalSlotCount()));
|
|
}
|
|
|
|
if (Leftover > 0)
|
|
{
|
|
Quantity = Leftover;
|
|
return;
|
|
}
|
|
|
|
Destroy();
|
|
}
|
|
|
|
void APickupItem::OnBeginFocus_Implementation()
|
|
{
|
|
if (bHighlightOnFocus)
|
|
{
|
|
Mesh->SetRenderCustomDepth(true);
|
|
}
|
|
}
|
|
|
|
void APickupItem::OnEndFocus_Implementation()
|
|
{
|
|
if (bHighlightOnFocus)
|
|
{
|
|
Mesh->SetRenderCustomDepth(false);
|
|
}
|
|
}
|
|
|
|
#undef LOCTEXT_NAMESPACE
|