Files
inventory-system-plugin/Source/ItemInteraction/Private/InteractionTraceComponent.cpp
Bonchellon 7f7e043a88 Initial commit: Item Interaction Ecosystem plugin (UE5.7)
Server-authoritative, data-driven item/inventory/interaction/carry/equipment/
world-slot/placement/crafting framework. 8 modules, compiles against UE 5.7.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 20:49:56 +03:00

87 lines
2.4 KiB
C++

// Copyright ExByte Studios. Item Interaction Ecosystem.
#include "InteractionTraceComponent.h"
#include "InteractableComponent.h"
#include "GameFramework/Pawn.h"
#include "GameFramework/PlayerController.h"
#include "Engine/World.h"
UInteractionTraceComponent::UInteractionTraceComponent()
{
PrimaryComponentTick.bCanEverTick = true;
PrimaryComponentTick.TickInterval = 0.1f; // 10 Hz is plenty for prompts
SetIsReplicatedByDefault(false); // purely local
}
void UInteractionTraceComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
TickTrace();
}
bool UInteractionTraceComponent::GetViewPoint(FVector& OutLocation, FRotator& OutRotation) const
{
const APawn* Pawn = Cast<APawn>(GetOwner());
const APlayerController* PC = Pawn ? Cast<APlayerController>(Pawn->GetController()) : nullptr;
if (!PC || !PC->IsLocalController())
{
return false;
}
PC->GetPlayerViewPoint(OutLocation, OutRotation);
return true;
}
void UInteractionTraceComponent::TickTrace()
{
FVector ViewLoc;
FRotator ViewRot;
if (!GetViewPoint(ViewLoc, ViewRot))
{
SetTarget(nullptr, nullptr);
return;
}
const FVector End = ViewLoc + ViewRot.Vector() * TraceDistance;
FCollisionQueryParams Params(SCENE_QUERY_STAT(InteractionTrace), false, GetOwner());
Params.bTraceComplex = false;
FHitResult Hit;
const bool bHit = GetWorld()->SweepSingleByChannel(
Hit, ViewLoc, End, FQuat::Identity, TraceChannel,
FCollisionShape::MakeSphere(TraceRadius), Params);
AActor* HitActor = bHit ? Hit.GetActor() : nullptr;
UInteractableComponent* Interactable = HitActor ? HitActor->FindComponentByClass<UInteractableComponent>() : nullptr;
if (Interactable)
{
// Distance gate against the component's own reach.
const float DistSq = FVector::DistSquared(ViewLoc, Hit.ImpactPoint);
if (DistSq > FMath::Square(Interactable->InteractionDistance))
{
Interactable = nullptr;
HitActor = nullptr;
}
}
else
{
HitActor = nullptr;
}
LastHitLocation = Hit.ImpactPoint;
LastHitNormal = Hit.ImpactNormal;
SetTarget(HitActor, Interactable);
}
void UInteractionTraceComponent::SetTarget(AActor* NewTarget, UInteractableComponent* NewInteractable)
{
if (CurrentTarget == NewTarget && CurrentInteractable == NewInteractable)
{
return;
}
CurrentTarget = NewTarget;
CurrentInteractable = NewInteractable;
OnTargetChanged.Broadcast(NewTarget, NewInteractable);
}