diff --git a/Source/RWTHVRToolkit/Private/Interaction/Interactables/ActionBehaviour.cpp b/Source/RWTHVRToolkit/Private/Interaction/Interactables/ActionBehaviour.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0b7ff6e65729a8c27204edff42de1369bd74f8b2 --- /dev/null +++ b/Source/RWTHVRToolkit/Private/Interaction/Interactables/ActionBehaviour.cpp @@ -0,0 +1,35 @@ +// Fill out your copyright notice in the Description page of Project Settings. + + +#include "Interaction/Interactables/ActionBehaviour.h" + +// We disable ticking here, as we are mainly interested in the events +UActionBehaviour::UActionBehaviour() +{ + PrimaryComponentTick.bCanEverTick = false; +} + +void UActionBehaviour::OnActionStart(USceneComponent* TriggeredComponent, const UInputAction* InputAction, + const FInputActionValue& Value) +{ +} + +void UActionBehaviour::OnActionEnd(USceneComponent* TriggeredComponent, const UInputAction* InputAction, + const FInputActionValue& Value) +{ +} + +void UActionBehaviour::BeginPlay() +{ + Super::BeginPlay(); + + OnActionBeginEvent.AddDynamic(this, &UActionBehaviour::OnActionStart); + OnActionEndEvent.AddDynamic(this, &UActionBehaviour::OnActionEnd); +} + +// Called every frame +void UActionBehaviour::TickComponent(float DeltaTime, ELevelTick TickType, + FActorComponentTickFunction* ThisTickFunction) +{ + Super::TickComponent(DeltaTime, TickType, ThisTickFunction); +} diff --git a/Source/RWTHVRToolkit/Private/Interaction/Interactees/OnClickGrabBehavior.cpp b/Source/RWTHVRToolkit/Private/Interaction/Interactables/GrabBehavior.cpp similarity index 65% rename from Source/RWTHVRToolkit/Private/Interaction/Interactees/OnClickGrabBehavior.cpp rename to Source/RWTHVRToolkit/Private/Interaction/Interactables/GrabBehavior.cpp index c924e7786c415380448f9bf68f1d5d374dedb27e..0acf4d7abd92c4ef4ac0e555c8ce3387b6c6ce43 100644 --- a/Source/RWTHVRToolkit/Private/Interaction/Interactees/OnClickGrabBehavior.cpp +++ b/Source/RWTHVRToolkit/Private/Interaction/Interactables/GrabBehavior.cpp @@ -1,13 +1,12 @@ // Fill out your copyright notice in the Description page of Project Settings. -#include "Interaction/Interactees/OnClickGrabBehavior.h" - -#include "Interaction/Interactees/InteractableBase.h" +#include "Interaction/Interactables/GrabBehavior.h" +#include "Interaction/Interactables/InteractableComponent.h" #include "Kismet/GameplayStatics.h" #include "Serialization/JsonTypes.h" -UPrimitiveComponent* UOnClickGrabBehavior::GetFirstComponentSimulatingPhysics(const AActor* TargetActor) +UPrimitiveComponent* UGrabBehavior::GetFirstComponentSimulatingPhysics(const AActor* TargetActor) { TArray<UPrimitiveComponent*> PrimitiveComponents; TargetActor->GetComponents<UPrimitiveComponent>(PrimitiveComponents); @@ -24,7 +23,7 @@ UPrimitiveComponent* UOnClickGrabBehavior::GetFirstComponentSimulatingPhysics(co } // recursively goes up the hierarchy and returns the highest parent simulating physics -UPrimitiveComponent* UOnClickGrabBehavior::GetHighestParentSimulatingPhysics(UPrimitiveComponent* Comp) +UPrimitiveComponent* UGrabBehavior::GetHighestParentSimulatingPhysics(UPrimitiveComponent* Comp) { if (Cast<UPrimitiveComponent>(Comp->GetAttachParent()) && Comp->GetAttachParent()->IsSimulatingPhysics()) { @@ -36,7 +35,8 @@ UPrimitiveComponent* UOnClickGrabBehavior::GetHighestParentSimulatingPhysics(UPr } } -void UOnClickGrabBehavior::OnClickStart(USceneComponent* TriggeredComponent, const FInputActionValue& Value) +void UGrabBehavior::OnActionStart(USceneComponent* TriggeredComponent, const UInputAction* InputAction, + const FInputActionValue& Value) { const APawn* Player = UGameplayStatics::GetPlayerPawn(GetWorld(), 0); @@ -59,16 +59,17 @@ void UOnClickGrabBehavior::OnClickStart(USceneComponent* TriggeredComponent, con if (bBlockOtherInteractionsWhileGrabbed) { - TArray<UInteractableBase*> Interactables; - GetOwner()->GetComponents<UInteractableBase>(Interactables, false); - for (UInteractableBase* Interactable : Interactables) + TArray<UInteractableComponent*> Interactables; + GetOwner()->GetComponents<UInteractableComponent>(Interactables, false); + for (UInteractableComponent* Interactable : Interactables) { Interactable->RestrictInteractionToComponent(TriggeredComponent); } } } -void UOnClickGrabBehavior::OnClickEnd(USceneComponent* TriggeredComponent, const FInputActionValue& Value) +void UGrabBehavior::OnActionEnd(USceneComponent* TriggeredComponent, const UInputAction* InputAction, + const FInputActionValue& Value) { if (MyPhysicsComponent) { @@ -82,9 +83,9 @@ void UOnClickGrabBehavior::OnClickEnd(USceneComponent* TriggeredComponent, const if (bBlockOtherInteractionsWhileGrabbed) { - TArray<UInteractableBase*> Interactables; - GetOwner()->GetComponents<UInteractableBase>(Interactables, false); - for (UInteractableBase* Interactable : Interactables) + TArray<UInteractableComponent*> Interactables; + GetOwner()->GetComponents<UInteractableComponent>(Interactables, false); + for (UInteractableComponent* Interactable : Interactables) { Interactable->ResetRestrictInteraction(); } diff --git a/Source/RWTHVRToolkit/Private/Interaction/Interactees/HoverBehaviour.cpp b/Source/RWTHVRToolkit/Private/Interaction/Interactables/HoverBehaviour.cpp similarity index 89% rename from Source/RWTHVRToolkit/Private/Interaction/Interactees/HoverBehaviour.cpp rename to Source/RWTHVRToolkit/Private/Interaction/Interactables/HoverBehaviour.cpp index 2c425f6f19880676561d20b4dcdbd88548bb024e..22986668f167c91498e6be7da5c2058bfac38856 100644 --- a/Source/RWTHVRToolkit/Private/Interaction/Interactees/HoverBehaviour.cpp +++ b/Source/RWTHVRToolkit/Private/Interaction/Interactables/HoverBehaviour.cpp @@ -1,7 +1,7 @@ // Fill out your copyright notice in the Description page of Project Settings. -#include "Interaction/Interactees/HoverBehaviour.h" +#include "Interaction/Interactables/HoverBehaviour.h" void UHoverBehaviour::OnHoverStart(const USceneComponent* TriggeredComponent, FHitResult Hit) { diff --git a/Source/RWTHVRToolkit/Private/Interaction/Interactables/InteractableComponent.cpp b/Source/RWTHVRToolkit/Private/Interaction/Interactables/InteractableComponent.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d354afa8768f1973d740239eaa223e3bc8c5ab88 --- /dev/null +++ b/Source/RWTHVRToolkit/Private/Interaction/Interactables/InteractableComponent.cpp @@ -0,0 +1,147 @@ +// Fill out your copyright notice in the Description page of Project Settings. + + +#include "Interaction/Interactables/InteractableComponent.h" +#include "Interaction/Interactables/ActionBehaviour.h" +#include "Interaction/Interactables/HoverBehaviour.h" + +void UInteractableComponent::RestrictInteractionToComponents(const TArray<USceneComponent*>& Components) +{ + if (Components.IsEmpty()) + { + bRestrictInteraction = false; + AllowedComponents.Empty(); + } + else + { + bRestrictInteraction = true; + AllowedComponents = Components; + } +} + +void UInteractableComponent::RestrictInteractionToComponent(USceneComponent* Component) +{ + TArray<USceneComponent*> Components; + Components.Add(Component); + RestrictInteractionToComponents(Components); +} + +void UInteractableComponent::ResetRestrictInteraction() +{ + bRestrictInteraction = false; + AllowedComponents.Empty(); +} + +// Called when the game starts +void UInteractableComponent::BeginPlay() +{ + Super::BeginPlay(); + InitDefaultBehaviourReferences(); +} + +// This functions dispatches the HoverStart Event to the attached Hover Behaviour Components +void UInteractableComponent::HandleOnHoverStartEvents(USceneComponent* TriggerComponent, + const EInteractorType Interactor) +{ + // We early return if there the InteractorFilter is set and the Interactor is allowed. + if (!(InteractorFilter == EInteractorType::None || InteractorFilter & Interactor)) return; + + // We early return if the source Interactor is not part of the allowed components + if (!IsComponentAllowed(TriggerComponent)) return; + + //Broadcast event to all HoverBehaviours + for (const UHoverBehaviour* b : OnHoverBehaviours) + { + b->OnHoverStartEvent.Broadcast(TriggerComponent, HitResult); + } +} + +// This functions dispatches the HoverEnd Event to the attached Hover Behaviour Components +void UInteractableComponent::HandleOnHoverEndEvents(USceneComponent* TriggerComponent, const EInteractorType Interactor) +{ + // We early return if there the InteractorFilter is set and the Interactor is allowed. + if (!(InteractorFilter == EInteractorType::None || InteractorFilter & Interactor)) return; + + // We early return if the source Interactor is not part of the allowed components + if (!IsComponentAllowed(TriggerComponent)) return; + + //Broadcast event to all HoverBehaviours + for (const UHoverBehaviour* b : OnHoverBehaviours) + { + b->OnHoverEndEvent.Broadcast(TriggerComponent); + } +} + +// This functions dispatches the ActionStart Event to the attached Action Behaviour Components +void UInteractableComponent::HandleOnActionStartEvents(USceneComponent* TriggerComponent, + const UInputAction* InputAction, + const FInputActionValue& Value, + const EInteractorType Interactor) +{ + // We early return if there the InteractorFilter is set and the Interactor is allowed. + if (!(InteractorFilter == EInteractorType::None || InteractorFilter & Interactor)) return; + + // We early return if the source Interactor is not part of the allowed components + if (!IsComponentAllowed(TriggerComponent)) return; + + //Broadcast event to all ActionBehaviours + for (const UActionBehaviour* b : OnActionBehaviours) + { + b->OnActionBeginEvent.Broadcast(TriggerComponent, InputAction, Value); + } +} + +// This functions dispatches the ActionEnd Event to the attached Action Behaviour Components +void UInteractableComponent::HandleOnActionEndEvents(USceneComponent* TriggerComponent, const UInputAction* InputAction, + const FInputActionValue& Value, + const EInteractorType Interactor) +{ + // We early return if there the InteractorFilter is set and the Interactor is allowed. + if (!(InteractorFilter == EInteractorType::None || InteractorFilter & Interactor)) return; + + // We early return if the source Interactor is not part of the allowed components + if (!IsComponentAllowed(TriggerComponent)) return; + + //Broadcast event to all ActionBehaviours + for (const UActionBehaviour* b : OnActionBehaviours) + { + b->OnActionEndEvent.Broadcast(TriggerComponent, InputAction, Value); + } +} + +// This function searches for Action and Hover Behaviours that are attached to the Actor iff they are not set +// manually by the user. +void UInteractableComponent::InitDefaultBehaviourReferences() +{ + // only do this if empty, otherwise the user has explicitly stated, which behaviors to include + if (OnHoverBehaviours.IsEmpty()) + { + //Selecting + TInlineComponentArray<UHoverBehaviour*> AttachedHoverBehaviours; + GetOwner()->GetComponents(AttachedHoverBehaviours, true); + + OnHoverBehaviours = AttachedHoverBehaviours; + } + + // only do this if empty, otherwise the user has explicitly stated, which behaviors to include + if (OnActionBehaviours.IsEmpty()) + { + //Clicking + TInlineComponentArray<UActionBehaviour*> AttachedClickBehaviours; + GetOwner()->GetComponents(AttachedClickBehaviours, true); + + OnActionBehaviours = AttachedClickBehaviours; + } +} + +bool UInteractableComponent::IsComponentAllowed(USceneComponent* Component) const +{ + if (bRestrictInteraction) + { + if (!AllowedComponents.Contains(Component)) + { + return false; + } + } + return true; +} diff --git a/Source/RWTHVRToolkit/Private/Interaction/Interactees/ClickBehaviour.cpp b/Source/RWTHVRToolkit/Private/Interaction/Interactees/ClickBehaviour.cpp deleted file mode 100644 index 158839e941a704f8f496106d3357984153ec77e8..0000000000000000000000000000000000000000 --- a/Source/RWTHVRToolkit/Private/Interaction/Interactees/ClickBehaviour.cpp +++ /dev/null @@ -1,32 +0,0 @@ -// Fill out your copyright notice in the Description page of Project Settings. - - -#include "Interaction/Interactees/ClickBehaviour.h" - -// Sets default values for this component's properties -UClickBehaviour::UClickBehaviour() -{ - PrimaryComponentTick.bCanEverTick = true; -} - -void UClickBehaviour::OnClickStart(USceneComponent* TriggeredComponent, const FInputActionValue& Value) -{ -} - -void UClickBehaviour::OnClickEnd(USceneComponent* TriggeredComponent, const FInputActionValue& Value) -{ -} - -void UClickBehaviour::BeginPlay() -{ - Super::BeginPlay(); - - OnClickStartEvent.AddDynamic(this, &UClickBehaviour::OnClickStart); - OnClickEndEvent.AddDynamic(this, &UClickBehaviour::OnClickEnd); -} - -// Called every frame -void UClickBehaviour::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) -{ - Super::TickComponent(DeltaTime, TickType, ThisTickFunction); -} diff --git a/Source/RWTHVRToolkit/Private/Interaction/Interactees/GrabbableComponent.cpp b/Source/RWTHVRToolkit/Private/Interaction/Interactees/GrabbableComponent.cpp deleted file mode 100644 index 115d3397dc7617ac09c31e0802a2d05b8ef67331..0000000000000000000000000000000000000000 --- a/Source/RWTHVRToolkit/Private/Interaction/Interactees/GrabbableComponent.cpp +++ /dev/null @@ -1,4 +0,0 @@ -// Fill out your copyright notice in the Description page of Project Settings. - - -#include "Interaction/Interactees/GrabbableComponent.h" diff --git a/Source/RWTHVRToolkit/Private/Interaction/Interactees/InteractableBase.cpp b/Source/RWTHVRToolkit/Private/Interaction/Interactees/InteractableBase.cpp deleted file mode 100644 index 46bac83c41fa33d1d604a104f6e0addfb03e97c9..0000000000000000000000000000000000000000 --- a/Source/RWTHVRToolkit/Private/Interaction/Interactees/InteractableBase.cpp +++ /dev/null @@ -1,117 +0,0 @@ -// Fill out your copyright notice in the Description page of Project Settings. - - -#include "Interaction/Interactees/InteractableBase.h" - -#include "Interaction/Interactees/ClickBehaviour.h" -#include "Interaction/Interactees/HoverBehaviour.h" - -void UInteractableBase::RestrictInteractionToComponents(const TArray<USceneComponent*>& Components) -{ - if(Components.IsEmpty()) - { - bRestrictInteraction = false; - AllowedComponents.Empty(); - } else - { - bRestrictInteraction = true; - AllowedComponents = Components; - } -} - -void UInteractableBase::RestrictInteractionToComponent(USceneComponent* Component) -{ - TArray<USceneComponent*> Components; - Components.Add(Component); - RestrictInteractionToComponents(Components); -} - -void UInteractableBase::ResetRestrictInteraction() -{ - bRestrictInteraction = false; - AllowedComponents.Empty(); -} - -// Called when the game starts -void UInteractableBase::BeginPlay() -{ - Super::BeginPlay(); - InitDefaultBehaviourReferences(); -} - -void UInteractableBase::HandleOnHoverStartEvents(USceneComponent* TriggerComponent) -{ - if(!IsComponentAllowed(TriggerComponent)) return; - - for(const UHoverBehaviour* b : OnHoverBehaviours) - { - b->OnHoverStartEvent.Broadcast(TriggerComponent, HitResult); - } - -} - -void UInteractableBase::HandleOnHoverEndEvents(USceneComponent* TriggerComponent) -{ - if(!IsComponentAllowed(TriggerComponent)) return; - - for(const UHoverBehaviour* b : OnHoverBehaviours) - { - b->OnHoverEndEvent.Broadcast(TriggerComponent); - } -} - -void UInteractableBase::HandleOnClickStartEvents(USceneComponent* TriggerComponent, const FInputActionValue& Value) -{ - if(!IsComponentAllowed(TriggerComponent)) return; - - for(const UClickBehaviour* b : OnClickBehaviours) - { - b->OnClickStartEvent.Broadcast(TriggerComponent, Value); - } -} - -void UInteractableBase::HandleOnClickEndEvents(USceneComponent* TriggerComponent, const FInputActionValue& Value) -{ - if(!IsComponentAllowed(TriggerComponent)) return; - - for(const UClickBehaviour* b : OnClickBehaviours) - { - b->OnClickEndEvent.Broadcast(TriggerComponent, Value); - } -} - -void UInteractableBase::InitDefaultBehaviourReferences() -{ - // only do this if empty, otherwise the user has explicitly stated, which behaviors to include - if(OnHoverBehaviours.IsEmpty()) - { - //Selecting - TInlineComponentArray<UHoverBehaviour*> AttachedHoverBehaviours; - GetOwner()->GetComponents(AttachedHoverBehaviours, true); - - OnHoverBehaviours = AttachedHoverBehaviours; - } - - // only do this if empty, otherwise the user has explicitly stated, which behaviors to include - if(OnClickBehaviours.IsEmpty()) - { - //Clicking - TInlineComponentArray<UClickBehaviour*> AttachedClickBehaviours; - GetOwner()->GetComponents(AttachedClickBehaviours, true); - - OnClickBehaviours = AttachedClickBehaviours; - } -} - -bool UInteractableBase::IsComponentAllowed(USceneComponent* Component) const -{ - if(bRestrictInteraction) - { - if(!AllowedComponents.Contains(Component)) - { - return false; - } - } - return true; -} - diff --git a/Source/RWTHVRToolkit/Private/Interaction/Interactees/RaycastSelectable.cpp b/Source/RWTHVRToolkit/Private/Interaction/Interactees/RaycastSelectable.cpp deleted file mode 100644 index f09396346a2cd62aa5ae2f680f5185f25d5786c3..0000000000000000000000000000000000000000 --- a/Source/RWTHVRToolkit/Private/Interaction/Interactees/RaycastSelectable.cpp +++ /dev/null @@ -1,4 +0,0 @@ -// Fill out your copyright notice in the Description page of Project Settings. - - -#include "Interaction/Interactees/RaycastSelectable.h" diff --git a/Source/RWTHVRToolkit/Private/Interaction/Interactors/GrabComponent.cpp b/Source/RWTHVRToolkit/Private/Interaction/Interactors/GrabComponent.cpp index d40092ec8a170af2c7d16cef4cfcd646f1794f98..32df40be5c43d29f66c99351bd0c28165ec48c48 100644 --- a/Source/RWTHVRToolkit/Private/Interaction/Interactors/GrabComponent.cpp +++ b/Source/RWTHVRToolkit/Private/Interaction/Interactors/GrabComponent.cpp @@ -5,7 +5,8 @@ #include "EnhancedInputComponent.h" #include "EnhancedInputSubsystems.h" -#include "Interaction/Interactees/GrabbableComponent.h" +#include "Interaction/Interactables/InteractableComponent.h" +#include "Interaction/Interactables/InteractionBitSet.h" #include "Kismet/GameplayStatics.h" @@ -24,7 +25,7 @@ void UGrabComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorC Super::TickComponent(DeltaTime, TickType, ThisTickFunction); - TArray<UGrabbableComponent*> CurrentGrabCompsInRange; + TArray<UInteractableComponent*> CurrentGrabCompsInRange; TArray<AActor*> ActorsToIgnore; TArray<FHitResult> OutHits; @@ -42,8 +43,8 @@ void UGrabComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorC AActor* HitActor = Hit.GetActor(); if (HitActor) { - UGrabbableComponent* Grabbable = HitActor->FindComponentByClass<UGrabbableComponent>(); - if (Grabbable && Grabbable->IsInteractable) + UInteractableComponent* Grabbable = HitActor->FindComponentByClass<UInteractableComponent>(); + if (Grabbable && Grabbable->HasInteractionTypeFlag(EInteractorType::Grab) && Grabbable->IsInteractable) { Grabbable->HitResult = Hit; CurrentGrabCompsInRange.Add(Grabbable); @@ -54,28 +55,28 @@ void UGrabComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorC CurrentGrabbableInRange = CurrentGrabCompsInRange; // Call hover start events on all components that were not in range before - for (UGrabbableComponent* CurrentGrabbale : CurrentGrabCompsInRange) + for (UInteractableComponent* CurrentGrabbale : CurrentGrabCompsInRange) { if (!PreviousGrabbablesInRange.Contains(CurrentGrabbale)) { PreviousGrabbablesInRange.Add(CurrentGrabbale); - CurrentGrabbale->HandleOnHoverStartEvents(this); + CurrentGrabbale->HandleOnHoverStartEvents(this, EInteractorType::Grab); } } - TArray<UGrabbableComponent*> ComponentsToRemove; + TArray<UInteractableComponent*> ComponentsToRemove; // Call hover end events on all components that were previously in range, but not anymore - for (UGrabbableComponent* PrevGrabbale : PreviousGrabbablesInRange) + for (UInteractableComponent* PrevGrabbale : PreviousGrabbablesInRange) { if (!CurrentGrabCompsInRange.Contains(PrevGrabbale)) { ComponentsToRemove.Add(PrevGrabbale); - PrevGrabbale->HandleOnHoverEndEvents(this); + PrevGrabbale->HandleOnHoverEndEvents(this, EInteractorType::Grab); } } - for (UGrabbableComponent* CompToRemove : ComponentsToRemove) + for (UInteractableComponent* CompToRemove : ComponentsToRemove) { PreviousGrabbablesInRange.Remove(CompToRemove); } @@ -106,16 +107,16 @@ void UGrabComponent::SetupPlayerInput(UInputComponent* PlayerInputComponent) void UGrabComponent::OnBeginGrab(const FInputActionValue& Value) { - for (UGrabbableComponent* Grabbale : CurrentGrabbableInRange) + for (UInteractableComponent* Grabbale : CurrentGrabbableInRange) { - Grabbale->HandleOnClickStartEvents(this, Value); + Grabbale->HandleOnActionStartEvents(this, GrabInputAction, Value, EInteractorType::Grab); } } void UGrabComponent::OnEndGrab(const FInputActionValue& Value) { - for (UGrabbableComponent* Grabbale : CurrentGrabbableInRange) + for (UInteractableComponent* Grabbale : CurrentGrabbableInRange) { - Grabbale->HandleOnClickEndEvents(this, Value); + Grabbale->HandleOnActionEndEvents(this, GrabInputAction, Value, EInteractorType::Grab); } } diff --git a/Source/RWTHVRToolkit/Private/Interaction/Interactors/RaycastSelectionComponent.cpp b/Source/RWTHVRToolkit/Private/Interaction/Interactors/RaycastSelectionComponent.cpp index 8798f6a52d6421aa4ee6d8f762ef72d502ef1fc7..be22429936c5b2aeea654f8b05c3c302f2950bee 100644 --- a/Source/RWTHVRToolkit/Private/Interaction/Interactors/RaycastSelectionComponent.cpp +++ b/Source/RWTHVRToolkit/Private/Interaction/Interactors/RaycastSelectionComponent.cpp @@ -5,6 +5,7 @@ #include "EnhancedInputComponent.h" #include "EnhancedInputSubsystems.h" +#include "Interaction/Interactables/InteractableComponent.h" #include "Kismet/KismetSystemLibrary.h" // Sets default values for this component's properties @@ -23,7 +24,7 @@ void URaycastSelectionComponent::TickComponent(float DeltaTime, ELevelTick TickT { Super::TickComponent(DeltaTime, TickType, ThisTickFunction); - URaycastSelectable* CurrentSelectable = nullptr; + UInteractableComponent* CurrentSelectable = nullptr; TArray<AActor*> ActorsToIgnore; @@ -41,7 +42,7 @@ void URaycastSelectionComponent::TickComponent(float DeltaTime, ELevelTick TickT AActor* HitActor = Hit.GetActor(); if (HitActor) { - URaycastSelectable* Selectable = HitActor->FindComponentByClass<URaycastSelectable>(); + UInteractableComponent* Selectable = HitActor->FindComponentByClass<UInteractableComponent>(); if (Selectable && Selectable->IsInteractable) { CurrentSelectable = Selectable; @@ -49,35 +50,31 @@ void URaycastSelectionComponent::TickComponent(float DeltaTime, ELevelTick TickT } } - CurrentRaycastSelectable = CurrentSelectable; + CurrentInteractable = CurrentSelectable; - if (CurrentRaycastSelectable != PreviousRaycastSelectable) + if (CurrentInteractable != PreviousInteractable) { - if (CurrentRaycastSelectable) - { - CurrentRaycastSelectable->HandleOnHoverStartEvents(this); - } - if (PreviousRaycastSelectable) - { - PreviousRaycastSelectable->HandleOnHoverEndEvents(this); - } + if (CurrentInteractable && CurrentInteractable->HasInteractionTypeFlag(EInteractorType::Raycast)) + CurrentInteractable->HandleOnHoverStartEvents(this, EInteractorType::Raycast); + if (PreviousInteractable && PreviousInteractable->HasInteractionTypeFlag(EInteractorType::Raycast)) + PreviousInteractable->HandleOnHoverEndEvents(this, EInteractorType::Raycast); } - PreviousRaycastSelectable = CurrentRaycastSelectable; + PreviousInteractable = CurrentInteractable; } void URaycastSelectionComponent::OnBeginSelect(const FInputActionValue& Value) { - if (CurrentRaycastSelectable) - { - CurrentRaycastSelectable->HandleOnClickStartEvents(this, Value); - } + if (CurrentInteractable && CurrentInteractable->HasInteractionTypeFlag(EInteractorType::Raycast)) + CurrentInteractable->HandleOnActionStartEvents(this, RayCastSelectInputAction, Value, + EInteractorType::Raycast); } void URaycastSelectionComponent::OnEndSelect(const FInputActionValue& Value) { - if (CurrentRaycastSelectable) - CurrentRaycastSelectable->HandleOnClickEndEvents(this, Value); + if (CurrentInteractable && CurrentInteractable->HasInteractionTypeFlag(EInteractorType::Raycast)) + CurrentInteractable->HandleOnActionEndEvents(this, RayCastSelectInputAction, Value, + EInteractorType::Raycast); } void URaycastSelectionComponent::SetupPlayerInput(UInputComponent* PlayerInputComponent) diff --git a/Source/RWTHVRToolkit/Public/Interaction/Interactables/ActionBehaviour.h b/Source/RWTHVRToolkit/Public/Interaction/Interactables/ActionBehaviour.h new file mode 100644 index 0000000000000000000000000000000000000000..14d2f407da84e380576e13d6dcc6cfaa7b0506f0 --- /dev/null +++ b/Source/RWTHVRToolkit/Public/Interaction/Interactables/ActionBehaviour.h @@ -0,0 +1,48 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "InputAction.h" +#include "Components/SceneComponent.h" +#include "InputActionValue.h" +#include "InteractionBitSet.h" +#include "ActionBehaviour.generated.h" + + +DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams(FOnActionBegin, USceneComponent*, TriggeredComponent, + const UInputAction*, + InputAction, const FInputActionValue&, Value); + +DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams(FOnActionEnd, USceneComponent*, TriggeredComponent, const UInputAction*, + InputAction, const FInputActionValue&, Value); + +UCLASS(ClassGroup=(Custom), meta=(BlueprintSpawnableComponent)) +class RWTHVRTOOLKIT_API UActionBehaviour : public USceneComponent +{ + GENERATED_BODY() + +public: + // Sets default values for this component's properties + UActionBehaviour(); + + UPROPERTY(BlueprintAssignable) + FOnActionBegin OnActionBeginEvent; + + UPROPERTY(BlueprintAssignable) + FOnActionEnd OnActionEndEvent; + +protected: + UFUNCTION() + virtual void OnActionStart(USceneComponent* TriggeredComponent, const UInputAction* InputAction, + const FInputActionValue& Value); + + UFUNCTION() + virtual void OnActionEnd(USceneComponent* TriggeredComponent, const UInputAction* InputAction, + const FInputActionValue& Value); + + virtual void BeginPlay() override; + + virtual void TickComponent(float DeltaTime, ELevelTick TickType, + FActorComponentTickFunction* ThisTickFunction) override; +}; diff --git a/Source/RWTHVRToolkit/Public/Interaction/Interactees/OnClickGrabBehavior.h b/Source/RWTHVRToolkit/Public/Interaction/Interactables/GrabBehavior.h similarity index 59% rename from Source/RWTHVRToolkit/Public/Interaction/Interactees/OnClickGrabBehavior.h rename to Source/RWTHVRToolkit/Public/Interaction/Interactables/GrabBehavior.h index 45022934b1670029f0f6257de7e855fa2e5cc7a4..b50766d60b6e71a8146f640ec3382a1637c4adff 100644 --- a/Source/RWTHVRToolkit/Public/Interaction/Interactees/OnClickGrabBehavior.h +++ b/Source/RWTHVRToolkit/Public/Interaction/Interactables/GrabBehavior.h @@ -3,13 +3,13 @@ #pragma once #include "CoreMinimal.h" -#include "ClickBehaviour.h" +#include "ActionBehaviour.h" #include "Components/SceneComponent.h" -#include "OnClickGrabBehavior.generated.h" +#include "GrabBehavior.generated.h" UCLASS(ClassGroup=(Custom), meta=(BlueprintSpawnableComponent)) -class RWTHVRTOOLKIT_API UOnClickGrabBehavior : public UClickBehaviour +class RWTHVRTOOLKIT_API UGrabBehavior : public UActionBehaviour { GENERATED_BODY() @@ -17,8 +17,10 @@ public: UPROPERTY(EditAnywhere, Category="Grabbing") bool bBlockOtherInteractionsWhileGrabbed = true; - virtual void OnClickStart(USceneComponent* TriggeredComponent, const FInputActionValue& Value) override; - virtual void OnClickEnd(USceneComponent* TriggeredComponent, const FInputActionValue& Value) override; + virtual void OnActionStart(USceneComponent* TriggeredComponent, const UInputAction* InputAction, + const FInputActionValue& Value) override; + virtual void OnActionEnd(USceneComponent* TriggeredComponent, const UInputAction* InputAction, + const FInputActionValue& Value) override; UPrimitiveComponent* GetFirstComponentSimulatingPhysics(const AActor* TargetActor); diff --git a/Source/RWTHVRToolkit/Public/Interaction/Interactees/HoverBehaviour.h b/Source/RWTHVRToolkit/Public/Interaction/Interactables/HoverBehaviour.h similarity index 100% rename from Source/RWTHVRToolkit/Public/Interaction/Interactees/HoverBehaviour.h rename to Source/RWTHVRToolkit/Public/Interaction/Interactables/HoverBehaviour.h diff --git a/Source/RWTHVRToolkit/Public/Interaction/Interactables/InteractableComponent.h b/Source/RWTHVRToolkit/Public/Interaction/Interactables/InteractableComponent.h new file mode 100644 index 0000000000000000000000000000000000000000..b3aada6852224ab480c73582afc65d81b23dd414 --- /dev/null +++ b/Source/RWTHVRToolkit/Public/Interaction/Interactables/InteractableComponent.h @@ -0,0 +1,101 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "InputAction.h" +#include "InteractionBitSet.h" +#include "Components/ActorComponent.h" +#include "InteractableComponent.generated.h" + + +struct FInputActionValue; +class UActionBehaviour; +class UHoverBehaviour; + +/* + * This class is the entry point into interactions on actors. + * The InteractorComponents will call this component to notify it about Action and Hover events. + * + * The Interactable component receives Action and Hover calls and broadcasts it to all registered + * Action and Hover Behaviour components. + * + * The Interactable can be filtered. + * Currently we filter on the InteractorType, e.g.: Raycast, Spherecast, etc. + * + * Action and Hover Behaviours can be manually added via Blueprints on a per-Interactable basis. + * If no Action and Hover Behaviours are set manually, all Action and Hover behaviours that are + * attached to the Actor are used. + * + */ +UCLASS(ClassGroup=(Custom), meta=(BlueprintSpawnableComponent)) +class RWTHVRTOOLKIT_API UInteractableComponent : public UActorComponent +{ + GENERATED_BODY() + +public: + UPROPERTY(EditAnywhere, BlueprintReadWrite) + bool IsInteractable = true; + + UPROPERTY(BlueprintReadWrite, EditAnywhere, meta = (Bitmask, BitmaskEnum = EInteractorType)) + int32 InteractorFilter = 0; + + UPROPERTY(EditAnywhere, BlueprintReadWrite) + TArray<UHoverBehaviour*> OnHoverBehaviours; + + UPROPERTY(EditAnywhere, BlueprintReadWrite) + TArray<UActionBehaviour*> OnActionBehaviours; + + UFUNCTION(BlueprintCallable) + FORCEINLINE bool HasInteractionTypeFlag(EInteractorType type) + { + return type & InteractorFilter; + } + + /** + * @brief Restrict interactability to given components (e.g. if an object is grabbed, block interactions from other components) + * @param Components + */ + UFUNCTION() + void RestrictInteractionToComponents(const TArray<USceneComponent*>& Components); + + UFUNCTION() + void RestrictInteractionToComponent(USceneComponent* Component); + + UFUNCTION() + void ResetRestrictInteraction(); + +protected: + // Called when the game starts + virtual void BeginPlay() override; + +public: + void HandleOnHoverStartEvents(USceneComponent* TriggerComponent, const EInteractorType Interactor); + void HandleOnHoverEndEvents(USceneComponent* TriggerComponent, const EInteractorType Interactor); + void HandleOnActionStartEvents(USceneComponent* TriggerComponent, const UInputAction* InputAction, + const FInputActionValue& Value, + const EInteractorType Interactor); + void HandleOnActionEndEvents(USceneComponent* TriggerComponent, const UInputAction* InputAction, + const FInputActionValue& Value, + const EInteractorType Interactor); + + /** + * @brief If click and grab behaviors are not explicitly specified, load all existing ones + */ + void InitDefaultBehaviourReferences(); + + // Hit event of component that triggered this interactable + UPROPERTY() + FHitResult HitResult; + + UPROPERTY() + bool bRestrictInteraction; + + UPROPERTY() + TArray<USceneComponent*> AllowedComponents; + + bool IsComponentAllowed(USceneComponent* Component) const; + +private: + bool bInitOnce = true; +}; diff --git a/Source/RWTHVRToolkit/Public/Interaction/Interactables/InteractionBitSet.h b/Source/RWTHVRToolkit/Public/Interaction/Interactables/InteractionBitSet.h new file mode 100644 index 0000000000000000000000000000000000000000..e8dd1afcdc3c58c33fbe31ad01eeedf145ea26ec --- /dev/null +++ b/Source/RWTHVRToolkit/Public/Interaction/Interactables/InteractionBitSet.h @@ -0,0 +1,41 @@ +#pragma once + +UENUM(BlueprintType, meta = (Bitflags, UseEnumValuesAsMaskValuesInEditor = "true")) +enum EInteractorType: int +{ + None = 0 UMETA(Hidden), + Raycast = 1 << 0, + Spherecast = 1 << 1, + Grab = 1 << 2, + Reserved2 = 1 << 3, + Reserved3 = 1 << 4, + Reserved4 = 1 << 5, + Reserved5 = 1 << 6, + Reserved6 = 1 << 7, + Reserved7 = 1 << 8, + Reserved8 = 1 << 9, + Reserved9 = 1 << 10, + Reserved10 = 1 << 11, + Reserved11 = 1 << 12, + Reserved12 = 1 << 13, + Reserved13 = 1 << 14, + Reserved14 = 1 << 15, + Custom1 = 1 << 16, + Custom2 = 1 << 17, + Custom3 = 1 << 18, + Custom4 = 1 << 19, + Custom5 = 1 << 20, + Custom6 = 1 << 21, + Custom7 = 1 << 22, + Custom8 = 1 << 23, + Custom9 = 1 << 24, + Custom10 = 1 << 25, + Custom11 = 1 << 26, + Custom12 = 1 << 27, + Custom13 = 1 << 28, + Custom14 = 1 << 29, + Custom15 = 1 << 30 +}; + + +ENUM_CLASS_FLAGS(EInteractorType); diff --git a/Source/RWTHVRToolkit/Public/Interaction/Interactees/ClickBehaviour.h b/Source/RWTHVRToolkit/Public/Interaction/Interactees/ClickBehaviour.h deleted file mode 100644 index c2116085249b761ec8e3bfe486817fea669bc06c..0000000000000000000000000000000000000000 --- a/Source/RWTHVRToolkit/Public/Interaction/Interactees/ClickBehaviour.h +++ /dev/null @@ -1,43 +0,0 @@ -// Fill out your copyright notice in the Description page of Project Settings. - -#pragma once - -#include "CoreMinimal.h" -#include "Components/SceneComponent.h" -#include "InputActionValue.h" -#include "ClickBehaviour.generated.h" - - -DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnClickStart, USceneComponent*, TriggeredComponent, - const FInputActionValue&, Value); - -DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnClicktEnd, USceneComponent*, TriggeredComponent, - const FInputActionValue&, Value); - -UCLASS(ClassGroup=(Custom), meta=(BlueprintSpawnableComponent)) -class RWTHVRTOOLKIT_API UClickBehaviour : public USceneComponent -{ - GENERATED_BODY() - -public: - // Sets default values for this component's properties - UClickBehaviour(); - - UPROPERTY(BlueprintAssignable) - FOnClickStart OnClickStartEvent; - - UPROPERTY(BlueprintAssignable) - FOnClicktEnd OnClickEndEvent; - -protected: - UFUNCTION() - virtual void OnClickStart(USceneComponent* TriggeredComponent, const FInputActionValue& Value); - - UFUNCTION() - virtual void OnClickEnd(USceneComponent* TriggeredComponent, const FInputActionValue& Value); - - virtual void BeginPlay() override; - - virtual void TickComponent(float DeltaTime, ELevelTick TickType, - FActorComponentTickFunction* ThisTickFunction) override; -}; diff --git a/Source/RWTHVRToolkit/Public/Interaction/Interactees/GrabbableComponent.h b/Source/RWTHVRToolkit/Public/Interaction/Interactees/GrabbableComponent.h deleted file mode 100644 index 9276b29eb3cead4bf5910022083bec26f5e01856..0000000000000000000000000000000000000000 --- a/Source/RWTHVRToolkit/Public/Interaction/Interactees/GrabbableComponent.h +++ /dev/null @@ -1,16 +0,0 @@ -// Fill out your copyright notice in the Description page of Project Settings. - -#pragma once - -#include "CoreMinimal.h" -#include "Interaction/Interactees/InteractableBase.h" -#include "GrabbableComponent.generated.h" - -/** - * - */ -UCLASS(ClassGroup=(Custom), meta=(BlueprintSpawnableComponent)) -class RWTHVRTOOLKIT_API UGrabbableComponent : public UInteractableBase -{ - GENERATED_BODY() -}; diff --git a/Source/RWTHVRToolkit/Public/Interaction/Interactees/InteractableBase.h b/Source/RWTHVRToolkit/Public/Interaction/Interactees/InteractableBase.h deleted file mode 100644 index c291ff27c88f8df0bcd31158003abe38be5c32ef..0000000000000000000000000000000000000000 --- a/Source/RWTHVRToolkit/Public/Interaction/Interactees/InteractableBase.h +++ /dev/null @@ -1,71 +0,0 @@ -// Fill out your copyright notice in the Description page of Project Settings. - -#pragma once - -#include "CoreMinimal.h" -#include "Components/ActorComponent.h" -#include "InteractableBase.generated.h" - - -struct FInputActionValue; -class UClickBehaviour; -class UHoverBehaviour; - -UCLASS(ClassGroup=(Custom), meta=(BlueprintSpawnableComponent)) -class RWTHVRTOOLKIT_API UInteractableBase : public UActorComponent -{ - GENERATED_BODY() - -public: - UPROPERTY(EditAnywhere, BlueprintReadWrite) - bool IsInteractable = true; - - UPROPERTY(EditAnywhere, BlueprintReadWrite) - TArray<UHoverBehaviour*> OnHoverBehaviours; - - UPROPERTY(EditAnywhere, BlueprintReadWrite) - TArray<UClickBehaviour*> OnClickBehaviours; - - /** - * @brief Restrict interactability to given components (e.g. if an object is grabbed, block interactions from other components) - * @param Components - */ - UFUNCTION() - void RestrictInteractionToComponents(const TArray<USceneComponent*>& Components); - - UFUNCTION() - void RestrictInteractionToComponent(USceneComponent* Component); - - UFUNCTION() - void ResetRestrictInteraction(); - -protected: - // Called when the game starts - virtual void BeginPlay() override; - -public: - void HandleOnHoverStartEvents(USceneComponent* TriggerComponent); - void HandleOnHoverEndEvents(USceneComponent* TriggerComponent); - void HandleOnClickStartEvents(USceneComponent* TriggerComponent, const FInputActionValue& Value); - void HandleOnClickEndEvents(USceneComponent* TriggerComponent, const FInputActionValue& Value); - - /** - * @brief If click and grab behaviors are not explicitly specified, load all existing ones - */ - void InitDefaultBehaviourReferences(); - - // Hit event of component that triggered this interactable - UPROPERTY() - FHitResult HitResult; - - UPROPERTY() - bool bRestrictInteraction; - - UPROPERTY() - TArray<USceneComponent*> AllowedComponents; - - bool IsComponentAllowed(USceneComponent* Component) const; - -private: - bool bInitOnce = true; -}; diff --git a/Source/RWTHVRToolkit/Public/Interaction/Interactees/RaycastSelectable.h b/Source/RWTHVRToolkit/Public/Interaction/Interactees/RaycastSelectable.h deleted file mode 100644 index 65fdc8b28b559761af8f439bfb1d6a4720e40cc7..0000000000000000000000000000000000000000 --- a/Source/RWTHVRToolkit/Public/Interaction/Interactees/RaycastSelectable.h +++ /dev/null @@ -1,16 +0,0 @@ -// Fill out your copyright notice in the Description page of Project Settings. - -#pragma once - -#include "CoreMinimal.h" -#include "Interaction/Interactees/InteractableBase.h" -#include "RaycastSelectable.generated.h" - -/** - * - */ -UCLASS(ClassGroup=(Custom), meta=(BlueprintSpawnableComponent)) -class RWTHVRTOOLKIT_API URaycastSelectable : public UInteractableBase -{ - GENERATED_BODY() -}; diff --git a/Source/RWTHVRToolkit/Public/Interaction/Interactors/GrabComponent.h b/Source/RWTHVRToolkit/Public/Interaction/Interactors/GrabComponent.h index dd0676c12a3d9bbb0716ff0d6c50373c2f528901..cb154963f9c86ca26e7f20cd9e8afb38821c2037 100644 --- a/Source/RWTHVRToolkit/Public/Interaction/Interactors/GrabComponent.h +++ b/Source/RWTHVRToolkit/Public/Interaction/Interactors/GrabComponent.h @@ -4,6 +4,7 @@ #include "CoreMinimal.h" #include "Components/SceneComponent.h" +#include "Interaction/Interactables/InteractableComponent.h" #include "Pawn/InputExtensionInterface.h" #include "GrabComponent.generated.h" @@ -43,8 +44,8 @@ private: void OnEndGrab(const FInputActionValue& Value); UPROPERTY() - TArray<UGrabbableComponent*> PreviousGrabbablesInRange; + TArray<UInteractableComponent*> PreviousGrabbablesInRange; UPROPERTY() - TArray<UGrabbableComponent*> CurrentGrabbableInRange; + TArray<UInteractableComponent*> CurrentGrabbableInRange; }; diff --git a/Source/RWTHVRToolkit/Public/Interaction/Interactors/RaycastSelectionComponent.h b/Source/RWTHVRToolkit/Public/Interaction/Interactors/RaycastSelectionComponent.h index 03e73b39631ff6662194d9ce57eab438e61c78fd..9d70e04e2ecce78fe053c0cdbd0951a1deda5737 100644 --- a/Source/RWTHVRToolkit/Public/Interaction/Interactors/RaycastSelectionComponent.h +++ b/Source/RWTHVRToolkit/Public/Interaction/Interactors/RaycastSelectionComponent.h @@ -5,7 +5,6 @@ #include <Pawn/InputExtensionInterface.h> #include "CoreMinimal.h" -#include "Interaction/Interactees/RaycastSelectable.h" #include "Components/SceneComponent.h" #include "RaycastSelectionComponent.generated.h" @@ -47,8 +46,8 @@ public: private: UPROPERTY() - URaycastSelectable* PreviousRaycastSelectable; + UInteractableComponent* PreviousInteractable; UPROPERTY() - URaycastSelectable* CurrentRaycastSelectable; + UInteractableComponent* CurrentInteractable; };