Skip to content
Snippets Groups Projects
Commit 0b30ed2e authored by Marcel Krüger's avatar Marcel Krüger
Browse files

Merge branch 'refactor/interaction' into 'dev/5.3'

refactor(interaction): Change to a bitflag based sytem

See merge request !42
parents 6fc4cefd 02a453cd
No related branches found
No related tags found
1 merge request!42refactor(interaction): Change to a bitflag based sytem
Showing
with 430 additions and 246 deletions
// 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);
}
// Fill out your copyright notice in the Description page of Project Settings. // Fill out your copyright notice in the Description page of Project Settings.
#include "Interaction/Interactees/OnClickGrabBehavior.h" #include "Interaction/Interactables/GrabBehavior.h"
#include "Interaction/Interactables/InteractableComponent.h"
#include "Interaction/Interactees/InteractableBase.h"
#include "Kismet/GameplayStatics.h" #include "Kismet/GameplayStatics.h"
#include "Serialization/JsonTypes.h" #include "Serialization/JsonTypes.h"
UPrimitiveComponent* UOnClickGrabBehavior::GetFirstComponentSimulatingPhysics(const AActor* TargetActor) UPrimitiveComponent* UGrabBehavior::GetFirstComponentSimulatingPhysics(const AActor* TargetActor)
{ {
TArray<UPrimitiveComponent*> PrimitiveComponents; TArray<UPrimitiveComponent*> PrimitiveComponents;
TargetActor->GetComponents<UPrimitiveComponent>(PrimitiveComponents); TargetActor->GetComponents<UPrimitiveComponent>(PrimitiveComponents);
...@@ -24,7 +23,7 @@ UPrimitiveComponent* UOnClickGrabBehavior::GetFirstComponentSimulatingPhysics(co ...@@ -24,7 +23,7 @@ UPrimitiveComponent* UOnClickGrabBehavior::GetFirstComponentSimulatingPhysics(co
} }
// recursively goes up the hierarchy and returns the highest parent simulating physics // 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()) if (Cast<UPrimitiveComponent>(Comp->GetAttachParent()) && Comp->GetAttachParent()->IsSimulatingPhysics())
{ {
...@@ -36,7 +35,8 @@ UPrimitiveComponent* UOnClickGrabBehavior::GetHighestParentSimulatingPhysics(UPr ...@@ -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); const APawn* Player = UGameplayStatics::GetPlayerPawn(GetWorld(), 0);
...@@ -59,16 +59,17 @@ void UOnClickGrabBehavior::OnClickStart(USceneComponent* TriggeredComponent, con ...@@ -59,16 +59,17 @@ void UOnClickGrabBehavior::OnClickStart(USceneComponent* TriggeredComponent, con
if (bBlockOtherInteractionsWhileGrabbed) if (bBlockOtherInteractionsWhileGrabbed)
{ {
TArray<UInteractableBase*> Interactables; TArray<UInteractableComponent*> Interactables;
GetOwner()->GetComponents<UInteractableBase>(Interactables, false); GetOwner()->GetComponents<UInteractableComponent>(Interactables, false);
for (UInteractableBase* Interactable : Interactables) for (UInteractableComponent* Interactable : Interactables)
{ {
Interactable->RestrictInteractionToComponent(TriggeredComponent); Interactable->RestrictInteractionToComponent(TriggeredComponent);
} }
} }
} }
void UOnClickGrabBehavior::OnClickEnd(USceneComponent* TriggeredComponent, const FInputActionValue& Value) void UGrabBehavior::OnActionEnd(USceneComponent* TriggeredComponent, const UInputAction* InputAction,
const FInputActionValue& Value)
{ {
if (MyPhysicsComponent) if (MyPhysicsComponent)
{ {
...@@ -82,9 +83,9 @@ void UOnClickGrabBehavior::OnClickEnd(USceneComponent* TriggeredComponent, const ...@@ -82,9 +83,9 @@ void UOnClickGrabBehavior::OnClickEnd(USceneComponent* TriggeredComponent, const
if (bBlockOtherInteractionsWhileGrabbed) if (bBlockOtherInteractionsWhileGrabbed)
{ {
TArray<UInteractableBase*> Interactables; TArray<UInteractableComponent*> Interactables;
GetOwner()->GetComponents<UInteractableBase>(Interactables, false); GetOwner()->GetComponents<UInteractableComponent>(Interactables, false);
for (UInteractableBase* Interactable : Interactables) for (UInteractableComponent* Interactable : Interactables)
{ {
Interactable->ResetRestrictInteraction(); Interactable->ResetRestrictInteraction();
} }
......
// Fill out your copyright notice in the Description page of Project Settings. // 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) void UHoverBehaviour::OnHoverStart(const USceneComponent* TriggeredComponent, FHitResult Hit)
{ {
......
// 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;
}
// 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);
}
// Fill out your copyright notice in the Description page of Project Settings.
#include "Interaction/Interactees/GrabbableComponent.h"
// 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;
}
// Fill out your copyright notice in the Description page of Project Settings.
#include "Interaction/Interactees/RaycastSelectable.h"
...@@ -5,7 +5,8 @@ ...@@ -5,7 +5,8 @@
#include "EnhancedInputComponent.h" #include "EnhancedInputComponent.h"
#include "EnhancedInputSubsystems.h" #include "EnhancedInputSubsystems.h"
#include "Interaction/Interactees/GrabbableComponent.h" #include "Interaction/Interactables/InteractableComponent.h"
#include "Interaction/Interactables/InteractionBitSet.h"
#include "Kismet/GameplayStatics.h" #include "Kismet/GameplayStatics.h"
...@@ -24,7 +25,7 @@ void UGrabComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorC ...@@ -24,7 +25,7 @@ void UGrabComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorC
Super::TickComponent(DeltaTime, TickType, ThisTickFunction); Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
TArray<UGrabbableComponent*> CurrentGrabCompsInRange; TArray<UInteractableComponent*> CurrentGrabCompsInRange;
TArray<AActor*> ActorsToIgnore; TArray<AActor*> ActorsToIgnore;
TArray<FHitResult> OutHits; TArray<FHitResult> OutHits;
...@@ -42,8 +43,8 @@ void UGrabComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorC ...@@ -42,8 +43,8 @@ void UGrabComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorC
AActor* HitActor = Hit.GetActor(); AActor* HitActor = Hit.GetActor();
if (HitActor) if (HitActor)
{ {
UGrabbableComponent* Grabbable = HitActor->FindComponentByClass<UGrabbableComponent>(); UInteractableComponent* Grabbable = HitActor->FindComponentByClass<UInteractableComponent>();
if (Grabbable && Grabbable->IsInteractable) if (Grabbable && Grabbable->HasInteractionTypeFlag(EInteractorType::Grab) && Grabbable->IsInteractable)
{ {
Grabbable->HitResult = Hit; Grabbable->HitResult = Hit;
CurrentGrabCompsInRange.Add(Grabbable); CurrentGrabCompsInRange.Add(Grabbable);
...@@ -54,28 +55,28 @@ void UGrabComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorC ...@@ -54,28 +55,28 @@ void UGrabComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorC
CurrentGrabbableInRange = CurrentGrabCompsInRange; CurrentGrabbableInRange = CurrentGrabCompsInRange;
// Call hover start events on all components that were not in range before // 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)) if (!PreviousGrabbablesInRange.Contains(CurrentGrabbale))
{ {
PreviousGrabbablesInRange.Add(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 // 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)) if (!CurrentGrabCompsInRange.Contains(PrevGrabbale))
{ {
ComponentsToRemove.Add(PrevGrabbale); ComponentsToRemove.Add(PrevGrabbale);
PrevGrabbale->HandleOnHoverEndEvents(this); PrevGrabbale->HandleOnHoverEndEvents(this, EInteractorType::Grab);
} }
} }
for (UGrabbableComponent* CompToRemove : ComponentsToRemove) for (UInteractableComponent* CompToRemove : ComponentsToRemove)
{ {
PreviousGrabbablesInRange.Remove(CompToRemove); PreviousGrabbablesInRange.Remove(CompToRemove);
} }
...@@ -106,16 +107,16 @@ void UGrabComponent::SetupPlayerInput(UInputComponent* PlayerInputComponent) ...@@ -106,16 +107,16 @@ void UGrabComponent::SetupPlayerInput(UInputComponent* PlayerInputComponent)
void UGrabComponent::OnBeginGrab(const FInputActionValue& Value) 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) 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);
} }
} }
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include "EnhancedInputComponent.h" #include "EnhancedInputComponent.h"
#include "EnhancedInputSubsystems.h" #include "EnhancedInputSubsystems.h"
#include "Interaction/Interactables/InteractableComponent.h"
#include "Kismet/KismetSystemLibrary.h" #include "Kismet/KismetSystemLibrary.h"
// Sets default values for this component's properties // Sets default values for this component's properties
...@@ -23,7 +24,7 @@ void URaycastSelectionComponent::TickComponent(float DeltaTime, ELevelTick TickT ...@@ -23,7 +24,7 @@ void URaycastSelectionComponent::TickComponent(float DeltaTime, ELevelTick TickT
{ {
Super::TickComponent(DeltaTime, TickType, ThisTickFunction); Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
URaycastSelectable* CurrentSelectable = nullptr; UInteractableComponent* CurrentSelectable = nullptr;
TArray<AActor*> ActorsToIgnore; TArray<AActor*> ActorsToIgnore;
...@@ -41,7 +42,7 @@ void URaycastSelectionComponent::TickComponent(float DeltaTime, ELevelTick TickT ...@@ -41,7 +42,7 @@ void URaycastSelectionComponent::TickComponent(float DeltaTime, ELevelTick TickT
AActor* HitActor = Hit.GetActor(); AActor* HitActor = Hit.GetActor();
if (HitActor) if (HitActor)
{ {
URaycastSelectable* Selectable = HitActor->FindComponentByClass<URaycastSelectable>(); UInteractableComponent* Selectable = HitActor->FindComponentByClass<UInteractableComponent>();
if (Selectable && Selectable->IsInteractable) if (Selectable && Selectable->IsInteractable)
{ {
CurrentSelectable = Selectable; CurrentSelectable = Selectable;
...@@ -49,35 +50,31 @@ void URaycastSelectionComponent::TickComponent(float DeltaTime, ELevelTick TickT ...@@ -49,35 +50,31 @@ void URaycastSelectionComponent::TickComponent(float DeltaTime, ELevelTick TickT
} }
} }
CurrentRaycastSelectable = CurrentSelectable; CurrentInteractable = CurrentSelectable;
if (CurrentRaycastSelectable != PreviousRaycastSelectable) if (CurrentInteractable != PreviousInteractable)
{ {
if (CurrentRaycastSelectable) if (CurrentInteractable && CurrentInteractable->HasInteractionTypeFlag(EInteractorType::Raycast))
{ CurrentInteractable->HandleOnHoverStartEvents(this, EInteractorType::Raycast);
CurrentRaycastSelectable->HandleOnHoverStartEvents(this); if (PreviousInteractable && PreviousInteractable->HasInteractionTypeFlag(EInteractorType::Raycast))
} PreviousInteractable->HandleOnHoverEndEvents(this, EInteractorType::Raycast);
if (PreviousRaycastSelectable)
{
PreviousRaycastSelectable->HandleOnHoverEndEvents(this);
}
} }
PreviousRaycastSelectable = CurrentRaycastSelectable; PreviousInteractable = CurrentInteractable;
} }
void URaycastSelectionComponent::OnBeginSelect(const FInputActionValue& Value) void URaycastSelectionComponent::OnBeginSelect(const FInputActionValue& Value)
{ {
if (CurrentRaycastSelectable) if (CurrentInteractable && CurrentInteractable->HasInteractionTypeFlag(EInteractorType::Raycast))
{ CurrentInteractable->HandleOnActionStartEvents(this, RayCastSelectInputAction, Value,
CurrentRaycastSelectable->HandleOnClickStartEvents(this, Value); EInteractorType::Raycast);
}
} }
void URaycastSelectionComponent::OnEndSelect(const FInputActionValue& Value) void URaycastSelectionComponent::OnEndSelect(const FInputActionValue& Value)
{ {
if (CurrentRaycastSelectable) if (CurrentInteractable && CurrentInteractable->HasInteractionTypeFlag(EInteractorType::Raycast))
CurrentRaycastSelectable->HandleOnClickEndEvents(this, Value); CurrentInteractable->HandleOnActionEndEvents(this, RayCastSelectInputAction, Value,
EInteractorType::Raycast);
} }
void URaycastSelectionComponent::SetupPlayerInput(UInputComponent* PlayerInputComponent) void URaycastSelectionComponent::SetupPlayerInput(UInputComponent* PlayerInputComponent)
......
...@@ -3,38 +3,43 @@ ...@@ -3,38 +3,43 @@
#pragma once #pragma once
#include "CoreMinimal.h" #include "CoreMinimal.h"
#include "InputAction.h"
#include "Components/SceneComponent.h" #include "Components/SceneComponent.h"
#include "InputActionValue.h" #include "InputActionValue.h"
#include "ClickBehaviour.generated.h" #include "InteractionBitSet.h"
#include "ActionBehaviour.generated.h"
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnClickStart, USceneComponent*, TriggeredComponent, DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams(FOnActionBegin, USceneComponent*, TriggeredComponent,
const FInputActionValue&, Value); const UInputAction*,
InputAction, const FInputActionValue&, Value);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnClicktEnd, USceneComponent*, TriggeredComponent, DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams(FOnActionEnd, USceneComponent*, TriggeredComponent, const UInputAction*,
const FInputActionValue&, Value); InputAction, const FInputActionValue&, Value);
UCLASS(ClassGroup=(Custom), meta=(BlueprintSpawnableComponent)) UCLASS(ClassGroup=(Custom), meta=(BlueprintSpawnableComponent))
class RWTHVRTOOLKIT_API UClickBehaviour : public USceneComponent class RWTHVRTOOLKIT_API UActionBehaviour : public USceneComponent
{ {
GENERATED_BODY() GENERATED_BODY()
public: public:
// Sets default values for this component's properties // Sets default values for this component's properties
UClickBehaviour(); UActionBehaviour();
UPROPERTY(BlueprintAssignable) UPROPERTY(BlueprintAssignable)
FOnClickStart OnClickStartEvent; FOnActionBegin OnActionBeginEvent;
UPROPERTY(BlueprintAssignable) UPROPERTY(BlueprintAssignable)
FOnClicktEnd OnClickEndEvent; FOnActionEnd OnActionEndEvent;
protected: protected:
UFUNCTION() UFUNCTION()
virtual void OnClickStart(USceneComponent* TriggeredComponent, const FInputActionValue& Value); virtual void OnActionStart(USceneComponent* TriggeredComponent, const UInputAction* InputAction,
const FInputActionValue& Value);
UFUNCTION() UFUNCTION()
virtual void OnClickEnd(USceneComponent* TriggeredComponent, const FInputActionValue& Value); virtual void OnActionEnd(USceneComponent* TriggeredComponent, const UInputAction* InputAction,
const FInputActionValue& Value);
virtual void BeginPlay() override; virtual void BeginPlay() override;
......
...@@ -3,13 +3,13 @@ ...@@ -3,13 +3,13 @@
#pragma once #pragma once
#include "CoreMinimal.h" #include "CoreMinimal.h"
#include "ClickBehaviour.h" #include "ActionBehaviour.h"
#include "Components/SceneComponent.h" #include "Components/SceneComponent.h"
#include "OnClickGrabBehavior.generated.h" #include "GrabBehavior.generated.h"
UCLASS(ClassGroup=(Custom), meta=(BlueprintSpawnableComponent)) UCLASS(ClassGroup=(Custom), meta=(BlueprintSpawnableComponent))
class RWTHVRTOOLKIT_API UOnClickGrabBehavior : public UClickBehaviour class RWTHVRTOOLKIT_API UGrabBehavior : public UActionBehaviour
{ {
GENERATED_BODY() GENERATED_BODY()
...@@ -17,8 +17,10 @@ public: ...@@ -17,8 +17,10 @@ public:
UPROPERTY(EditAnywhere, Category="Grabbing") UPROPERTY(EditAnywhere, Category="Grabbing")
bool bBlockOtherInteractionsWhileGrabbed = true; bool bBlockOtherInteractionsWhileGrabbed = true;
virtual void OnClickStart(USceneComponent* TriggeredComponent, const FInputActionValue& Value) override; virtual void OnActionStart(USceneComponent* TriggeredComponent, const UInputAction* InputAction,
virtual void OnClickEnd(USceneComponent* TriggeredComponent, const FInputActionValue& Value) override; const FInputActionValue& Value) override;
virtual void OnActionEnd(USceneComponent* TriggeredComponent, const UInputAction* InputAction,
const FInputActionValue& Value) override;
UPrimitiveComponent* GetFirstComponentSimulatingPhysics(const AActor* TargetActor); UPrimitiveComponent* GetFirstComponentSimulatingPhysics(const AActor* TargetActor);
......
...@@ -3,16 +3,33 @@ ...@@ -3,16 +3,33 @@
#pragma once #pragma once
#include "CoreMinimal.h" #include "CoreMinimal.h"
#include "InputAction.h"
#include "InteractionBitSet.h"
#include "Components/ActorComponent.h" #include "Components/ActorComponent.h"
#include "InteractableBase.generated.h" #include "InteractableComponent.generated.h"
struct FInputActionValue; struct FInputActionValue;
class UClickBehaviour; class UActionBehaviour;
class UHoverBehaviour; 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)) UCLASS(ClassGroup=(Custom), meta=(BlueprintSpawnableComponent))
class RWTHVRTOOLKIT_API UInteractableBase : public UActorComponent class RWTHVRTOOLKIT_API UInteractableComponent : public UActorComponent
{ {
GENERATED_BODY() GENERATED_BODY()
...@@ -20,11 +37,20 @@ public: ...@@ -20,11 +37,20 @@ public:
UPROPERTY(EditAnywhere, BlueprintReadWrite) UPROPERTY(EditAnywhere, BlueprintReadWrite)
bool IsInteractable = true; bool IsInteractable = true;
UPROPERTY(BlueprintReadWrite, EditAnywhere, meta = (Bitmask, BitmaskEnum = EInteractorType))
int32 InteractorFilter = 0;
UPROPERTY(EditAnywhere, BlueprintReadWrite) UPROPERTY(EditAnywhere, BlueprintReadWrite)
TArray<UHoverBehaviour*> OnHoverBehaviours; TArray<UHoverBehaviour*> OnHoverBehaviours;
UPROPERTY(EditAnywhere, BlueprintReadWrite) UPROPERTY(EditAnywhere, BlueprintReadWrite)
TArray<UClickBehaviour*> OnClickBehaviours; 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) * @brief Restrict interactability to given components (e.g. if an object is grabbed, block interactions from other components)
...@@ -44,10 +70,14 @@ protected: ...@@ -44,10 +70,14 @@ protected:
virtual void BeginPlay() override; virtual void BeginPlay() override;
public: public:
void HandleOnHoverStartEvents(USceneComponent* TriggerComponent); void HandleOnHoverStartEvents(USceneComponent* TriggerComponent, const EInteractorType Interactor);
void HandleOnHoverEndEvents(USceneComponent* TriggerComponent); void HandleOnHoverEndEvents(USceneComponent* TriggerComponent, const EInteractorType Interactor);
void HandleOnClickStartEvents(USceneComponent* TriggerComponent, const FInputActionValue& Value); void HandleOnActionStartEvents(USceneComponent* TriggerComponent, const UInputAction* InputAction,
void HandleOnClickEndEvents(USceneComponent* TriggerComponent, const FInputActionValue& Value); 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 * @brief If click and grab behaviors are not explicitly specified, load all existing ones
......
#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);
// 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()
};
// 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()
};
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include "CoreMinimal.h" #include "CoreMinimal.h"
#include "Components/SceneComponent.h" #include "Components/SceneComponent.h"
#include "Interaction/Interactables/InteractableComponent.h"
#include "Pawn/InputExtensionInterface.h" #include "Pawn/InputExtensionInterface.h"
#include "GrabComponent.generated.h" #include "GrabComponent.generated.h"
...@@ -43,8 +44,8 @@ private: ...@@ -43,8 +44,8 @@ private:
void OnEndGrab(const FInputActionValue& Value); void OnEndGrab(const FInputActionValue& Value);
UPROPERTY() UPROPERTY()
TArray<UGrabbableComponent*> PreviousGrabbablesInRange; TArray<UInteractableComponent*> PreviousGrabbablesInRange;
UPROPERTY() UPROPERTY()
TArray<UGrabbableComponent*> CurrentGrabbableInRange; TArray<UInteractableComponent*> CurrentGrabbableInRange;
}; };
...@@ -5,7 +5,6 @@ ...@@ -5,7 +5,6 @@
#include <Pawn/InputExtensionInterface.h> #include <Pawn/InputExtensionInterface.h>
#include "CoreMinimal.h" #include "CoreMinimal.h"
#include "Interaction/Interactees/RaycastSelectable.h"
#include "Components/SceneComponent.h" #include "Components/SceneComponent.h"
#include "RaycastSelectionComponent.generated.h" #include "RaycastSelectionComponent.generated.h"
...@@ -47,8 +46,8 @@ public: ...@@ -47,8 +46,8 @@ public:
private: private:
UPROPERTY() UPROPERTY()
URaycastSelectable* PreviousRaycastSelectable; UInteractableComponent* PreviousInteractable;
UPROPERTY() UPROPERTY()
URaycastSelectable* CurrentRaycastSelectable; UInteractableComponent* CurrentInteractable;
}; };
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment