I’m trying to implement a grab/drop feature in my project, so that the user can pick up objects that have physics. I need to do it in C++, but since there is plenty of material on this with Blueprints and almost none in C++ I started implementing the feature in Blueprint, and it works. The steps are these:
- If a certain key is pressed, do a line trace
- If the line trace hit something, create a Physics Handle Component in the current actor and call GrabComponent on the hit component
- If the key is released, call ReleaseComponent on the Physics Handle Component
In the Tick function, if there is a grab component I just call SetTargetLocation on the Physics Handle passing a location just in front of the camera (so that the user can move and the object stays in front of him), like this (sorry, it’s kind of messy):
Now, this works pretty much like in this video:
I started implementing this in C++, doing exactly the same things. The code looks like this:
// If the mouse button was clicked and no component is grabbed
if(GEngine->GetFirstLocalPlayerController(GetWorld())->IsInputKeyDown(EKeys::LeftMouseButton) && mMovedComponent == nullptr)
{
FHitResult hitResult;
FVector rayStart;
FVector rayEnd;
rayStart = FirstPersonCameraComponent->GetComponentLocation();
rayEnd = rayStart + FirstPersonCameraComponent->GetForwardVector() * 10000;
// Doing line trace to check if I hit something
bool hitFound = GetWorld()->LineTraceSingleByChannel(hitResult, rayStart, rayEnd, ECollisionChannel::ECC_Visibility);
if(hitFound)
{
// Saving the reference to the hit component and setting it to simulate physics
mMovedComponent = hitResult.Component.Get();
mMovedComponent->SetSimulatePhysics(true);
// Creating the handle
mPhysicsHandle = NewObject<UPhysicsHandleComponent>(this, TEXT("PhysicsHandle"));
// Setting the initial location of the handle
FVector loc = UGameplayStatics::GetPlayerCameraManager(GetWorld(), 0)->GetCameraLocation();
FRotator rot = UGameplayStatics::GetPlayerCameraManager(GetWorld(), 0)->GetCameraRotation();
mPhysicsHandle->SetTargetLocationAndRotation(loc, rot);
// Grabbing the hit component
mPhysicsHandle->GrabComponent(mMovedComponent, NAME_None, hitResult.ImpactPoint, false);
}
}
// If the player keeps pressing the mouse, I move the physics handle so that it stays in front of the camera
else if(GEngine->GetFirstLocalPlayerController(GetWorld())->IsInputKeyDown(EKeys::LeftMouseButton) && mMovedComponent != nullptr)
{
FVector loc = UGameplayStatics::GetPlayerCameraManager(GetWorld(), 0)->GetCameraLocation();
FRotator rot = UGameplayStatics::GetPlayerCameraManager(GetWorld(), 0)->GetCameraRotation();
// I create the new location so that is just in front of the player
loc += rot.Quaternion().GetForwardVector() * 200;
mPhysicsHandle->SetTargetLocation(loc);
}
// If the player is no longer pressing the key I release the physics handle
else if(mMovedComponent != nullptr && !GEngine->GetFirstLocalPlayerController(GetWorld())->IsInputKeyDown(EKeys::LeftMouseButton))
{
mMovedComponent->SetSimulatePhysics(false);
mMovedComponent = nullptr;
mPhysicsHandle->ReleaseComponent();
}
This code kind of works, meaning that the handle is created and it starts in the right spot. The problem is that it NEVER moves, even though “mPhysicsHandle->SetTargetLocation(loc)” is called at each subsequent tick and the new vector is correct (I print it in the log at each tick so I could see the values).
I don’t understand, why isn’t the handle moving?!