From c74a19c1dfe319ffd3bbfe4764741359ad199d91 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timon=20R=C3=B6mer?= <t.roemer@vr.rwth-aachen.de>
Date: Fri, 22 Mar 2024 15:14:04 +0100
Subject: [PATCH] Comments and explains IntenSelect Component source code

---
 .../Private/Pawn/IntenSelectComponent.cpp     | 322 +++++++++++++-----
 .../Public/Pawn/IntenSelectComponent.h        | 152 ++++++++-
 2 files changed, 379 insertions(+), 95 deletions(-)

diff --git a/Source/RWTHVRToolkit/Private/Pawn/IntenSelectComponent.cpp b/Source/RWTHVRToolkit/Private/Pawn/IntenSelectComponent.cpp
index d3970f5c..130b0efe 100644
--- a/Source/RWTHVRToolkit/Private/Pawn/IntenSelectComponent.cpp
+++ b/Source/RWTHVRToolkit/Private/Pawn/IntenSelectComponent.cpp
@@ -77,37 +77,57 @@ void UIntenSelectComponent::BeginPlay()
 	InitInputBindings();
 	InitMaterialParamCollection();
 
+	// Calculate sphere cast radius
 	SphereCastRadius = CalculateSphereCastRadius();
+
+	// Set interaction distance to maximum selection distance
 	InteractionDistance = MaxSelectionDistance;
 
+	// Set the component active based on the SetActiveOnStart flag
 	SetActive(SetActiveOnStart, false);
 }
 
 void UIntenSelectComponent::InitInputBindings()
 {
-	const APawn* Pawn = Cast<APawn>(GetOwner());
-	if (!Pawn)
-		return;
-	UEnhancedInputComponent* EI = Cast<UEnhancedInputComponent>(Pawn->InputComponent);
+	// Get the player controller
+	const APlayerController* PC = UGameplayStatics::GetPlayerController(GetWorld(), 0);
+
+	// Get the local player subsystem for enhanced input
+	UEnhancedInputLocalPlayerSubsystem* Subsystem =
+		ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(PC->GetLocalPlayer());
 
-	if (!EI)
+	// Get the player input component
+	UInputComponent* PlayerInputComponent = PC->InputComponent;
+	UEnhancedInputComponent* PEI = Cast<UEnhancedInputComponent>(PlayerInputComponent);
+
+	// Check if the enhanced input component is valid
+	if (!PEI)
 	{
+		// Display an error message and quit the game if the enhanced input component is not found
 		const FString Message = "Could not get PlayerInputComponent for IntenSelect Input Assignment!";
+#if WITH_EDITOR
+		const FText Title = FText::FromString(FString("ERROR"));
+		FMessageDialog::Open(EAppMsgType::Ok, FText::FromString(Message), Title);
+#endif
 		UE_LOG(LogTemp, Error, TEXT("%s"), *Message)
+		UKismetSystemLibrary::QuitGame(this, nullptr, EQuitPreference::Quit, false);
 		return;
 	}
 
-	// Bind the actions
-	EI->BindAction(InputClick, ETriggerEvent::Started, this, &UIntenSelectComponent::OnFireDown);
-	EI->BindAction(InputClick, ETriggerEvent::Completed, this, &UIntenSelectComponent::OnFireUp);
+	// Bind the actions for input events
+	PEI->BindAction(InputClick, ETriggerEvent::Started, this, &UIntenSelectComponent::OnFireDown);
+	PEI->BindAction(InputClick, ETriggerEvent::Completed, this, &UIntenSelectComponent::OnFireUp);
 }
 
 void UIntenSelectComponent::InitSplineComponent()
 {
+	// Create a new spline component
 	SplineComponent = NewObject<USplineComponent>(this, TEXT("SplineComponent"));
 
+	// Check if the spline component was successfully created
 	if (SplineComponent)
 	{
+		// Setup attachment and mobility of the spline component
 		SplineComponent->SetupAttachment(this);
 		SplineComponent->SetMobility(EComponentMobility::Movable);
 		SplineComponent->RegisterComponent();
@@ -115,27 +135,32 @@ void UIntenSelectComponent::InitSplineComponent()
 	}
 	else
 	{
+		// Display an error message if the spline component creation fails
 		const FString Message = "Error while spawning SplineComponent!";
 #if WITH_EDITOR
 		const FText Title = FText::FromString(FString("ERROR"));
 		FMessageDialog::Open(EAppMsgType::Ok, FText::FromString(Message), Title);
 #endif
-
 		UE_LOG(LogTemp, Error, TEXT("%s"), *Message)
 	}
 }
 
 void UIntenSelectComponent::InitSplineMeshComponent()
 {
+	// Create a new spline mesh component
 	SplineMeshComponent =
 		NewObject<USplineMeshComponent>(this, USplineMeshComponent::StaticClass(), TEXT("SplineMeshComponent"));
+
+	// Check if the spline mesh component was successfully created
 	if (SplineMeshComponent)
 	{
+		// Setup attachment and mobility of the spline mesh component
 		SplineMeshComponent->SetupAttachment(this);
 		SplineMeshComponent->SetMobility(EComponentMobility::Movable);
 		SplineMeshComponent->RegisterComponent();
 		SplineMeshComponent->CreationMethod = EComponentCreationMethod::Instance;
 
+		// Set the static mesh if available
 		if (SplineMesh)
 		{
 			SplineMeshComponent->SetStaticMesh(SplineMesh);
@@ -145,6 +170,7 @@ void UIntenSelectComponent::InitSplineMeshComponent()
 			UE_LOG(LogTemp, Warning, TEXT("SplineMesh not set!"));
 		}
 
+		// Set the material if available
 		if (SplineMaterial)
 		{
 			SplineMeshComponent->SetMaterial(0, SplineMaterial);
@@ -154,35 +180,43 @@ void UIntenSelectComponent::InitSplineMeshComponent()
 			UE_LOG(LogTemp, Warning, TEXT("SplineMesh material not set! Using default material instead."));
 		}
 
+		// Set the forward axis and shadow casting properties
 		SplineMeshComponent->SetForwardAxis(ESplineMeshAxis::Z);
 		SplineMeshComponent->CastShadow = false;
 	}
 	else
 	{
+		// Display an error message if the spline mesh component creation fails
 		UE_LOG(LogTemp, Error, TEXT("Error while spawning SplineMeshComponent!"))
 	}
 }
 
