Created
November 27, 2019 16:15
-
-
Save Werninator/9bf4fe80756bfc6ab0bd00c970f540c2 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Copyright Patrick Werner 2019 | |
#include "Grabber.h" | |
#include "Engine/World.h" | |
#include "GameFramework/PlayerController.h" | |
#include "Components/PrimitiveComponent.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(); | |
FindPhysicsHandleComponent(); | |
FindInputComponent(); | |
if (InputComponent) | |
{ | |
BindInputs(); | |
} | |
} | |
// Called every frame | |
void UGrabber::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) | |
{ | |
Super::TickComponent(DeltaTime, TickType, ThisTickFunction); | |
/// if physics handle is attached | |
if (PhysicsHandle && PhysicsHandle->GrabbedComponent) | |
{ | |
/// move the object that we're holding each frame | |
PhysicsHandle->SetTargetLocation(GetLineTraceEnd()); | |
} | |
} | |
PlayerViewportTransform UGrabber::GetPlayerViewportTransformData() const | |
{ | |
PlayerViewportTransform TransformData = PlayerViewportTransform(); | |
GetWorld()->GetFirstPlayerController()->GetPlayerViewPoint( | |
OUT TransformData.Location, | |
OUT TransformData.Rotation | |
); | |
return TransformData; | |
} | |
FVector UGrabber::GetLineTraceStart() const | |
{ | |
PlayerViewportTransform TransformData = GetPlayerViewportTransformData(); | |
return TransformData.Location; | |
} | |
FVector UGrabber::GetLineTraceEnd() const | |
{ | |
PlayerViewportTransform TransformData = GetPlayerViewportTransformData(); | |
return TransformData.Location + TransformData.Rotation.Vector() * Reach; | |
} | |
void UGrabber::Grab() | |
{ | |
/// Line trace and see if we reach any actors with physics body collision channel set | |
FHitResult HitResult = GetFirstPhysicsBodyInReach(); | |
AActor* HitActor = HitResult.GetActor(); | |
/// if we hit something then attach a physics handle | |
if (PhysicsHandle && HitActor) | |
{ | |
PhysicsHandle->GrabComponent( | |
HitResult.GetComponent(), | |
NAME_None, | |
HitActor->GetActorLocation(), | |
true | |
); | |
} | |
} | |
void UGrabber::Release() | |
{ | |
if (PhysicsHandle) | |
{ | |
PhysicsHandle->ReleaseComponent(); | |
} | |
} | |
void UGrabber::FindPhysicsHandleComponent() | |
{ | |
/// Look for attached Physics handle | |
PhysicsHandle = GetOwner()->FindComponentByClass<UPhysicsHandleComponent>(); | |
if (!PhysicsHandle) | |
{ | |
UE_LOG(LogTemp, Error, TEXT("%s: Grabber needs PhysicsHandle to work!"), *GetOwner()->GetName()); | |
} | |
} | |
// find input component which automatically attaches itself to the default pawn | |
void UGrabber::FindInputComponent() | |
{ | |
InputComponent = GetOwner()->FindComponentByClass<UInputComponent>(); | |
if (!InputComponent) | |
{ | |
UE_LOG(LogTemp, Error, TEXT("%s: Grabber needs InputComponent to work!"), *GetOwner()->GetName()); | |
} | |
} | |
void UGrabber::BindInputs() const | |
{ | |
/// Bind the input axis | |
InputComponent->BindAction(TEXT("Grab"), IE_Pressed, this, &UGrabber::Grab); | |
InputComponent->BindAction(TEXT("Grab"), IE_Released, this, &UGrabber::Release); | |
} | |
FHitResult UGrabber::GetFirstPhysicsBodyInReach() const | |
{ | |
/// line trace (raycast) out to reach distance | |
FHitResult HitResult; | |
FCollisionQueryParams TraceParameters = FCollisionQueryParams(FName(TEXT("")), false, GetOwner()); | |
GetWorld()->LineTraceSingleByObjectType( | |
OUT HitResult, | |
GetLineTraceStart(), | |
GetLineTraceEnd(), | |
FCollisionObjectQueryParams(ECollisionChannel::ECC_PhysicsBody), | |
TraceParameters | |
); | |
return HitResult; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Copyright Patrick Werner 2019 | |
#pragma once | |
#include "CoreMinimal.h" | |
#include "Components/ActorComponent.h" | |
#include "PhysicsEngine/PhysicsHandleComponent.h" | |
#include "Components/InputComponent.h" | |
#include "Grabber.generated.h" | |
struct PlayerViewportTransform | |
{ | |
FVector Location; | |
FRotator Rotation; | |
}; | |
UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) ) | |
class UE4CPP_SECTION_03_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: | |
// how far ahead of the player can we reach in cm | |
float Reach = 150.f; | |
UPhysicsHandleComponent* PhysicsHandle = nullptr; | |
UInputComponent* InputComponent = nullptr; | |
// gets relevant player viewport transform data | |
PlayerViewportTransform GetPlayerViewportTransformData() const; | |
// returns current start of reach line | |
FVector GetLineTraceStart() const; | |
// returns current end of reach line | |
FVector GetLineTraceEnd() const; | |
// ray cast and grab what's in reach | |
void Grab(); | |
// called when greb is released | |
void Release(); | |
// find PhysicsHandle | |
void FindPhysicsHandleComponent(); | |
// find InputComponent | |
void FindInputComponent(); | |
// bind user inputs to methods | |
void BindInputs() const; | |
// Return hit for first physics body in reach | |
FHitResult GetFirstPhysicsBodyInReach() const; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment