Hey, so I made my function have multiple outs using pointers. It works, but keen to hear if this is a good way to code this. I am a cpp noob, so I am sure it probably isn’t. I saw a post from @Maxidelius which used structs instead - I’m going to try it that way too.
PS. I’m still a bit stuck on const - hence why it is not in the code… need to go back over that.
Header FIle:
// Copyright Omar Sattaur 2021
#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();
// Called every frame
virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
protected:
// Called when the game starts
virtual void BeginPlay() override;
public:
UPROPERTY(EditAnywhere)
float Reach = 300.f;
UPhysicsHandleComponent* PhysicsHandle = nullptr;
UInputComponent* InputPlayer = nullptr;
void FindPhysicsHandle();
void Grab();
void GrabRelease();
FHitResult PickUpItemInReach();
void SetUpInput();
void PlayerLocAndReach(FVector*PlayerViewpointVec, FVector*LineTraceEnd);
};
CPP file
// Copyright Omar Sattaur 2021
#include "Grabber.h"
#include "DrawDebugHelpers.h"
#include "Engine/World.h"
#include "GameFramework/PlayerController.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();
FindPhysicsHandle();
SetUpInput();
}
// Called every frame
void UGrabber::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
FVector PlayerViewpointVec;
FVector LineTraceEnd;
PlayerLocAndReach(&PlayerViewpointVec, &LineTraceEnd);
if (PhysicsHandle->GrabbedComponent){PhysicsHandle->SetTargetLocation(LineTraceEnd);}
}
void UGrabber::FindPhysicsHandle()
{
PhysicsHandle = GetOwner()->FindComponentByClass<UPhysicsHandleComponent>(); // Declare the PhysicsHandle
if (PhysicsHandle == nullptr){UE_LOG(LogTemp, Error, TEXT("Missing 'PhysicsHandle' on %s"), *GetOwner()->GetName());}
}
void UGrabber::Grab()
{
FVector PlayerViewpointVec;
FVector LineTraceEnd;
PlayerLocAndReach(&PlayerViewpointVec, &LineTraceEnd);
// UE_LOG(LogTemp, Display, TEXT("Player pressed 'Grab' key"));
FHitResult HitResult = PickUpItemInReach();
UPrimitiveComponent* ComponentToGrab = HitResult.GetComponent();
if (HitResult.GetActor())
{
PhysicsHandle->GrabComponentAtLocation(ComponentToGrab, NAME_None, LineTraceEnd);
}
}
void UGrabber::GrabRelease()
{
// UE_LOG(LogTemp, Display, TEXT("Player released 'Grab' key"));
PhysicsHandle->ReleaseComponent();
}
void UGrabber::SetUpInput()
{
InputPlayer = GetOwner()->FindComponentByClass<UInputComponent>();
if (InputPlayer)
{
UE_LOG(LogTemp, Display, TEXT("'InputCompentent' found on %s"), *GetOwner()->GetName());
InputPlayer->BindAction("Grab", IE_Pressed, this, &UGrabber::Grab);
InputPlayer->BindAction("Grab", IE_Released, this, &UGrabber::GrabRelease);
}
// else{UE_LOG(LogTemp, Error, TEXT("Missing 'InputCompentent' on %s"), *GetOwner()->GetName());}
}
FHitResult UGrabber::PickUpItemInReach()
{
FVector PlayerViewpointVec;
FVector LineTraceEnd;
PlayerLocAndReach(&PlayerViewpointVec, &LineTraceEnd);
FHitResult Hit;
FCollisionQueryParams TraceParams(FName(TEXT("")), false, GetOwner());
GetWorld()->LineTraceSingleByObjectType(
OUT Hit,
PlayerViewpointVec,
LineTraceEnd,
FCollisionObjectQueryParams(ECollisionChannel::ECC_PhysicsBody),
TraceParams
);
if (Hit.IsValidBlockingHit()){UE_LOG(LogTemp, Warning, TEXT("Line trace hit %s"), *Hit.GetActor()->GetName());}
DrawDebugLine(
GetWorld(),
PlayerViewpointVec,
LineTraceEnd,
FColor(0, 200, 0, 0),
false, 0.f, 0, 5.f
);
// UE_LOG(LogTemp, Warning, TEXT("The PlayerViewpointVec is: %s and the PlayerViewpointRot is: %s"), *PlayerViewpointVec.ToString(), *PlayerViewpointRot.Vector().ToString());
return Hit;
}
void UGrabber::PlayerLocAndReach(FVector*PlayerViewpointVec, FVector*LineTraceEnd)
{
FRotator PlayerViewpointRot;
GetWorld()->GetFirstPlayerController()->GetPlayerViewPoint (OUT *PlayerViewpointVec, OUT PlayerViewpointRot);
*LineTraceEnd = *PlayerViewpointVec + FVector(PlayerViewpointRot.Vector()*Reach);
}