Files
Faye/Source/Faye/Components/CoffeeMachineController.cpp
2026-07-03 19:56:31 +02:00

264 lines
7.4 KiB
C++

// Fill out your copyright notice in the Description page of Project Settings.
#include "CoffeeMachineController.h"
#include "HoverableBoxComponent.h"
#include "Faye/Base/FayePlayerController.h"
#include "Kismet/GameplayStatics.h"
UCoffeeMachineController::UCoffeeMachineController()
{
PrimaryComponentTick.bCanEverTick = true;
}
void UCoffeeMachineController::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
if (!bCoffeeMakingActive) return;
if (InputType == EInputControllerType::Mouse)
{
PerformMouseHover();
if (CurrentSelectedMeshComponent)
{
MoveHeldObject();
}
}
}
void UCoffeeMachineController::ToggleCoffeeMaking(bool bActive)
{
bCoffeeMakingActive = bActive;
PlayerController->ToggleCoffeeMaking(bActive);
if (bCoffeeMakingActive)
{
PlayerController->OnCoffeeMakingAction_GrabStarted.AddUniqueDynamic(this, &UCoffeeMachineController::OnInputGrab);
PlayerController->OnCoffeeMakingAction_GrabRelease.AddUniqueDynamic(this, &UCoffeeMachineController::OnInputRelease);
}
else
{
PlayerController->OnCoffeeMakingAction_GrabStarted.RemoveDynamic(this, &UCoffeeMachineController::OnInputGrab);
PlayerController->OnCoffeeMakingAction_GrabRelease.RemoveDynamic(this, &UCoffeeMachineController::OnInputRelease);
}
}
void UCoffeeMachineController::SetCoffeeMakingStage(ECoffeeMachineMakingState NewStage)
{
CurrentCoffeeMakingStage = NewStage;
}
void UCoffeeMachineController::BeginPlay()
{
Super::BeginPlay();
PlayerController = Cast<AFayePlayerController>(UGameplayStatics::GetPlayerController(GetWorld(), 0));
}
void UCoffeeMachineController::PerformMouseHover()
{
float MouseX, MouseY;
if (!PlayerController->GetMousePosition(MouseX, MouseY)) return;
FVector WorldOrigin, WorldDirection;
if (!PlayerController->DeprojectScreenPositionToWorld(MouseX, MouseY, WorldOrigin, WorldDirection)) return;
FVector TraceEnd = WorldOrigin + (WorldDirection * 300.f);
TArray<FHitResult> HitResults;
FCollisionQueryParams Params;
Params.AddIgnoredComponent(CurrentSelectedBoxComponent);
const bool bHit = GetWorld()->LineTraceMultiByChannel(HitResults, WorldOrigin, TraceEnd, ECC_GameTraceChannel1, Params);
HoverBox(bHit? Cast<UHoverableBoxComponent>(HitResults[0].Component) : nullptr);
}
void UCoffeeMachineController::MoveHeldObject()
{
float MouseX, MouseY;
if (!PlayerController->GetMousePosition(MouseX, MouseY)) return;
FVector WorldOrigin, WorldDirection;
if (!PlayerController->DeprojectScreenPositionToWorld(MouseX, MouseY, WorldOrigin, WorldDirection)) return;
APlayerCameraManager* CameraManager = PlayerController->PlayerCameraManager;
FVector CameraForward = CameraManager->GetActorForwardVector();
FPlane MovementPlane(CurrentSelectedMeshComponent->GetComponentLocation(), CameraForward);
FVector IntersectPoint = FMath::RayPlaneIntersection(WorldOrigin, WorldDirection, MovementPlane);
switch (CurrentGrabbedObjectMovementMode)
{
case ECoffeeMachinePropMovementMode::PlaneYZ:
break;
case ECoffeeMachinePropMovementMode::ZOnly:
{
IntersectPoint.X = CurrentGrabbedObjectStartPos.X;
IntersectPoint.Y = CurrentGrabbedObjectStartPos.Y;
IntersectPoint.Z = FMath::Clamp(IntersectPoint.Z, CurrentGrabbedObjectStartPos.Z - 14.f, CurrentGrabbedObjectStartPos.Z);
// if (GEngine)
// {
// GEngine->AddOnScreenDebugMessage(-1, 1.f, FColor::Red, FString::Printf(TEXT("Intersection point: %s"), *IntersectPoint.ToString()));
// }
break;
}
}
CurrentSelectedMeshComponent->SetWorldLocation(IntersectPoint);
}
void UCoffeeMachineController::HoverBox(UHoverableBoxComponent* InBox)
{
if (InBox == CurrentHoverableComponent)
{
if (CanHover(InBox))
return;
}
if (CurrentHoverableComponent)
{
CurrentHoverableComponent->OnUnhovered.Broadcast();
CurrentHoverableComponent = nullptr;
return;
}
if (CanHover(InBox))
{
CurrentHoverableComponent = InBox;
CurrentHoverableComponent->OnHovered.Broadcast();
}
}
bool UCoffeeMachineController::GrabObject(UHoverableBoxComponent* InBox)
{
if (CurrentCoffeeMakingStage != ECoffeeMachineMakingState::Start &&
CurrentCoffeeMakingStage != ECoffeeMachineMakingState::PortafilterPressing) return false;
if (InBox && InBox->GetAttachParent() && CanGrab(InBox))
{
CurrentSelectedBoxComponent = InBox;
CurrentSelectedMeshComponent = Cast<UStaticMeshComponent>(InBox->GetAttachParent());
CurrentSelectedBoxComponent->OnSelected.Broadcast();
CurrentGrabbedObjectStartPos = CurrentSelectedMeshComponent->GetComponentLocation();
if (InBox->ComponentHasTag(OBJECT_TYPE_PORTAFILTER) && CurrentCoffeeMakingStage == ECoffeeMachineMakingState::Start)
{
SetCoffeeMakingStage(ECoffeeMachineMakingState::PortafilterDragging);
CurrentGrabbedObjectMovementMode = ECoffeeMachinePropMovementMode::PlaneYZ;
}
else if (InBox->ComponentHasTag(OBJECT_TYPE_TAMPER) && CurrentCoffeeMakingStage == ECoffeeMachineMakingState::PortafilterPressing)
{
CurrentGrabbedObjectMovementMode = ECoffeeMachinePropMovementMode::ZOnly;
CurrentGrabbedObjectStartPos = TamperLiftStartingPos;
}
return true;
}
return false;
}
void UCoffeeMachineController::ReleaseObject()
{
OnObjectReleased.Broadcast();
if (CurrentSelectedBoxComponent)
{
CurrentSelectedBoxComponent->OnUnselected.Broadcast();
}
CurrentSelectedMeshComponent = nullptr;
CurrentSelectedBoxComponent = nullptr;
}
bool UCoffeeMachineController::CanGrab(const UHoverableBoxComponent* InBox) const
{
return InBox &&
((InBox->ComponentHasTag(OBJECT_TYPE_PORTAFILTER) && CurrentCoffeeMakingStage == ECoffeeMachineMakingState::Start) ||
(InBox->ComponentHasTag(OBJECT_TYPE_TAMPER) && CurrentCoffeeMakingStage == ECoffeeMachineMakingState::PortafilterPressing));
}
bool UCoffeeMachineController::CanHover(const UHoverableBoxComponent* InBox) const
{
if (!InBox) return false;
switch (CurrentCoffeeMakingStage)
{
case ECoffeeMachineMakingState::Start:
{
if (!InBox->ComponentHasTag(OBJECT_TYPE_PORTAFILTER) && !InBox->ComponentHasTag(OBJECT_TYPE_COFFEE_MUG)) return false;
break;
}
case ECoffeeMachineMakingState::PortafilterDragging:
{
if (!InBox->ComponentHasTag(OBJECT_TYPE_GRINDER)) return false;
break;
}
case ECoffeeMachineMakingState::PortafilterFilling:
{
if (!InBox->ComponentHasTag(OBJECT_TYPE_GRINDER_BUTTON)) return false;
break;
}
case ECoffeeMachineMakingState::PortafilterPressing:
{
if (!InBox->ComponentHasTag(OBJECT_TYPE_TAMPER)) return false;
break;
}
case ECoffeeMachineMakingState::CoffeeLoaded:
{
if (!InBox->ComponentHasTag(OBJECT_TYPE_MAIN_MACHINE_BUTTON) && !InBox->ComponentHasTag(OBJECT_TYPE_COFFEE_MUG)) return false;
// Cannot press button if cup not placed
if (InBox->ComponentHasTag(OBJECT_TYPE_MAIN_MACHINE_BUTTON) && !bCupPlaced) return false;
break;
}
case ECoffeeMachineMakingState::CoffeeFilling:
{
if (!InBox->ComponentHasTag(OBJECT_TYPE_MAIN_MACHINE_BUTTON)) return false;
break;
}
case ECoffeeMachineMakingState::CoffeeReady:
{
if (!InBox->ComponentHasTag(OBJECT_TYPE_COFFEE_MUG)) return false;
break;
}
case ECoffeeMachineMakingState::WaitingAction:
return false;
}
return true;
}
void UCoffeeMachineController::OnInputGrab()
{
if (!GrabObject(CurrentHoverableComponent))
{
OnObjectClicked.Broadcast();
}
}
void UCoffeeMachineController::OnInputRelease()
{
ReleaseObject();
}