From b93ca620b52e2e32ce00e45c86e68b089355369d Mon Sep 17 00:00:00 2001 From: Mamadou Babaei Date: Mon, 8 May 2023 15:28:49 +0200 Subject: [PATCH] add the initial implementation for the touch functionality and its feedbacks --- .../GameFramework/SGPlayerController.cpp | 255 +++++++++++++++++- .../GameFramework/SGPlayerController.h | 14 +- 2 files changed, 266 insertions(+), 3 deletions(-) diff --git a/Source/SenseGlove/Private/SenseGlove/GameFramework/SGPlayerController.cpp b/Source/SenseGlove/Private/SenseGlove/GameFramework/SGPlayerController.cpp index 727ad2d0..3fb64d1e 100644 --- a/Source/SenseGlove/Private/SenseGlove/GameFramework/SGPlayerController.cpp +++ b/Source/SenseGlove/Private/SenseGlove/GameFramework/SGPlayerController.cpp @@ -35,12 +35,263 @@ #include "SenseGlove/GameFramework/SGPlayerController.h" +#include "Engine/TimerHandle.h" +#include "TimerManager.h" + +#include "SenseGlove/Components/SGGrabComponent.h" +#include "SenseGlove/Components/SGTouchComponent.h" +#include "SenseGlove/GameFramework/SGPawn.h" +#include "SGCore/SGBuzzCommand.h" +#include "SGCore/SGForceFeedbackCommand.h" +#include "SGCore/SGHapticGlove.h" + +struct ASGPlayerController::FImpl +{ + /************************ + * Static methods + ************************/ + + static int32 GetBuzzLevel(const AActor* Actor); + static float GetBuzzDuration(const AActor* ActorThumbTouching, const AActor* ActorIndexTouching, + const AActor* ActorMiddleTouching, const AActor* ActorRingTouching, + const AActor* ActorPinkyTouching); + + static int32 GetForceFeedbackLevel(const AActor* Actor); + + /************************ + * Member variables + ************************/ + + FTimerHandle TouchBuzzStopTimer; + + /************************ + * Owner object + ************************/ + + ASGPlayerController* Owner; + + /************************ + * Constructor / Destructor + ************************/ + + explicit FImpl(ASGPlayerController* InOwner); + ~FImpl(); + + /************************ + * Default copy constructor & copy assignment operator + ************************/ + + FImpl(const FImpl& Rhs) = default; + FImpl& operator=(const FImpl& Rhs) = default; + + /************************ + * Methods + ************************/ + + USGBuzzCommand* GetBuzzCommand(const AActor* ActorThumbTouching, const AActor* ActorIndexTouching, + const AActor* ActorMiddleTouching, const AActor* ActorRingTouching, + const AActor* ActorPinkyTouching) const; + USGForceFeedbackCommand* GetForceFeedbackCommand(const AActor* ActorThumbTouching, const AActor* ActorIndexTouching, + const AActor* ActorMiddleTouching, const AActor* ActorRingTouching, + const AActor* ActorPinkyTouching) const; +}; + +int32 ASGPlayerController::FImpl::GetBuzzLevel(const AActor* Actor) +{ + if (IsValid(Actor)) + { + const USGTouchComponent* TouchComponent = USGTouchComponent::GetTouchComponent(Actor); + if (TouchComponent) + { + return TouchComponent->GetBuzzLevel(); + } + } + + return 0; +} + +float ASGPlayerController::FImpl::GetBuzzDuration(const AActor* ActorThumbTouching, const AActor* ActorIndexTouching, + const AActor* ActorMiddleTouching, const AActor* ActorRingTouching, + const AActor* ActorPinkyTouching) +{ + if (IsValid(ActorThumbTouching)) + { + const USGTouchComponent* TouchComponent = USGTouchComponent::GetTouchComponent(ActorThumbTouching); + if (TouchComponent) + { + return TouchComponent->GetBuzzDuration(); + } + } + + if (IsValid(ActorIndexTouching)) + { + const USGTouchComponent* TouchComponent = USGTouchComponent::GetTouchComponent(ActorIndexTouching); + if (TouchComponent) + { + return TouchComponent->GetBuzzDuration(); + } + } + + if (IsValid(ActorMiddleTouching)) + { + const USGTouchComponent* TouchComponent = USGTouchComponent::GetTouchComponent(ActorMiddleTouching); + if (TouchComponent) + { + return TouchComponent->GetBuzzDuration(); + } + } + + if (IsValid(ActorRingTouching)) + { + const USGTouchComponent* TouchComponent = USGTouchComponent::GetTouchComponent(ActorRingTouching); + if (TouchComponent) + { + return TouchComponent->GetBuzzDuration(); + } + } + + if (IsValid(ActorPinkyTouching)) + { + const USGTouchComponent* TouchComponent = USGTouchComponent::GetTouchComponent(ActorPinkyTouching); + if (TouchComponent) + { + return TouchComponent->GetBuzzDuration(); + } + } + + return 0.0f; +} + +int32 ASGPlayerController::FImpl::GetForceFeedbackLevel(const AActor* Actor) +{ + if (IsValid(Actor)) + { + const USGTouchComponent* TouchComponent = USGTouchComponent::GetTouchComponent(Actor); + if (TouchComponent) + { + return TouchComponent->GetForceFeedbackLevel(); + } + } + + return 0; +} + ASGPlayerController::ASGPlayerController(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) { } -void ASGPlayerController::SetupInputComponent() +void ASGPlayerController::BeginPlay() { - Super::SetupInputComponent(); + Super::BeginPlay(); + + ASGPawn* SGPawn = Cast(GetPawn()); + if (ensureAlwaysMsgf(IsValid(SGPawn), TEXT("%s"), TEXT("ERROR: invalid SenseGlove pawn!"))) + { + return; + } + + SGPawn->OnGrabStateUpdated().AddWeakLambda( + this, [&]( + const USGVirtualHandComponent* Hand, + const AActor* ActorThumbCanGrab, const AActor* ActorIndexCanGrab, + const AActor* ActorMiddleCanGrab) -> void + { + if (!IsValid(Hand)) + { + return; + } + + if (IsValid(ActorThumbCanGrab) && + ((ActorIndexCanGrab == ActorThumbCanGrab)) || ActorMiddleCanGrab == ActorThumbCanGrab) + { + + } + }); + + SGPawn->OnTouchStateUpdated().AddWeakLambda( + this, [&]( + const USGVirtualHandComponent* Hand, + const AActor* ActorThumbTouching, const AActor* ActorIndexTouching, const AActor* ActorMiddleTouching, + const AActor* ActorRingTouching, const AActor* ActorPinkyTouching) -> void + { + if (!IsValid(Hand)) + { + return; + } + + USGHapticGlove* Glove = Hand->GetConnectedGlove(); + if (!IsValid(Glove)) + { + return; + } + + const USGBuzzCommand* BuzzCommand{Pimpl->GetBuzzCommand( + ActorThumbTouching, ActorIndexTouching, ActorMiddleTouching, ActorRingTouching, ActorPinkyTouching)}; + Glove->SendHaptics(BuzzCommand); + + const float Duration = FImpl::GetBuzzDuration( + ActorThumbTouching, ActorIndexTouching, ActorMiddleTouching, ActorRingTouching, ActorPinkyTouching); + + GetWorldTimerManager().ClearTimer(Pimpl->TouchBuzzStopTimer); + + FTimerDelegate TouchBuzzStopHandler; + TouchBuzzStopHandler.BindLambda([&]()-> void + { + Glove->SendHaptics(USGBuzzCommand::Off(this)); + }); + + GetWorldTimerManager().SetTimer( + Pimpl->TouchBuzzStopTimer, TouchBuzzStopHandler, Duration, false, -1.0f); + + const USGForceFeedbackCommand* ForceFeedbackCommand{Pimpl->GetForceFeedbackCommand( + ActorThumbTouching, ActorIndexTouching, ActorMiddleTouching, ActorRingTouching, ActorPinkyTouching)}; + Glove->SendHaptics(ForceFeedbackCommand); + }); +} + +ASGPlayerController::FImpl::FImpl(ASGPlayerController* InOwner) + : Owner(InOwner) +{ +} + +ASGPlayerController::FImpl::~FImpl() = default; + +USGBuzzCommand* ASGPlayerController::FImpl::GetBuzzCommand(const AActor* ActorThumbTouching, + const AActor* ActorIndexTouching, + const AActor* ActorMiddleTouching, + const AActor* ActorRingTouching, + const AActor* ActorPinkyTouching) const +{ + USGBuzzCommand* BuzzCommand = USGBuzzCommand::NewBuzzCommand( + Owner, + GetBuzzLevel(ActorThumbTouching), + GetBuzzLevel(ActorIndexTouching), + GetBuzzLevel(ActorMiddleTouching), + GetBuzzLevel(ActorRingTouching), + GetBuzzLevel(ActorPinkyTouching) + ); + return BuzzCommand; +} + +USGForceFeedbackCommand* ASGPlayerController::FImpl::GetForceFeedbackCommand(const AActor* ActorThumbTouching, + const AActor* ActorIndexTouching, + const AActor* ActorMiddleTouching, + const AActor* ActorRingTouching, + const AActor* ActorPinkyTouching) const +{ + USGForceFeedbackCommand* ForceFeedbackCommand = USGForceFeedbackCommand::NewForceFeedbackCommand( + Owner, + GetForceFeedbackLevel(ActorThumbTouching), + GetForceFeedbackLevel(ActorIndexTouching), + GetForceFeedbackLevel(ActorMiddleTouching), + GetForceFeedbackLevel(ActorRingTouching), + GetForceFeedbackLevel(ActorPinkyTouching) + ); + return ForceFeedbackCommand; +} + +void ASGPlayerController::FImplDeleter::operator()(const FImpl* P) const +{ + delete P; } \ No newline at end of file diff --git a/Source/SenseGlove/Public/SenseGlove/GameFramework/SGPlayerController.h b/Source/SenseGlove/Public/SenseGlove/GameFramework/SGPlayerController.h index bd24cd2a..61959259 100644 --- a/Source/SenseGlove/Public/SenseGlove/GameFramework/SGPlayerController.h +++ b/Source/SenseGlove/Public/SenseGlove/GameFramework/SGPlayerController.h @@ -36,6 +36,7 @@ #pragma once #include "GameFramework/PlayerController.h" +#include "Templates/UniquePtr.h" #include "SGPlayerController.generated.h" @@ -44,6 +45,17 @@ class SENSEGLOVE_API ASGPlayerController : public APlayerController { GENERATED_UCLASS_BODY() +private: + struct FImpl; + + struct FImplDeleter + { + void operator()(const FImpl* P) const; + }; + + TUniquePtr Pimpl; + FImplDeleter PimplDeleter; + protected: - virtual void SetupInputComponent() override; + virtual void BeginPlay() override; }; \ No newline at end of file