My Refactor

I didn’t fully agree with you on a number of items in the refactoring, I feel like you added a lot of code that didn’t really do anything particularly useful, and while I do recognize that this is a simple example, there wasn’t a great deal of value in actually refactoring it other than for practice. I did not create two separate functions for player and reach, nor did I encapsulate the setup functions, I only have three private functions, grab, release, and get_reach. While I do agree this results in some code duplication, in this particular case, I don’t find that obnoxious. The main issue is that you need a FVector for the end point of the reach and you need a FHitResult to find what you hit and the hit result is an out parameter, which makes this function call awkward, but… whatevs.

// (C) Aaron Stackpole, 2020

#pragma once

#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "PhysicsEngine/PhysicsHandleComponent.h"
#include "GameFramework/PlayerController.h"
#include "Engine/World.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;

	UPROPERTY(EditAnywhere)
	float Reach = 100.f;

protected:
	// Called when the game starts
	virtual void BeginPlay() override;

private:
	void grab();
	void release();

	FVector get_reach() const;
};

#include "DrawDebugHelpers.h"
#define OUT

UPhysicsHandleComponent* phc = nullptr;
UInputComponent* ic = nullptr;

UGrabber::UGrabber()
{
	PrimaryComponentTick.bCanEverTick = true;
}

void UGrabber::BeginPlay()
{
	Super::BeginPlay();

	// Find Physics Handle
	phc = GetOwner()->FindComponentByClass<UPhysicsHandleComponent>();
	if (!phc) UE_LOG(LogTemp, Error, TEXT("No UPhysicsHandleComponent found in scene!"));

	// Setup Input Component
	ic = GetOwner()->FindComponentByClass<UInputComponent>();
	if (ic)
	{
		UE_LOG(LogTemp, Warning, TEXT("UInputComponent found on %s!"), *GetOwner()->GetName());
		ic->BindAction("Grab", IE_Pressed, this, &UGrabber::grab);
		ic->BindAction("Release", IE_Released, this, &UGrabber::release);
	}
	else
	{
		UE_LOG(LogTemp, Error, TEXT("No UInputComponent found on %s!"), *GetOwner()->GetName());
	}
}

void UGrabber::grab()
{
	UE_LOG(LogTemp, Warning, TEXT("Grab pressed..."));

	FVector v_pawn;
	FRotator r_pawn;
	FHitResult hr;

	GetWorld()->GetFirstPlayerController()->GetPlayerViewPoint(OUT v_pawn, OUT r_pawn);
	//UE_LOG(LogTemp, Warning, TEXT("Location: %s, Rotation: %s"), *v_pawn.ToString(), *r_pawn.ToString())
	//FVector v_end = v_pawn + FVector(0.f, 0.f, 100.f); // Draw line up 1M
	//DrawDebugLine(GetWorld(), v_pawn, v_end, FColor(0, 255, 0), false, 0.f, 0, 5.f);
	FVector v_end = v_pawn + r_pawn.Vector() * Reach;

	auto cqp = FCollisionQueryParams(FName(TEXT("cqp")), false, GetOwner());
	GetWorld()->LineTraceSingleByObjectType(OUT hr, v_pawn, v_end, FCollisionObjectQueryParams(ECollisionChannel::ECC_PhysicsBody), cqp);
	if (AActor* what = hr.GetActor()) UE_LOG(LogTemp, Warning, TEXT("Grabber has hit: %s"), *what->GetName());

	if (UPrimitiveComponent* pc = hr.GetComponent())
		phc->GrabComponentAtLocation(pc, NAME_None, v_end);
}

void UGrabber::release()
{
	UE_LOG(LogTemp, Warning, TEXT("Grab released..."));
	phc->ReleaseComponent();
}

FVector UGrabber::get_reach() const
{
	FVector v_pawn;
	FRotator r_pawn;
	GetWorld()->GetFirstPlayerController()->GetPlayerViewPoint(OUT v_pawn, OUT r_pawn);

	return v_pawn + r_pawn.Vector() * Reach;
}

// Called every frame
void UGrabber::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
	Super::TickComponent(DeltaTime, TickType, ThisTickFunction);

	if (phc->GrabbedComponent)
	{
		phc->SetTargetLocation(get_reach());
	}
}```
1 Like

Nice looking code :wink:

Privacy & Terms