From e48bb34425c43a30d59ca65cc3305e042a05dc32 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Marcel=20Kr=C3=BCger?= <krueger@vr.rwth-aachen.de>
Date: Fri, 11 Jun 2021 11:09:24 +0200
Subject: [PATCH] Add functionality to have enter and leave events on
 targatable actor

---
 .../Pawn/BasicVRInteractionComponent.cpp      | 29 +++++++++++++++++++
 .../Public/Interaction/Targetable.h           |  8 +++++
 .../Public/Pawn/BasicVRInteractionComponent.h |  4 ++-
 3 files changed, 40 insertions(+), 1 deletion(-)

diff --git a/Source/DisplayClusterExtensions/Private/Pawn/BasicVRInteractionComponent.cpp b/Source/DisplayClusterExtensions/Private/Pawn/BasicVRInteractionComponent.cpp
index c0a06d4..fe1a96a 100644
--- a/Source/DisplayClusterExtensions/Private/Pawn/BasicVRInteractionComponent.cpp
+++ b/Source/DisplayClusterExtensions/Private/Pawn/BasicVRInteractionComponent.cpp
@@ -104,9 +104,38 @@ void UBasicVRInteractionComponent::TickComponent(float DeltaTime, ELevelTick Tic
 
 	const FTwoVectors StartEnd = GetHandRay(MaxClickDistance);
 	TOptional<FHitResult> Hit = RaytraceForFirstHit(StartEnd);
+
 	if (!Hit.IsSet())
+	{
+
+		// Execute leave event on the actor that lost the focus if there was one
+		if (LastActorHit && LastActorHit->Implements<UTargetable>())
+		{
+				ITargetable::Execute_OnTargetedLeave(LastActorHit);
+		}
+
+		LastActorHit = nullptr;
 		return;
+	}
+	
 	AActor* HitActor = Hit->GetActor();
+	LastActorHit = HitActor; // Store the actor that was hit to have access to it in the next frame as well
+
+	// Execute Leave and enter events when the focused actor changed
+	if (HitActor != LastActorHit)
+	{
+		//We can always execute the enter event as we are sure that a hit occured
+		if (HitActor->Implements<UTargetable>())
+		{
+			ITargetable::Execute_OnTargetedEnter(HitActor);
+		}
+
+		//Only execute the Leave Event if there was an actor that was focused previously
+		if (LastActorHit != nullptr && LastActorHit->Implements<UTargetable>())
+		{
+			ITargetable::Execute_OnTargetedLeave(LastActorHit);
+		}
+	}
 
 	// for now uses the same distance as clicking
 	if (HitActor->Implements<UTargetable>() && Hit->Distance < MaxClickDistance)
diff --git a/Source/DisplayClusterExtensions/Public/Interaction/Targetable.h b/Source/DisplayClusterExtensions/Public/Interaction/Targetable.h
index a11da8b..3dd1e6a 100644
--- a/Source/DisplayClusterExtensions/Public/Interaction/Targetable.h
+++ b/Source/DisplayClusterExtensions/Public/Interaction/Targetable.h
@@ -22,4 +22,12 @@ public:
 	// function that will be called when clickable actor got clicked, and passed the world pos of the click
 	UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = Gameplay)
 	void OnTargeted(FVector WorldPositionOfTarget);
+	
+	//function that will be called when a targetable actor gets focused
+	UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = Gameplay)
+	void OnTargetedEnter();
+
+	//function that will be called when a targetable actor loses focused
+	UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = Gameplay)
+	void OnTargetedLeave();
 };
diff --git a/Source/DisplayClusterExtensions/Public/Pawn/BasicVRInteractionComponent.h b/Source/DisplayClusterExtensions/Public/Pawn/BasicVRInteractionComponent.h
index 6e86c20..bf02488 100644
--- a/Source/DisplayClusterExtensions/Public/Pawn/BasicVRInteractionComponent.h
+++ b/Source/DisplayClusterExtensions/Public/Pawn/BasicVRInteractionComponent.h
@@ -40,7 +40,9 @@ private:
 	UPROPERTY() UPrimitiveComponent* ComponentSimulatingPhysics = nullptr;
 	UPROPERTY() UGrabbingBehaviorComponent* Behavior = nullptr;
 	UPROPERTY() USceneComponent* InteractionRayEmitter = nullptr;
-	
+	UPROPERTY() UStaticMeshComponent* InteractionRay = nullptr;
+	/* Stores the reference of the Actor that was hit in the last frame*/
+	UPROPERTY() AActor* LastActorHit = nullptr;
 	void HandlePhysicsAndAttachActor(AActor* HitActor);
 	FTwoVectors GetHandRay(float Length) const;
 	TOptional<FHitResult> RaytraceForFirstHit(const FTwoVectors& Ray) const;
-- 
GitLab