Looks like I’m getting pretty close:
[video]https://youtu.be/ops__oWtFf0[/video]
Here’s the code I used in the video
(USERotatingDevice is a subclass of USEDeviceActivator, which handles all the mouse input and event delegates for the component):
/* Called whenever a mouse drag operation occurs */
void USERotatingDevice::OnDeviceDragged_Callback(UActorComponent *Device, FVector2D DeltaMouse, float DeltaTime)
{
// Only allow changes to occur on the device being interacted with
if (Device != this)
return;
// Only allow changes to occur if this component is attached to a base component
TArray<USceneComponent*> Parents;
GetParentComponents(Parents);
if (Parents.Num() < 1)
return;
// Find the base component
USceneComponent *Base = nullptr;
for (auto Parent : Parents) {
if (Parent->GetName().Contains(TEXT("Base"))) {
Base = Parent;
break;
}
}
// Exit if no valid base component could be found
if (!IsValid(Base))
return;
// Exit if no activation nodes have been defined
auto NodeCount = ActivationNodes.Num();
if (NodeCount < 1)
return;
// Get the handle and pivot socket locations
auto GrabSocketLocation = FVector::ZeroVector;
auto PivotSocketLocation = FVector::ZeroVector;
if (ActivationMesh->HasAnySockets()) {
if (MeshSocketName != NAME_None) {
GrabSocketLocation = ActivationMesh->GetSocketLocation(MeshSocketName);
}
PivotSocketLocation = ActivationMesh->GetSocketLocation(TEXT("PivotPoint"));
}
// Get the mouse location & directional vector (in world coordinates)
auto PC = CastChecked<AMyPlayerController>(UGameplayStatics::GetPlayerController(GetWorld(), 0));
auto MouseWorldLocation = FVector::ZeroVector;
auto MouseWorldDirection = FVector::ZeroVector;
PC->DeprojectMousePositionToWorld(MouseWorldLocation, MouseWorldDirection);
// Get the device's normalized directional vectors
auto BaseUpVector = Base->GetUpVector();
auto BaseRightVector = Base->GetRightVector();
auto BaseForwardVector = Base->GetForwardVector();
// Get the camera's normlized directional vectors
auto Character = CastChecked<ASEDeviceTestCharacter>(UGameplayStatics::GetPlayerCharacter(GetWorld(), 0));
auto CharacterCamera = Character->GetFirstPersonCameraComponent();
auto CameraUpVector = CharacterCamera->GetUpVector();
auto CameraRightVector = CharacterCamera->GetRightVector();
auto CameraForwardVector = CharacterCamera->GetForwardVector();
// Get the direction vectors between Pivot & Handle, and Pivot & Mouse
auto HandleUpVector = -(PivotSocketLocation - GrabSocketLocation); // Not sure why, but without the negation this is actually a "down" vector
auto PivotToMouseVector = PivotSocketLocation - MouseWorldLocation;
HandleUpVector.Normalize();
PivotToMouseVector.Normalize();
auto LeverActivationVector = BaseForwardVector;
auto dotPUp = FVector::DotProduct(LeverActivationVector.SafeNormal(), CameraUpVector);
auto dotPRight = FVector::DotProduct(LeverActivationVector.SafeNormal(), CameraRightVector);
auto dotPForward = FVector::DotProduct(LeverActivationVector.SafeNormal(), CameraForwardVector);
auto StrDotPUp = FString(TEXT("[UP]: ")).Append(FString::SanitizeFloat(dotPUp));
auto StrDotPRight = FString(TEXT("[RIGHT]: ")).Append(FString::SanitizeFloat(dotPRight));
auto StrDotPForward = FString(TEXT("[FORWARD]: ")).Append(FString::SanitizeFloat(dotPForward));
FlushPersistentDebugLines(GetWorld());
DrawDebugDirectionalArrow(GetWorld(), PivotSocketLocation, PivotSocketLocation + (BaseForwardVector * 40.f), 6.f, FColor::Red, false, 3.f, 0, 1.5f);
DrawDebugDirectionalArrow(GetWorld(), PivotSocketLocation, PivotSocketLocation + (BaseRightVector * 40.f), 6.f, FColor::Green, false, 3.f, 0, 1.5f);
DrawDebugDirectionalArrow(GetWorld(), PivotSocketLocation, PivotSocketLocation + (BaseUpVector * 40.f), 6.f, FColor::Blue, false, 3.f, 0, 1.5f);
DrawDebugDirectionalArrow(GetWorld(), PivotSocketLocation, GrabSocketLocation + (HandleUpVector * 40.f), 6.f, FColor::Yellow, false, 3.f, 1, 2.f);
auto color = FColor::White;
auto message = FString(TEXT("N/A"));
// in front
if (dotPForward > 0.5f && FMath::Abs(dotPRight) < 0.5f && FMath::Abs(dotPUp) < 0.5f)
{
color = FColor::Blue;
message = TEXT("Floor: FRONT");
}
// behind
if (dotPForward < 0.5f && FMath::Abs(dotPRight) < 0.5f && FMath::Abs(dotPUp) < 0.5f)
{
color = FColor::Cyan;
message = TEXT("Floor: BEHIND");
}
// from right side
if (dotPRight > 0.5f && FMath::Abs(dotPForward) < 0.5f && FMath::Abs(dotPUp) < 0.5f)
{
color = FColor::Emerald;
message = TEXT("Floor: RIGHT");
}
// from left side
if (dotPRight < 0.5f && FMath::Abs(dotPForward) < 0.5f && FMath::Abs(dotPUp) < 0.5f)
{
color = FColor::Green;
message = TEXT("Floor: LEFT");
}
// on wall
if (FMath::Abs(dotPUp) > 0.5f)
{
color = FColor::Magenta;
message = TEXT("Wall");
}
FlushDebugStrings(GetWorld());
DrawDebugString(GetWorld(), GrabSocketLocation + (HandleUpVector * 40.f), message, nullptr, color);
DrawDebugString(GetWorld(), GrabSocketLocation + (HandleUpVector * 32.f), StrDotPUp, nullptr, dotPUp < 0.f ? FColor::Red : FColor::Green);
DrawDebugString(GetWorld(), GrabSocketLocation + (HandleUpVector * 24.f), StrDotPRight, nullptr, dotPRight < 0.f ? FColor::Red : FColor::Green);
DrawDebugString(GetWorld(), GrabSocketLocation + (HandleUpVector * 16.f), StrDotPForward, nullptr, dotPForward < 0.f ? FColor::Red : FColor::Green);
}
Any suggestions?