.h
// StrivnX
#pragma once
#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "PhysicsEngine/PhysicsHandleComponent.h"
#include "Grabber.generated.h"
UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
class BUILDINGESCAPE_API UGrabber : public UActorComponent
{
GENERATED_BODY()
public:
// Sets default values for this component's properties
UGrabber();
protected:
// Called when the game starts
virtual void BeginPlay() override;
public:
// Called every frame
virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
private:
float Reach = 100.f;
UPhysicsHandleComponent* PhysicsHandle = nullptr;
UInputComponent* InputComponent = nullptr;
private:
void Grab();
void Release();
void FindPhysicsHandle();
void SetupInputComponent();
FVector LineTraceEnd();
FVector GetPlayerViewpointLocation();
void PlayerViewpoint(FVector& GetPlayerViewpointLocationOUT, FRotator& PlayerViewpointRotationOUT);
FHitResult GetFirstPhysicsBodyInReach();
};
.cpp
// StrivnX
#include "GameFramework/PlayerController.h"
#include "Engine/World.h"
#include "DrawDebugHelpers.h"
#include "Grabber.h"
#define OUT
// Sets default values for this component's properties
UGrabber::UGrabber()
{
// Set this component to be initialized when the game starts, and to be ticked every frame. You can turn these features
// off to improve performance if you don't need them.
PrimaryComponentTick.bCanEverTick = true;
// ...
}
// Called when the game starts
void UGrabber::BeginPlay()
{
Super::BeginPlay();
//checking for physics handle component
FindPhysicsHandle();
SetupInputComponent();
}
void UGrabber::FindPhysicsHandle()
{
PhysicsHandle = GetOwner()->FindComponentByClass<UPhysicsHandleComponent>();
if (!PhysicsHandle)UE_LOG(LogTemp, Error, TEXT("PhysicsHandle are NOT Set!"));
}
void UGrabber::SetupInputComponent()
{
InputComponent = GetOwner()->InputComponent;
//bind delegate Functions To Actions defined in project setting
if (InputComponent)
{
InputComponent->BindAction("Grab", IE_Pressed, this, &UGrabber::Grab);
InputComponent->BindAction("Grab", IE_Released, this, &UGrabber::Release);
}
}
void UGrabber::Grab()
{
//If we hit something then attach to the physics handle
FHitResult HitResult = GetFirstPhysicsBodyInReach();
UPrimitiveComponent* ComponentToGrab = HitResult.GetComponent();
if (HitResult.GetActor())
{
HitResult.GetComponent()->GetRelativeRotation() = FRotator(0.f, 0.f, 0.f);
//TODO attach to physics handle
PhysicsHandle->GrabComponentAtLocationWithRotation(
ComponentToGrab,
NAME_None,
HitResult.GetComponent()->GetRelativeLocation(),
HitResult.GetComponent()->GetRelativeRotation()
);
PhysicsHandle->SetInterpolationSpeed(20.f);
}
}
void UGrabber::Release()
{
PhysicsHandle->ReleaseComponent();
}
// Called every frame
void UGrabber::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{ Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
//Get PlayerViewpoint
FVector PlayerViewpointLocation;
FRotator PlayerViewpointRotation;
PlayerViewpoint(OUT PlayerViewpointLocation, OUT PlayerViewpointRotation);
//Draw A Line for Showing the reach Of Ray-Cast
DrawDebugLine(
GetWorld(),
GetPlayerViewpointLocation(),
LineTraceEnd(),
FColor(255, 0, 0),
false,
0.f,
0,
5.f);
// If the "physicshandle" handle an object.
if (PhysicsHandle->GetGrabbedComponent())
{
FRotator RPlayerAbove = PlayerViewpointRotation;
RPlayerAbove = { PlayerViewpointRotation.Pitch + 90.f, PlayerViewpointRotation.Yaw, PlayerViewpointRotation.Roll };
FVector LineTraceEndAbove = LineTraceEnd();
LineTraceEndAbove = PlayerViewpointLocation + RPlayerAbove.Vector() * Reach;
//Draw A Line for Showing where the object will be
DrawDebugLine(GetWorld(), PlayerViewpointLocation, LineTraceEndAbove, FColor(0, 0, 0), false, 0.f, 0, 5.f);
// Move the object we are holding.
PhysicsHandle->SetTargetLocationAndRotation(LineTraceEndAbove, PlayerViewpointRotation); // PlayerViewpointRotation is ObjectRotation
}
}
FHitResult UGrabber::GetFirstPhysicsBodyInReach()
{
//Ray-Cast
FHitResult HitResult;
FCollisionQueryParams TraceParams(FName(TEXT("")), false, GetOwner());
bool bHit = GetWorld()->LineTraceSingleByObjectType(
OUT HitResult,
GetPlayerViewpointLocation(),
LineTraceEnd(),
FCollisionObjectQueryParams(ECollisionChannel::ECC_PhysicsBody),
TraceParams
);
// See Waht it Hits
if (bHit)
{
FString NameOfObject = HitResult.GetActor()->GetName();
UE_LOG(LogTemp, Warning, TEXT("[FHitResult] Name Of Object: %s || GetCollisionProfileName %s"),*NameOfObject, *HitResult.GetComponent()->GetCollisionProfileName().ToString());
}
return HitResult;
}
FVector UGrabber::LineTraceEnd()
{
FVector PlayerViewpointLocation;
FRotator PlayerViewpointRotation;
PlayerViewpoint(PlayerViewpointLocation, PlayerViewpointRotation);
FVector PlayerForwardVector = GetWorld()->GetFirstPlayerController()->GetPawn()->GetActorForwardVector();//For Testing
return PlayerViewpointLocation + PlayerViewpointRotation.Vector() * Reach;
}
void UGrabber::PlayerViewpoint(OUT FVector& PlayerViewpointLocationOUT, OUT FRotator& PlayerViewpointRotationOUT)
{
// Get players viewpoint
FVector PlayerViewpointLocation;
FRotator PlayerViewpointRotation;
GetWorld()->GetFirstPlayerController()->GetPlayerViewPoint(
OUT PlayerViewpointLocation,
OUT PlayerViewpointRotation);
PlayerViewpointLocationOUT = PlayerViewpointLocation;
PlayerViewpointRotationOUT = PlayerViewpointRotation;
}
FVector UGrabber::GetPlayerViewpointLocation()
{
// Get players viewpoint
FVector PlayerViewpointLocation;
FRotator PlayerViewpointRotation;
GetWorld()->GetFirstPlayerController()->GetPlayerViewPoint(
OUT PlayerViewpointLocation,
OUT PlayerViewpointRotation);
return PlayerViewpointLocation;
}