Hi guys, short question!
I wrote a Grabber.cpp component that I attached to my ThirdPersonCharacter along with a PhysicsHandle so now I can Grab stuff and move around the map, the only problem is that only server are able to do that.
I think I missing something with HasAuthority(), but not sure.
void UGrabber::BeginPlay()
{
Super::BeginPlay();
FindPhysicsHandleComponent();
SetupInputComponent();
}
// Called every frame
void UGrabber::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
if (!ensure(PhysicsHandle != nullptr)) return;
// If the physics handle is attached
if (PhysicsHandle->GrabbedComponent)
{
// move the object that we're holding
PhysicsHandle->SetTargetLocation(GetReachLineEnd());
}
/*DrawDebugLine(
GetWorld(),
GetReachLineStart(),
GetReachLineEnd(),
FColor(255, 0, 0),
false,
0.f,
0.f,
10.f
);*/
}
void UGrabber::FindPhysicsHandleComponent()
{
PhysicsHandle = GetOwner()->FindComponentByClass<UPhysicsHandleComponent>();
if (!ensure(PhysicsHandle != nullptr))
{
UE_LOG(LogTemp, Warning, TEXT("%s missing physics handle component"), *GetOwner()->GetName());
return;
}
}
void UGrabber::SetupInputComponent()
{
Input = GetOwner()->FindComponentByClass<UInputComponent>();
if (Input)
{
Input->BindAction("Grab", IE_Pressed, this, &UGrabber::Grab);
Input->BindAction("Grab", IE_Released, this, &UGrabber::Release);
}
else
{
UE_LOG(LogTemp, Error, TEXT("%s missing input component"), *GetOwner()->GetName());
}
}
void UGrabber::Grab()
{
/// LINE TRACE and see if reach any actors with physics body collision channel set
auto HitResult = GetFirstPhysicsBodyInReach();
auto ComponentToGrab = HitResult.GetComponent(); // gets the mesh in our case
auto ActorHit = HitResult.GetActor();
/// If we hit something then attached a physics handle
if (ActorHit != nullptr)
{
if (!PhysicsHandle) { return; }
/// attach physic handle
PhysicsHandle->GrabComponent(
ComponentToGrab,
NAME_None, // no bones needed
ComponentToGrab->GetOwner()->GetActorLocation(),
true
);
}
}
void UGrabber::Release()
{
if (!ensure(PhysicsHandle != nullptr)) return;
PhysicsHandle->ReleaseComponent();
}
const FHitResult UGrabber::GetFirstPhysicsBodyInReach()
{
/// Line-trace (AKA ray-cast) out to reach distance
FHitResult HitResult;
FCollisionQueryParams TraceParameters(FName(TEXT("")), false, GetOwner());
GetWorld()->LineTraceSingleByObjectType(
OUT HitResult,
GetReachLineStart(),
GetReachLineEnd(),
FCollisionObjectQueryParams(ECollisionChannel::ECC_PhysicsBody),
TraceParameters
);
return HitResult;
}
FVector UGrabber::GetReachLineStart()
{
return GetWorld()->GetFirstPlayerController()->GetPawn()->GetPawnViewLocation();
}
FVector UGrabber::GetReachLineEnd()
{
FVector PlayerViewPointLocation = GetWorld()->GetFirstPlayerController()->GetPawn()->GetPawnViewLocation();
FRotator PlayerViewPointRotation = GetWorld()->GetFirstPlayerController()->GetControlRotation();
return (PlayerViewPointLocation + (PlayerViewPointRotation.Vector() * Reach));
}
The .header file contains the functions and the variables nothing more
#pragma once
#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "Components/InputComponent.h"
#include "PhysicsEngine/PhysicsHandleComponent.h"
#include "Grabber.generated.h"
UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
class PUZZLEPLATFORMS_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:
// Reachable from player in cm
float Reach = 150.f;
UPhysicsHandleComponent* PhysicsHandle = nullptr;
UInputComponent* Input = nullptr;
// Ray-cast and grab what's in reach
void Grab();
// Called when grab is released
void Release();
// Find (assumed) attached physics handle
void FindPhysicsHandleComponent();
// Setup (assumed) attached input component
void SetupInputComponent();
// Return hit for first physics body in reach
const FHitResult GetFirstPhysicsBodyInReach();
// Return current end of reach line
FVector GetReachLineEnd();
// Return current start of reach line
FVector GetReachLineStart();
};
Maybe Im missing these function in the BeginPlay()?
if (HasAuthority())
{
SetReplicates(true);
SetReplicateMovement(true);
}
Thank you all, or whoever is gonna read this post