Import initial du projet Survival (UE 5.8)
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>
This commit is contained in:
@@ -0,0 +1,173 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
|
||||
#include "InteractionComponent.h"
|
||||
|
||||
#include "DrawDebugHelpers.h"
|
||||
#include "Engine/World.h"
|
||||
#include "GameFramework/Controller.h"
|
||||
#include "GameFramework/Pawn.h"
|
||||
#include "Interactable.h"
|
||||
|
||||
UInteractionComponent::UInteractionComponent()
|
||||
{
|
||||
PrimaryComponentTick.bCanEverTick = true;
|
||||
}
|
||||
|
||||
void UInteractionComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
|
||||
{
|
||||
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
|
||||
|
||||
// On espace les traces : c'est une requete physique, pas gratuite, et
|
||||
// l'affichage du prompt n'a pas besoin d'etre rafraichi chaque frame.
|
||||
TimeSinceLastTrace += DeltaTime;
|
||||
if (TimeSinceLastTrace < TraceInterval)
|
||||
{
|
||||
return;
|
||||
}
|
||||
TimeSinceLastTrace = 0.f;
|
||||
|
||||
UpdateFocus();
|
||||
}
|
||||
|
||||
bool UInteractionComponent::GetViewPoint(FVector& OutLocation, FRotator& OutRotation) const
|
||||
{
|
||||
const APawn* OwnerPawn = Cast<APawn>(GetOwner());
|
||||
if (!OwnerPawn)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// On passe par le controller plutot que d'aller chercher la camera nous-memes :
|
||||
// GetPlayerViewPoint renvoie exactement ce que le joueur voit a l'ecran, y
|
||||
// compris les effets de camera. Le trace part donc pile du centre du viseur.
|
||||
if (const AController* OwnerController = OwnerPawn->GetController())
|
||||
{
|
||||
OwnerController->GetPlayerViewPoint(OutLocation, OutRotation);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void UInteractionComponent::UpdateFocus()
|
||||
{
|
||||
FVector ViewLocation;
|
||||
FRotator ViewRotation;
|
||||
if (!GetViewPoint(ViewLocation, ViewRotation))
|
||||
{
|
||||
SetFocusedActor(nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
const FVector TraceEnd = ViewLocation + ViewRotation.Vector() * InteractionRange;
|
||||
|
||||
FCollisionQueryParams Params(SCENE_QUERY_STAT(InteractionTrace), /*bTraceComplex=*/false, GetOwner());
|
||||
|
||||
// Sphere balayee plutot que rayon pur : quelques cm de tolerance suffisent
|
||||
// pour que viser un petit objet cesse d'etre un exercice de precision.
|
||||
FHitResult Hit;
|
||||
const bool bHit = GetWorld()->SweepSingleByChannel(
|
||||
Hit,
|
||||
ViewLocation,
|
||||
TraceEnd,
|
||||
FQuat::Identity,
|
||||
TraceChannel,
|
||||
FCollisionShape::MakeSphere(TraceRadius),
|
||||
Params);
|
||||
|
||||
AActor* Candidate = bHit ? Hit.GetActor() : nullptr;
|
||||
if (!IsValidInteractable(Candidate))
|
||||
{
|
||||
Candidate = nullptr;
|
||||
}
|
||||
|
||||
SetFocusedActor(Candidate);
|
||||
|
||||
#if ENABLE_DRAW_DEBUG
|
||||
if (bDrawDebug)
|
||||
{
|
||||
const FColor Color = Candidate ? FColor::Green : FColor::Red;
|
||||
DrawDebugLine(GetWorld(), ViewLocation, TraceEnd, Color, false, TraceInterval, 0, 1.f);
|
||||
if (bHit)
|
||||
{
|
||||
DrawDebugSphere(GetWorld(), Hit.ImpactPoint, TraceRadius, 12, Color, false, TraceInterval);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool UInteractionComponent::IsValidInteractable(AActor* Actor) const
|
||||
{
|
||||
if (!IsValid(Actor) || !Actor->Implements<UInteractable>())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// L'objet a le dernier mot : une porte verrouillee peut refuser d'etre visee.
|
||||
return IInteractable::Execute_CanInteract(Actor, GetOwner());
|
||||
}
|
||||
|
||||
void UInteractionComponent::SetFocusedActor(AActor* NewFocus)
|
||||
{
|
||||
AActor* OldFocus = FocusedActor.Get();
|
||||
const bool bWantsFocus = (NewFocus != nullptr);
|
||||
|
||||
// On compare les pointeurs ET l'etat booleen. Sans le booleen, le cas
|
||||
// "la cible s'est detruite toute seule" passerait inapercu : FocusedActor
|
||||
// renvoie deja nullptr, donc nullptr == nullptr, et on sortirait sans
|
||||
// prevenir l'UI -- le prompt resterait affiche indefiniment.
|
||||
if (OldFocus == NewFocus && bHasFocusedActor == bWantsFocus)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// IsValid() et pas seulement != nullptr : l'ancienne cible a pu etre detruite
|
||||
// entre deux traces, typiquement un objet qu'on vient de ramasser.
|
||||
if (IsValid(OldFocus) && OldFocus->Implements<UInteractable>())
|
||||
{
|
||||
IInteractable::Execute_OnEndFocus(OldFocus);
|
||||
}
|
||||
|
||||
FocusedActor = NewFocus;
|
||||
bHasFocusedActor = bWantsFocus;
|
||||
|
||||
if (NewFocus)
|
||||
{
|
||||
IInteractable::Execute_OnBeginFocus(NewFocus);
|
||||
}
|
||||
|
||||
OnFocusChanged.Broadcast(NewFocus, OldFocus);
|
||||
}
|
||||
|
||||
void UInteractionComponent::TryInteract()
|
||||
{
|
||||
// On retrace avant d'agir : jusqu'a TraceInterval secondes ont pu s'ecouler
|
||||
// depuis le dernier trace, et interagir avec un objet qu'on ne vise plus
|
||||
// serait un bug tres visible.
|
||||
UpdateFocus();
|
||||
|
||||
AActor* Target = FocusedActor.Get();
|
||||
if (!Target)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
IInteractable::Execute_Interact(Target, GetOwner());
|
||||
|
||||
// L'interaction vient peut-etre de detruire la cible, ou de la rendre
|
||||
// non-interactive (porte maintenant ouverte). On reevalue tout de suite
|
||||
// plutot que d'attendre le prochain trace periodique.
|
||||
UpdateFocus();
|
||||
}
|
||||
|
||||
FText UInteractionComponent::GetFocusedPrompt() const
|
||||
{
|
||||
AActor* Target = FocusedActor.Get();
|
||||
if (!IsValid(Target))
|
||||
{
|
||||
return FText::GetEmpty();
|
||||
}
|
||||
|
||||
return IInteractable::Execute_GetInteractionPrompt(Target);
|
||||
}
|
||||
Reference in New Issue
Block a user