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>
87 lines
2.4 KiB
C++
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);
|
|
}
|