+
 void UIntenSelectComponent::InitForwardRayMeshComponent()
 {
+	// Create a new static mesh component for the forward ray
 	ForwardRayMeshComponent =
 		NewObject<UStaticMeshComponent>(this, UStaticMeshComponent::StaticClass(), TEXT("ForwardRay"));
 
+	// Check if the forward ray mesh component was successfully created
 	if (ForwardRayMeshComponent)
 	{
+		// Setup attachment and mobility of the forward ray mesh component
 		ForwardRayMeshComponent->SetupAttachment(this);
-		ForwardRayMeshComponent->SetMobility((EComponentMobility::Movable));
+		ForwardRayMeshComponent->SetMobility(EComponentMobility::Movable);
 		ForwardRayMeshComponent->RegisterComponent();
 		ForwardRayMeshComponent->CreationMethod = EComponentCreationMethod::Instance;
 
+		// Configure shadow casting and collision properties
 		ForwardRayMeshComponent->SetCastShadow(false);
 		ForwardRayMeshComponent->SetCollisionEnabled(ECollisionEnabled::NoCollision);
 
+		// Set relative scale and location based on max selection distance
 		const float MeshLength = MaxSelectionDistance > 1000 ? 1000 : MaxSelectionDistance;
 		ForwardRayMeshComponent->SetRelativeScale3D(FVector(MeshLength, ForwardRayWidth, ForwardRayWidth));
 		ForwardRayMeshComponent->SetRelativeLocation(FVector(MeshLength * 50, 0, 0));
 
-		// const ConstructorHelpers::FObjectFinder<UStaticMesh> CubeMesh(TEXT("/Engine/BasicShapes/Cube.Cube"));
+		// Set the static mesh for the forward ray component if available
 		if (ForwardRayMesh)
 		{
 			ForwardRayMeshComponent->SetStaticMesh(ForwardRayMesh);
@@ -192,62 +226,76 @@ void UIntenSelectComponent::InitForwardRayMeshComponent()
 			UE_LOG(LogTemp, Warning, TEXT("Mesh for RayComponent not set!"));
 		}
 
+		// Create dynamic material instance for the forward ray mesh component
 		UMaterialInstanceDynamic* DynamicMaterial =
 			UMaterialInstanceDynamic::Create(ForwardRayMaterial, ForwardRayMeshComponent);
 		this->ForwardRayMeshComponent->SetMaterial(0, DynamicMaterial);
 
+		// Set visibility based on draw forward ray flag
 		ForwardRayMeshComponent->SetHiddenInGame(!bDrawForwardRay);
 	}
 	else
 	{
+		// Display an error message if the forward ray mesh component creation fails
 		UE_LOG(LogTemp, Error, TEXT("Error while spawning ForwardRayMesh component!"));
 	}
 }
 
+
 void UIntenSelectComponent::InitMaterialParamCollection()
 {
+	// Check if the material parameter collection is set
 	if (MaterialParamCollection)
 	{
+		// Get the parameter collection instance from the world
 		this->ParameterCollectionInstance = GetWorld()->GetParameterCollectionInstance(MaterialParamCollection);
 		if (this->ParameterCollectionInstance)
 		{
+			// Set the scalar parameter value for transparency
 			this->ParameterCollectionInstance->SetScalarParameterValue("Transparency", DebugRayTransparency);
 		}
 		else
 		{
+			// Display a warning if the parameter collection instance is not found
 			UE_LOG(LogTemp, Warning,
 				   TEXT("MaterialParameterCollection required for rendering of IntenSelect could not be found!"))
 		}
 	}
 	else
 	{
+		// Display a warning if the material parameter collection is not set
 		UE_LOG(LogTemp, Warning, TEXT("MaterialParameterCollection required for InteSelect visualization is not set!"));
 	}
 }
 
 void UIntenSelectComponent::InitDebugConeMeshComponent()
 {
+	// Create a new static mesh component for the debug cone
 	DebugConeMeshComponent =
 		NewObject<UStaticMeshComponent>(this, UStaticMeshComponent::StaticClass(), TEXT("DebugCone"));
 
+	// Check if the debug cone mesh component was successfully created
 	if (DebugConeMeshComponent)
 	{
+		// Setup attachment and mobility of the debug cone mesh component
 		DebugConeMeshComponent->SetupAttachment(this);
 		DebugConeMeshComponent->SetMobility(EComponentMobility::Movable);
 		DebugConeMeshComponent->RegisterComponent();
 		DebugConeMeshComponent->CreationMethod = EComponentCreationMethod::Instance;
 
-
+		// Calculate transform for the cone based on selection cone angle and distance
 		FTransform ConeTransform = DebugConeMeshComponent->GetRelativeTransform();
 		const float ConeScale = MaxSelectionDistance / 50 * FMath::Tan(FMath::DegreesToRadians(SelectionConeAngle));
 		ConeTransform.SetScale3D(FVector(ConeScale, ConeScale, MaxSelectionDistance / 100));
 
+		// Set relative transform and location for the debug cone
 		DebugConeMeshComponent->SetRelativeTransform(ConeTransform);
 		DebugConeMeshComponent->SetRelativeLocation(FVector(MaxSelectionDistance - ConeBackwardShiftDistance, 0, 0),
 													false);
 		DebugConeMeshComponent->SetRelativeRotation(DebugConeRotation, false);
 		DebugConeMeshComponent->SetCollisionEnabled(ECollisionEnabled::NoCollision);
 
+		// Set the static mesh for the debug cone component if available
 		if (DebugConeMesh)
 		{
 			DebugConeMeshComponent->SetStaticMesh(DebugConeMesh);
@@ -256,6 +304,8 @@ void UIntenSelectComponent::InitDebugConeMeshComponent()
 		{
 			UE_LOG(LogTemp, Warning, TEXT("DebugCone mesh not set!"))
 		}
+
+		// Set the material for the debug cone component if available
 		if (DebugConeMaterial)
 		{
 			DebugConeMeshComponent->SetMaterial(0, DebugConeMaterial);
@@ -265,10 +315,12 @@ void UIntenSelectComponent::InitDebugConeMeshComponent()
 			UE_LOG(LogTemp, Warning, TEXT("DebugCone material not set! Using default material instead."))
 		}
 
+		// Set visibility based on draw debug cone flag
 		DebugConeMeshComponent->SetVisibility(bDrawDebugCone);
 	}
 	else
 	{
+		// Display an error message if the debug cone mesh component creation fails
 		UE_LOG(LogTemp, Error, TEXT("Error while spawning DebugCone component!"))
 	}
 }
@@ -278,59 +330,72 @@ void UIntenSelectComponent::InitDebugConeMeshComponent()
 
 float UIntenSelectComponent::CalculateSphereCastRadius() const
 {
+	// Calculate sphere cast radius based on selection cone angle and max selection distance
 	return FMath::Tan(FMath::DegreesToRadians(SelectionConeAngle)) * MaxSelectionDistance;
 }
 
+
 bool UIntenSelectComponent::CheckPointInCone(const FVector ConeStartPoint, const FVector ConeForward,
 											 const FVector PointToTest, const float Angle) const
 {
+	// Shift the start origin point of the cone backward
 	const FVector ShiftedStartOriginPoint = ConeStartPoint - (ConeForward * ConeBackwardShiftDistance);
+
+	// Calculate the direction to the test point
 	const FVector DirectionToTestPoint = (PointToTest - ShiftedStartOriginPoint).GetSafeNormal();
 
+	// Calculate the angle to the test point
 	const float AngleToTestPoint =
 		FMath::RadiansToDegrees(FMath::Acos((FVector::DotProduct(ConeForward, DirectionToTestPoint))));
 
+	// Check if the angle to the test point is within the specified cone angle
 	return AngleToTestPoint <= Angle;
 }
 
+
 void UIntenSelectComponent::OnNewSelected_Implementation(UIntenSelectable* Selection)
 {
+	// Set the current selection
 	CurrentSelection = Selection;
 
+	// Play sound feedback if cooldown allows
 	if (FeedbackCooldown == 0)
 	{
-		// UGameplayStatics::GetPlayerController(GetWorld(), 0)->PlayHapticEffect(SelectionFeedbackHaptic,
-		// EControllerHand::Right, 0.1, false);
 		UGameplayStatics::PlaySound2D(GetWorld(), OnSelectSound);
 		FeedbackCooldown = 0.1;
 	}
 }
 
+
 bool UIntenSelectComponent::GetActorsFromSphereCast(const FVector& SphereCastStart, TArray<FHitResult>& OutHits) const
 {
+	// Calculate start and end positions for the sphere cast
 	const FVector StartPos =
 		SphereCastStart + (GetComponentTransform().GetRotation().GetForwardVector() * SphereCastRadius);
-	const FVector EndPos =
-		StartPos + (this->GetComponentTransform().GetRotation().GetForwardVector() * (MaxSelectionDistance));
+	const FVector EndPos = StartPos + (GetComponentTransform().GetRotation().GetForwardVector() * MaxSelectionDistance);
 
+	// Set up collision query parameters
 	const FCollisionQueryParams Params = FCollisionQueryParams(FName(TEXT("SphereTraceMultiForObjects")), false);
-	// GetWorld()->SweepMultiByChannel(OutHits, StartPos, EndPos, FQuat::Identity, ECC_Visibility,
-	// FCollisionShape::MakeSphere(SphereCastRadius), Params);
 
+	// Perform sphere cast
 	GetWorld()->SweepMultiByChannel(OutHits, StartPos, EndPos, FQuat::Identity, ECC_Visibility,
 									FCollisionShape::MakeSphere(SphereCastRadius), Params);
-	// UKismetSystemLibrary::SphereTraceMulti(GetWorld(),StartPos,EndPos,SphereCastRadius,ETraceTypeQuery::TraceTypeQuery1,false,{},EDrawDebugTrace::ForOneFrame,OutHits,true);
+
 	return true;
 }
 
+
 UIntenSelectable* UIntenSelectComponent::GetMaxScoreActor(const float DeltaTime)
 {
-	const FVector ConeOrigin = this->GetComponentTransform().GetLocation();
-	const FVector ConeForward = this->GetComponentTransform().GetRotation().GetForwardVector();
+	// Get cone origin and forward direction
+	const FVector ConeOrigin = GetComponentTransform().GetLocation();
+	const FVector ConeForward = GetComponentTransform().GetRotation().GetForwardVector();
 
+	// Perform sphere cast to detect selectable actors
 	TArray<FHitResult> OutHits;
 	if (GetActorsFromSphereCast(ConeOrigin, OutHits))
 	{
+		// Iterate through hit results
 		for (const FHitResult& Hit : OutHits)
 		{
 			const FVector PointToCheck = Hit.ImpactPoint;
@@ -339,36 +404,39 @@ UIntenSelectable* UIntenSelectComponent::GetMaxScoreActor(const float DeltaTime)
 			const AActor* HitActor = Hit.GetActor();
 			if (HitActor)
 			{
-				const auto Selectable = HitActor->FindComponentByClass<UIntenSelectable>();
-
+				// Check if the hit actor is selectable and within selection distance
+				UIntenSelectable* Selectable = HitActor->FindComponentByClass<UIntenSelectable>();
 				if (Selectable && Selectable->IsSelectable && DistanceToActor <= MaxSelectionDistance)
 				{
+					// Add to score map
 					ScoreMap.FindOrAdd(Selectable, 0);
 				}
 			}
 		}
 	}
 
+	// Variables for tracking the maximum score selectable
 	UIntenSelectable* MaxScoreSelectable = nullptr;
 	float MaxScore = TNumericLimits<float>::Min();
 	TArray<UIntenSelectable*> RemoveList;
 	TArray<TPair<UIntenSelectable*, FHitResult>> CandidateList;
 
-	for (TTuple<UIntenSelectable*, float>& OldScoreEntry : ScoreMap)
+	// Iterate through the score map
+	for (TPair<UIntenSelectable*, float>& OldScoreEntry : ScoreMap)
 	{
-		// GEngine->AddOnScreenDebugMessage(INDEX_NONE, 0, FColor::Black,  OldScoreEntry.Key->GetOwner()->GetName() + "
-		// - Score: " + FString::SanitizeFloat(OldScoreEntry.Value));
 		if (!OldScoreEntry.Key)
 		{
 			continue;
 		}
 
+		// Calculate the new score and contact point
 		TPair<FHitResult, float> NewScorePair = OldScoreEntry.Key->GetBestPointScorePair(
 			ConeOrigin, ConeForward, ConeBackwardShiftDistance, SelectionConeAngle, OldScoreEntry.Value, DeltaTime);
 
 		ContactPointMap.Add(OldScoreEntry.Key, NewScorePair.Key);
 		const float DistanceToActor = FVector::Dist(ConeOrigin, NewScorePair.Key.ImpactPoint);
 
+		// Check if the new score is valid and if the actor is still selectable
 		const float Eps = 0.01;
 		if (NewScorePair.Value <= 0.01 || DistanceToActor >= MaxSelectionDistance || !OldScoreEntry.Key->IsSelectable)
 		{
@@ -378,15 +446,16 @@ UIntenSelectable* UIntenSelectComponent::GetMaxScoreActor(const float DeltaTime)
 		{
 			OldScoreEntry.Value = NewScorePair.Value;
 
+			// Check if the new score exceeds the maximum score
 			if (NewScorePair.Value > (1.0 - Eps) &&
-				this->CheckPointInCone(ConeOrigin, ConeForward, NewScorePair.Key.ImpactPoint, SelectionConeAngle))
+				CheckPointInCone(ConeOrigin, ConeForward, NewScorePair.Key.ImpactPoint, SelectionConeAngle))
 			{
 				CandidateList.Emplace(OldScoreEntry.Key, NewScorePair.Key);
 				MaxScore = NewScorePair.Value;
 				MaxScoreSelectable = OldScoreEntry.Key;
 			}
 			else if (NewScorePair.Value > MaxScore &&
-					 this->CheckPointInCone(ConeOrigin, ConeForward, NewScorePair.Key.ImpactPoint, SelectionConeAngle))
+					 CheckPointInCone(ConeOrigin, ConeForward, NewScorePair.Key.ImpactPoint, SelectionConeAngle))
 			{
 				MaxScore = NewScorePair.Value;
 				MaxScoreSelectable = OldScoreEntry.Key;
@@ -394,19 +463,22 @@ UIntenSelectable* UIntenSelectComponent::GetMaxScoreActor(const float DeltaTime)
 		}
 	}
 
-	for (const UIntenSelectable* i : RemoveList)
+	// Remove non-selectable actors from the maps
+	for (UIntenSelectable* i : RemoveList)
 	{
 		ContactPointMap.Remove(i);
 		ScoreMap.Remove(i);
 	}
+
+	// Select the nearest actor from the candidate list if available
 	if (CandidateList.Num() > 0)
 	{
-		auto DistanceToMaxScore =
+		float DistanceToMaxScore =
 			FVector::Distance(MaxScoreSelectable->GetOwner()->GetActorLocation(), GetComponentLocation());
-		auto Dist = TNumericLimits<float>::Max();
+		float Dist = TNumericLimits<float>::Max();
 		for (const TPair<UIntenSelectable*, FHitResult>& Actor : CandidateList)
 		{
-			const auto DistanceToCandidate = FVector::Distance(Actor.Value.ImpactPoint, GetComponentLocation());
+			const float DistanceToCandidate = FVector::Distance(Actor.Value.ImpactPoint, GetComponentLocation());
 			if (DistanceToCandidate < Dist)
 			{
 				MaxScoreSelectable = Actor.Key;
@@ -417,78 +489,86 @@ UIntenSelectable* UIntenSelectComponent::GetMaxScoreActor(const float DeltaTime)
 
 	return MaxScoreSelectable;
 }
+
 //				RAYCASTING
 
 
 void UIntenSelectComponent::HandleWidgetInteraction()
 {
-	const FVector Forward = this->GetComponentTransform().GetRotation().GetForwardVector();
-	const FVector Origin = this->GetComponentTransform().GetLocation();
+	// Get forward vector and origin of the component
+	const FVector Forward = GetComponentTransform().GetRotation().GetForwardVector();
+	const FVector Origin = GetComponentTransform().GetLocation();
 
+	// Raytrace to find the first hit
 	TOptional<FHitResult> Hit = RaytraceForFirstHit(Origin, Origin + Forward * MaxSelectionDistance);
 
+	// If no hit, clear focus and return
 	if (!Hit.IsSet())
 	{
 		IsWidgetInFocus = false;
 		return;
 	}
 
+	// Set hit result and check if a widget is in focus
 	SetCustomHitResult(Hit.GetValue());
 	UWidgetComponent* FocusedWidget = Cast<UWidgetComponent>(Hit.GetValue().GetComponent());
 	IsWidgetInFocus = (FocusedWidget != nullptr);
 
-
+	// Handle widget events (commented out for now)
 	/*
-	if(IsWidgetInFocus)
+	if (IsWidgetInFocus)
 	{
 		if (FocusedWidget != LastFocusedWidget)
 		{
-			//We can always execute the enter event as we are sure that a hit occured
 			if (FocusedWidget->GetOwner()->Implements<UTargetable>())
 			{
 				ITargetable::Execute_OnTargetedEnter(FocusedWidget->GetOwner());
 			}
 
-			//Only execute the Leave Event if there was an actor that was focused previously
 			if (LastFocusedWidget != nullptr && LastFocusedWidget->GetOwner()->Implements<UTargetable>())
 			{
 				ITargetable::Execute_OnTargetedLeave(LastFocusedWidget->GetOwner());
 			}
 		}
 
-		// for now uses the same distance as clicking
 		if (FocusedWidget->GetOwner()->Implements<UTargetable>())
 		{
 			ITargetable::Execute_OnTargeted(FocusedWidget->GetOwner(), Hit->Location);
 		}
 		LastFocusedWidget = FocusedWidget;
 
-		if(FocusedWidget->GetOwner()->GetClass()->ImplementsInterface(UIntenSelectableWidget::StaticClass()))
+		if (FocusedWidget->GetOwner()->GetClass()->ImplementsInterface(UIntenSelectableWidget::StaticClass()))
 		{
 			FVector pos = IIntenSelectableWidget::Execute_GetCoordinates(FocusedWidget->GetOwner());
 			GEngine->AddOnScreenDebugMessage(INDEX_NONE, 0, FColor::Black, "C++ Pos: " + pos.ToString());
 			WidgetFocusPoint = pos;
-		}else
+		}
+		else
 		{
 			GEngine->AddOnScreenDebugMessage(INDEX_NONE, 0, FColor::Black, "C++ Pos not available");
 		}
-	}*/
+	}
+	*/
 }
 
+
 TOptional<FHitResult> UIntenSelectComponent::RaytraceForFirstHit(const FVector& Start, const FVector& End) const
 {
-	// will be filled by the Line Trace Function
+	// Hit result to be filled by Line Trace function
 	FHitResult Hit;
 
+	// Set up collision query parameters
 	FCollisionQueryParams Params;
-	Params.AddIgnoredActor(GetOwner()->GetUniqueID()); // prevents actor hitting itself
+	Params.AddIgnoredActor(GetOwner()->GetUniqueID()); // Ignore the owner actor to prevent hitting itself
+
+	// Perform line trace
 	if (GetWorld()->LineTraceSingleByChannel(Hit, Start, End, ECollisionChannel::ECC_Visibility, Params))
 	{
 		return {Hit};
 	}
 	else
 	{
-		return {};
+		return {}; // No hit
 	}
 }
 
@@ -497,78 +577,106 @@ TOptional<FHitResult> UIntenSelectComponent::RaytraceForFirstHit(const FVector&
 
 void UIntenSelectComponent::DrawSelectionCurve(const FVector& EndPoint) const
 {
-	const FVector StartPoint = this->GetComponentTransform().GetLocation();
-	const FVector Forward = this->GetComponentTransform().GetRotation().GetForwardVector();
+	// Get start point, forward vector, and set spline points
+	const FVector StartPoint = GetComponentTransform().GetLocation();
+	const FVector Forward = GetComponentTransform().GetRotation().GetForwardVector();
 
 	SplineComponent->ClearSplinePoints(true);
 	SplineMeshComponent->SetHiddenInGame(false);
 
 	AddSplinePointsDefault(StartPoint, Forward, EndPoint);
 
+	// Get spline start and end positions and tangents
 	const FVector StartPosition = SplineComponent->GetLocationAtSplinePoint(0, ESplineCoordinateSpace::Local);
 	const FVector StartTangent = SplineComponent->GetTangentAtSplinePoint(0, ESplineCoordinateSpace::Local);
 	const FVector EndPosition = SplineComponent->GetLocationAtSplinePoint(1, ESplineCoordinateSpace::Local);
 	const FVector EndTangent = SplineComponent->GetTangentAtSplinePoint(1, ESplineCoordinateSpace::Local);
 
+	// Set start and end for spline mesh component
 	SplineMeshComponent->SetStartAndEnd(StartPosition, StartTangent, EndPosition, EndTangent, true);
 }
 
+
 void UIntenSelectComponent::AddSplinePointsDefault(const FVector& StartPoint, const FVector& Forward,
 												   const FVector& EndPoint) const
 {
+	// Add start and end points to the spline
 	SplineComponent->AddSplineWorldPoint(StartPoint);
-
-	const FVector StartToEnd = EndPoint - StartPoint;
-	const FVector ForwardProjection = StartToEnd.ProjectOnTo(Forward);
-
 	SplineComponent->AddSplineWorldPoint(EndPoint);
 
+	// Set spline point types
 	SplineComponent->SetSplinePointType(0, ESplinePointType::Curve, true);
 	SplineComponent->SetSplinePointType(1, ESplinePointType::Curve, true);
 
-	SplineComponent->SetTangentAtSplinePoint(0, Forward * ForwardProjection.Size() * SplineCurvatureStrength,
-											 ESplineCoordinateSpace::World, true);
-	SplineComponent->SetTangentAtSplinePoint(1, StartToEnd.GetSafeNormal(), ESplineCoordinateSpace::World, true);
+	// Calculate tangents for smooth curve
+	const FVector StartToEnd = EndPoint - StartPoint;
+	const FVector ForwardProjection = StartToEnd.ProjectOnTo(Forward);
+	const FVector StartTangent = Forward * ForwardProjection.Size() * SplineCurvatureStrength;
+	const FVector EndTangent = StartToEnd.GetSafeNormal();
+
+	// Set tangents at spline points
+	SplineComponent->SetTangentAtSplinePoint(0, StartTangent, ESplineCoordinateSpace::World, true);
+	SplineComponent->SetTangentAtSplinePoint(1, EndTangent, ESplineCoordinateSpace::World, true);
 }
 
+
 void UIntenSelectComponent::UpdateForwardRay(const FVector& ReferencePoint) const
 {
+	// Check if transparency curve is available
 	if (ForwardRayTransparencyCurve)
 	{
-		const FVector ConeForward = this->GetComponentTransform().GetRotation().GetForwardVector();
-		const FVector ConeOrigin =
-			this->GetComponentTransform().GetLocation() - (ConeForward * ConeBackwardShiftDistance);
+		// Calculate cone forward vector and origin
+		const FVector ConeForward = GetComponentTransform().GetRotation().GetForwardVector();
+		const FVector ConeOrigin = GetComponentTransform().GetLocation() - (ConeForward * ConeBackwardShiftDistance);
 
+		// Calculate angle to test point
 		const FVector TestPointVector = (ReferencePoint - ConeOrigin).GetSafeNormal();
 		const float AngleToTestPoint =
-			FMath::RadiansToDegrees(FMath::Acos((FVector::DotProduct(ConeForward, TestPointVector))));
+			FMath::RadiansToDegrees(FMath::Acos(FVector::DotProduct(ConeForward, TestPointVector)));
 
+		// Calculate new transparency based on curve
 		const float NewTransparency =
 			ForwardRayTransparencyCurve->GetFloatValue(AngleToTestPoint / SelectionConeAngle) * DebugRayTransparency;
-		ParameterCollectionInstance->SetScalarParameterValue("Transparency", NewTransparency);
+
+		// Set transparency parameter value in parameter collection
+		if (ParameterCollectionInstance)
+		{
+			ParameterCollectionInstance->SetScalarParameterValue("Transparency", NewTransparency);
+		}
+		else
+		{
+			UE_LOG(LogTemp, Warning, TEXT("ParameterCollectionInstance is null!"));
+		}
+	}
+	else
+	{
+		UE_LOG(LogTemp, Warning, TEXT("ForwardRayTransparencyCurve is null!"));
 	}
 }
 
+
 //				INPUT-HANDLING
 
 void UIntenSelectComponent::OnFireDown()
 {
-	// start interaction of WidgetInteractionComponent
+	// Start interaction of WidgetInteractionComponent
 	PressPointerKey(EKeys::LeftMouseButton);
 
+	// Check if there is a current selection
 	if (!CurrentSelection)
 	{
 		return;
 	}
 
-	if (CurrentSelection)
+	// Handle action start events for current selection
+	const FHitResult* GrabbedPoint = ContactPointMap.Find(CurrentSelection);
+	if (GrabbedPoint)
 	{
-		const FHitResult GrabbedPoint = *ContactPointMap.Find(CurrentSelection);
 		CurrentSelection->HandleOnActionStartEvents(this);
 		LastKnownSelection = CurrentSelection;
 		LastKnownGrabPoint =
 			LastKnownSelection->GetOwner()->GetRootComponent()->GetComponentTransform().InverseTransformPosition(
-				GrabbedPoint.ImpactPoint);
+				GrabbedPoint->ImpactPoint);
 	}
 	else
 	{
@@ -577,19 +685,22 @@ void UIntenSelectComponent::OnFireDown()
 
 	IsGrabbing = true;
 
+	// Update transparency if required
 	if (bDrawForwardRay && ParameterCollectionInstance)
 	{
 		ParameterCollectionInstance->SetScalarParameterValue("Transparency", 0);
 	}
 }
 
+
 void UIntenSelectComponent::OnFireUp()
 {
-	// end interaction of WidgetInteractionComponent
+	// End interaction of WidgetInteractionComponent
 	ReleasePointerKey(EKeys::LeftMouseButton);
 
 	IsGrabbing = false;
 
+	// Handle action end events for last known selection
 	if (LastKnownSelection)
 	{
 		FInputActionValue v;
@@ -597,136 +708,165 @@ void UIntenSelectComponent::OnFireUp()
 	}
 }
 
+
 //				SELECTION-HANDLING
 
 void UIntenSelectComponent::SelectObject(UIntenSelectable* SelectableComponent, AActor* SelectedBy)
 {
+	// Set the current selection to the specified selectable component
 	CurrentSelection = SelectableComponent;
 }
 
+
 void UIntenSelectComponent::Unselect()
 {
+	// Stop grabbing
 	IsGrabbing = false;
 
+	// Hide spline mesh component
 	SplineMeshComponent->SetHiddenInGame(true);
 
+	// Reset current selection
 	CurrentSelection = nullptr;
-	this->CurrentSelection = nullptr;
 }
 
+
 void UIntenSelectComponent::SetActive(bool bNewActive, bool bReset)
 {
 	if (bNewActive)
 	{
+		// Show forward ray and spline mesh components
 		ForwardRayMeshComponent->SetVisibility(true);
 		SplineMeshComponent->SetVisibility(true);
 
+		// Call superclass setActive function
 		Super::SetActive(true, bReset);
 	}
 	else
 	{
+		// If there is a current selection, handle no actor selected
 		if (CurrentSelection)
 		{
 			HandleNoActorSelected();
 		}
 
+		// If there is a last known selection, end the fire action
 		if (LastKnownSelection)
 		{
 			OnFireUp();
 		}
 
+		// Hide forward ray and spline mesh components
 		ForwardRayMeshComponent->SetVisibility(false);
 		SplineMeshComponent->SetVisibility(false);
 
+		// Call superclass setActive function
 		Super::SetActive(false, bReset);
 	}
 }
 
+
 //				TICK
 
 void UIntenSelectComponent::HandleCooldown(const float DeltaTime)
 {
+	// Reduce feedback cooldown by delta time
 	if (FeedbackCooldown > 0)
 	{
 		FeedbackCooldown -= DeltaTime;
 	}
+	// Ensure feedback cooldown does not go below 0
 	else
 	{
 		FeedbackCooldown = 0;
 	}
 }
 
-void UIntenSelectComponent::HandleGrabbing(const float DeltaTime) const {}
-
 void UIntenSelectComponent::HandleActorSelected(UIntenSelectable* NewSelection)
 {
+	// Check if the new selection is different from the current selection
 	if (NewSelection != CurrentSelection)
 	{
+		// If there is a current selection, handle hover end events
 		if (CurrentSelection)
 		{
 			CurrentSelection->HandleOnHoverEndEvents(this);
 		}
 
+		// If there is a new selection, handle hover start events
 		if (NewSelection)
 		{
-			UIntenSelectable* NewIntenSelectable = NewSelection;
-			const FHitResult GrabbedPoint = *ContactPointMap.Find(NewIntenSelectable);
-			NewIntenSelectable->HandleOnHoverStartEvents(this, GrabbedPoint);
+			const FHitResult* GrabbedPoint = ContactPointMap.Find(NewSelection);
+			if (GrabbedPoint)
+			{
+				NewSelection->HandleOnHoverStartEvents(this, *GrabbedPoint);
+			}
 		}
 
+		// Set the new selection as the current selection and trigger new selected event
 		CurrentSelection = NewSelection;
 		OnNewSelected(NewSelection);
 	}
 
+	// If there is a current selection, update forward ray and draw selection curve
 	if (CurrentSelection)
 	{
-		const UIntenSelectable* NewIntenSelectable = NewSelection;
-		const auto V_Net = ContactPointMap.Find(NewIntenSelectable)->ImpactPoint;
-		const FVector PointToDrawTo = ConvertNetVector(V_Net);
-
-		if (bDrawForwardRay)
+		const FHitResult* GrabbedPoint = ContactPointMap.Find(NewSelection);
+		if (GrabbedPoint)
 		{
-			UpdateForwardRay(PointToDrawTo);
-		}
+			const FVector PointToDrawTo = ConvertNetVector(GrabbedPoint->ImpactPoint);
 
-		DrawSelectionCurve(PointToDrawTo);
+			if (bDrawForwardRay)
+			{
+				UpdateForwardRay(PointToDrawTo);
+			}
+
+			DrawSelectionCurve(PointToDrawTo);
+		}
 	}
 }
 
+
 FVector UIntenSelectComponent::ConvertNetVector(FVector_NetQuantize v)
 {
-	FVector Result;
-	Result.X = v.X;
-	Result.Y = v.Y;
-	Result.Z = v.Z;
-	return Result;
+	// Convert NetQuantize vector to FVector
+	return FVector(v.X, v.Y, v.Z);
 }
 
 
 void UIntenSelectComponent::HandleNoActorSelected()
 {
+	// Hide spline mesh component
 	SplineMeshComponent->SetHiddenInGame(true);
 
+	// If there is a current selection, handle hover end events and reset current selection
 	if (CurrentSelection)
 	{
 		CurrentSelection->HandleOnHoverEndEvents(this);
+		CurrentSelection = nullptr;
 	}
 
+	// Reset transparency parameter if drawing forward ray
 	if (bDrawForwardRay && ParameterCollectionInstance)
 	{
 		ParameterCollectionInstance->SetScalarParameterValue("Transparency", DebugRayTransparency);
 	}
-	CurrentSelection = nullptr;
 }
 
+
 void UIntenSelectComponent::TickComponent(const float DeltaTime, const ELevelTick TickType,
 										  FActorComponentTickFunction* ThisTickFunction)
 {
+	// Call parent tick function
 	Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
 
-	this->HandleCooldown(DeltaTime);
+	// Handle cooldown for feedback
+	HandleCooldown(DeltaTime);
+
+	// Get the new selection based on current parameters
 	UIntenSelectable* const NewSelection = GetMaxScoreActor(DeltaTime);
 
+	// If currently grabbing an object, update selection curve and check for angle constraints
 	if (IsGrabbing && LastKnownSelection)
 	{
 		const FVector GrabPointWorld =
@@ -734,10 +874,10 @@ void UIntenSelectComponent::TickComponent(const float DeltaTime, const ELevelTic
 				LastKnownGrabPoint);
 		DrawSelectionCurve(GrabPointWorld);
 
-		const FVector ConeOrigin = this->GetComponentLocation();
-		const FVector ConeForward = this->GetForwardVector().GetSafeNormal();
+		const FVector ConeOrigin = GetComponentLocation();
+		const FVector ConeForward = GetForwardVector().GetSafeNormal();
 
-		if (!this->CheckPointInCone(ConeOrigin, ConeForward, GrabPointWorld, MaxClickStickAngle))
+		if (!CheckPointInCone(ConeOrigin, ConeForward, GrabPointWorld, MaxClickStickAngle))
 		{
 			OnFireUp();
 		}
@@ -750,11 +890,10 @@ void UIntenSelectComponent::TickComponent(const float DeltaTime, const ELevelTic
 		DrawSelectionCurve(GrabbedPoint);
 	}
 
-	// this->HandleWidgetInteraction();
+	// Handle widget interaction
 	IsWidgetInFocus = false;
 	if (IsWidgetInFocus)
 	{
-		// GEngine->AddOnScreenDebugMessage(INDEX_NONE, 0, FColor::Red, "Widget focused");
 		HandleNoActorSelected();
 
 		const FVector PointToDrawTo = WidgetFocusPoint;
@@ -768,14 +907,13 @@ void UIntenSelectComponent::TickComponent(const float DeltaTime, const ELevelTic
 	}
 	else
 	{
+		// If there is a new selection, handle it; otherwise, handle no actor selected
 		if (NewSelection)
 		{
-			// GEngine->AddOnScreenDebugMessage(INDEX_NONE, 0, FColor::Red, "Focused Actor:" + NewSelection->GetName());
 			HandleActorSelected(NewSelection);
 		}
 		else
 		{
-			// GEngine->AddOnScreenDebugMessage(INDEX_NONE, 0, FColor::Red, "No Actor in Focus");
 			HandleNoActorSelected();
 		}
 	}
diff --git a/Source/RWTHVRToolkit/Public/Pawn/IntenSelectComponent.h b/Source/RWTHVRToolkit/Public/Pawn/IntenSelectComponent.h
index 864e5dee..5142f339 100644
--- a/Source/RWTHVRToolkit/Public/Pawn/IntenSelectComponent.h
+++ b/Source/RWTHVRToolkit/Public/Pawn/IntenSelectComponent.h
@@ -143,71 +143,217 @@ public:
 
 #pragma region /** INITIALIZATION */
 private:
+	/**
+	 * \brief Initializes the input bindings for interacting with the component.
+	 */
 	void InitInputBindings();
+
+	/**
+	 * \brief Initializes the debug cone mesh component used for visualization.
+	 */
 	void InitDebugConeMeshComponent();
+
+	/**
+	 * \brief Initializes the spline mesh component used for visualization.
+	 */
 	void InitSplineMeshComponent();
+
+	/**
+	 * \brief Initializes the spline component used for visualization.
+	 */
 	void InitSplineComponent();
+
+	/**
+	 * \brief Initializes the forward ray mesh component used for visualization.
+	 */
 	void InitForwardRayMeshComponent();
+
+	/**
+	 * \brief Initializes the material parameter collection used for visualization.
+	 */
 	void InitMaterialParamCollection();
+
 #pragma endregion
 
 #pragma region /** SCORING */
+
 private:
+	/**
+	 * \brief Calculates the radius for sphere casting based on the selection cone angle and maximum selection distance.
+	 * \return The calculated sphere cast radius.
+	 */
 	float CalculateSphereCastRadius() const;
+
+	/**
+	 * \brief Retrieves actors from sphere casting to determine potential selections.
+	 * \param SphereCastStart The starting point of the sphere cast.
+	 * \param OutHits The array to store hit results.
+	 * \return True if successful, false otherwise.
+	 */
 	bool GetActorsFromSphereCast(const FVector& SphereCastStart, TArray<FHitResult>& OutHits) const;
+
+	/**
+	 * \brief Checks if a point is within the selection cone.
+	 * \param ConeStartPoint The starting point of the selection cone.
+	 * \param ConeForward The forward direction of the selection cone.
+	 * \param PointToTest The point to test for inclusion in the cone.
+	 * \param Angle The angle of the selection cone.
+	 * \return True if the point is within the cone, false otherwise.
+	 */
 	bool CheckPointInCone(const FVector ConeStartPoint, const FVector ConeForward, const FVector PointToTest,
 						  const float Angle) const;
+
+	/**
+	 * \brief Determines the actor with the maximum score for selection.
+	 * \param DeltaTime The time elapsed since the last frame.
+	 * \return The actor with the maximum score for selection.
+	 */
 	UIntenSelectable* GetMaxScoreActor(const float DeltaTime);
+
 #pragma endregion
 
+
 #pragma region /** VISUALS */
+
 private:
+	/**
+	 * \brief Draws a selection curve from the component to the specified end point.
+	 * \param EndPoint The end point of the selection curve.
+	 */
 	void DrawSelectionCurve(const FVector& EndPoint) const;
+
+	/**
+	 * \brief Adds default spline points for creating a spline between start and end points.
+	 * \param StartPoint The starting point of the spline.
+	 * \param Forward The forward direction of the spline.
+	 * \param EndPoint The end point of the spline.
+	 */
 	void AddSplinePointsDefault(const FVector& StartPoint, const FVector& Forward, const FVector& EndPoint) const;
+
+	/**
+	 * \brief Updates the forward ray visualization based on the reference point.
+	 * \param ReferencePoint The reference point to update the forward ray to.
+	 */
 	void UpdateForwardRay(const FVector& ReferencePoint) const;
+
 #pragma endregion
 
+
 #pragma region /** RAYCASTING */
+
 private:
+	/**
+	 * \brief Handles the interaction with widgets.
+	 */
 	void HandleWidgetInteraction();
+
+	/**
+	 * \brief Performs a raycast from the start to the end point and returns the first hit result, if any.
+	 * \param Start The starting point of the raycast.
+	 * \param End The ending point of the raycast.
+	 * \return The optional hit result of the raycast.
+	 */
 	TOptional<FHitResult> RaytraceForFirstHit(const FVector& Start, const FVector& End) const;
+
 #pragma endregion
 
+
 #pragma region /** INPUT-HANDLING */
+
 private:
+	/**
+	 * \brief Handles the input event when the fire button is pressed.
+	 */
 	UFUNCTION(BlueprintCallable)
 	void OnFireDown();
+
+	/**
+	 * \brief Handles the input event when the fire button is released.
+	 */
 	UFUNCTION(BlueprintCallable)
 	void OnFireUp();
+
 #pragma endregion
 
+
 #pragma region /** OTHER */
+
 private:
+	/**
+	 * \brief Handles the cooldown mechanism based on the passed time interval.
+	 * \param DeltaTime The time elapsed since the last frame.
+	 */
 	void HandleCooldown(const float DeltaTime);
-	void HandleGrabbing(const float DeltaTime) const;
+
+	/**
+	 * \brief Handles the scenario when no actor is selected.
+	 */
 	void HandleNoActorSelected();
+
+	/**
+	 * \brief Handles the selection of a new actor.
+	 * \param NewSelection The new selectable component to be selected.
+	 */
 	void HandleActorSelected(UIntenSelectable* NewSelection);
+
+	/**
+	 * \brief Converts a network quantized vector to a regular FVector.
+	 * \param v The network quantized vector to convert.
+	 * \return The converted FVector.
+	 */
 	FVector ConvertNetVector(FVector_NetQuantize v);
+
 #pragma endregion
 
+
 public:
+	/**
+	 * \brief Constructor for the UIntenSelectComponent class.
+	 */
 	UIntenSelectComponent(const FObjectInitializer& ObjectInitializer);
 
 #pragma region /** SELECTION */
+
+	/**
+	 * \brief Selects a given selectable component.
+	 * \param SelectableComponent The selectable component to be selected.
+	 * \param SelectedBy The actor responsible for the selection.
+	 */
 	void SelectObject(UIntenSelectable* SelectableComponent, AActor* SelectedBy);
+
+	/**
+	 * \brief Unselects the currently selected object.
+	 */
 	void Unselect();
+
 #pragma endregion
 
+	/**
+	 * \brief Sets whether the component is active or not.
+	 * \param bNewActive The new active state of the component.
+	 * \param bReset Whether the activation should happen even if ShouldActivate returns false.
+	 */
 	virtual void SetActive(bool bNewActive, bool bReset) override;
 
+	/**
+	 * \brief Blueprint-native event called when a new object is selected.
+	 * \param Selection The newly selected object.
+	 */
 	UFUNCTION(BlueprintNativeEvent)
 	void OnNewSelected(UIntenSelectable* Selection);
 
 protected:
-	// Called when the game starts
+	/**
+	 * \brief Called when the game starts.
+	 */
 	virtual void BeginPlay() override;
 
-	// Called every frame
+	/**
+	 * \brief Called every frame.
+	 * \param DeltaTime The time since the last frame.
+	 * \param TickType The type of tick.
+	 * \param ThisTickFunction The tick function for this component.
+	 */
 	virtual void TickComponent(float DeltaTime, ELevelTick TickType,
 							   FActorComponentTickFunction* ThisTickFunction) override;
 };
-- 
GitLab