Skip to content
Snippets Groups Projects
Commit 0b3d432b authored by Timon Römer's avatar Timon Römer
Browse files

Add IntenSelect files

parent cb10fd6d
No related branches found
No related tags found
2 merge requests!81Inten Select 5.3,!80UE5.3-2023.1-rc2
Showing
with 2206 additions and 5 deletions
...@@ -59,7 +59,7 @@ ...@@ -59,7 +59,7 @@
}, },
{ {
"Name": "DTrackPlugin", "Name": "DTrackPlugin",
"Enabled": true "Enabled": false
}, },
{ {
"Name": "EnhancedInput", "Name": "EnhancedInput",
......
...@@ -26,9 +26,7 @@ public class RWTHVRCluster : ModuleRules ...@@ -26,9 +26,7 @@ public class RWTHVRCluster : ModuleRules
"InputCore", "InputCore",
"UMG", "UMG",
"Slate", "Slate",
"SlateCore", "SlateCore"
"DTrackPlugin",
"DTrackInput"
} }
); );
......
...@@ -11,7 +11,7 @@ UClickBehaviour::UClickBehaviour() ...@@ -11,7 +11,7 @@ UClickBehaviour::UClickBehaviour()
void UClickBehaviour::OnClickStart(USceneComponent* TriggeredComponent,const FInputActionValue& Value) void UClickBehaviour::OnClickStart(USceneComponent* TriggeredComponent,const FInputActionValue& Value)
{ {
Value.
} }
void UClickBehaviour::OnClickEnd(USceneComponent* TriggeredComponent,const FInputActionValue& Value) void UClickBehaviour::OnClickEnd(USceneComponent* TriggeredComponent,const FInputActionValue& Value)
......
// Fill out your copyright notice in the Description page of Project Settings.
#include "Interaction/IntenSelectable.h"
#include "Interaction/ClickBehaviour.h"
#include "Interaction/IntenSelectableSinglePointScoring.h"
#include "Interaction/SelectionBehaviour.h"
#include "Misc/MessageDialog.h"
UIntenSelectable::UIntenSelectable()
{
PrimaryComponentTick.bCanEverTick = true;
}
TPair<FVector, float> UIntenSelectable::GetBestPointScorePair(const FVector& ConeOrigin,
const FVector& ConeForwardDirection, const float ConeBackwardShiftDistance, const float ConeAngle,
const float LastValue, const float DeltaTime) const
{
checkf(ScoringBehaviour,TEXT("%s"),*GetOwner()->GetName())
return ScoringBehaviour->GetBestPointScorePair(ConeOrigin, ConeForwardDirection, ConeBackwardShiftDistance, ConeAngle, LastValue, DeltaTime);
}
void UIntenSelectable::HandleOnSelectStartEvents(const UIntenSelectComponent* IntenSelect, const FVector& Point)
{
for(const USelectionBehaviour* b : OnSelectBehaviours)
{
b->OnSelectStartEvent.Broadcast(IntenSelect->GetOwner(), Point);
}
}
void UIntenSelectable::HandleOnSelectEndEvents(const UIntenSelectComponent* IntenSelect)
{
for(const USelectionBehaviour* b : OnSelectBehaviours)
{
b->OnSelectEndEvent.Broadcast(IntenSelect->GetOwner());
}
}
void UIntenSelectable::HandleOnClickStartEvents(const UIntenSelectComponent* IntenSelect, const FVector& Point)
{
for(const UClickBehaviour* b : OnClickBehaviours)
{
b->OnClickStartEvent.Broadcast(IntenSelect->GetOwner(), Point);
}
}
void UIntenSelectable::HandleOnClickEndEvents(const UIntenSelectComponent* IntenSelect)
{
for(const UClickBehaviour* b : OnClickBehaviours)
{
b->OnClickEndEvent.Broadcast(IntenSelect->GetOwner());
}
}
void UIntenSelectable::InitDefaultBehaviourReferences()
{
//Scoring
UIntenSelectableScoring* AttachedScoring = Cast<UIntenSelectableScoring>(GetOwner()->GetComponentByClass(UIntenSelectableScoring::StaticClass()));
if(AttachedScoring)
{
ScoringBehaviour = AttachedScoring;
}else
{
ScoringBehaviour = NewObject<UIntenSelectableSinglePointScoring>(this, UIntenSelectableSinglePointScoring::StaticClass(), "Default Scoring");
ScoringBehaviour->SetWorldLocation(GetOwner()->GetActorLocation());
ScoringBehaviour->AttachToComponent(GetOwner()->GetRootComponent(), FAttachmentTransformRules::SnapToTargetNotIncludingScale);
}
//Selecting
TInlineComponentArray<USelectionBehaviour*> AttachedSelectionBehaviours;
GetOwner()->GetComponents(AttachedSelectionBehaviours, true);
this->OnSelectBehaviours = AttachedSelectionBehaviours;
//Clicking
TInlineComponentArray<UClickBehaviour*> AttachedClickBehaviours;
GetOwner()->GetComponents(AttachedClickBehaviours, true);
this->OnClickBehaviours = AttachedClickBehaviours;
}
void UIntenSelectable::ShowErrorAndQuit(const FString& Message) const
{
UE_LOG(LogTemp, Error, TEXT("%s"), *Message)
#if WITH_EDITOR
const FText Title = FText::FromString(FString("RUNTIME ERROR"));
FMessageDialog::Open(EAppMsgType::Ok, FText::FromString(Message), &Title);
#endif
UKismetSystemLibrary::QuitGame(this, nullptr, EQuitPreference::Quit, false);
}
void UIntenSelectable::BeginPlay()
{
Super::BeginPlay();
TInlineComponentArray<UIntenSelectable*> AttachedIntenSelectables;
GetOwner()->GetComponents(AttachedIntenSelectables, false);
if(AttachedIntenSelectables.Num() > 1)
{
if(!ScoringBehaviour)
{
ShowErrorAndQuit("Please assign the Scoring Behaviour manually when using more than one IntenSelectable Component!");
}
}else
{
InitDefaultBehaviourReferences();
}
}
// Fill out your copyright notice in the Description page of Project Settings.
#include "Interaction/IntenSelectableCircleScoring.h"
#include "DrawDebugHelpers.h"
#include "Kismet/KismetMathLibrary.h"
// Sets default values for this component's properties
UIntenSelectableCircleScoring::UIntenSelectableCircleScoring()
{
PrimaryComponentTick.bCanEverTick = true;
}
TPair<FVector, float> UIntenSelectableCircleScoring::GetBestPointScorePair(const FVector& ConeOrigin,
const FVector& ConeForwardDirection, const float ConeBackwardShiftDistance, const float ConeAngle,
const float LastValue, const float DeltaTime)
{
FVector Point = GetClosestSelectionPointTo(ConeOrigin, ConeForwardDirection);
float Score = GetScore(ConeOrigin, ConeForwardDirection, ConeBackwardShiftDistance, ConeAngle, Point, LastValue, DeltaTime);
return TPair<FVector, float>{Point, Score};
}
FVector UIntenSelectableCircleScoring::GetClosestSelectionPointTo(const FVector& Point, const FVector& Direction) const
{
const FVector CenterWorld = this->GetComponentLocation();
const FVector CircleNormalWorld = this->GetComponentTransform().TransformPositionNoScale(FVector::ForwardVector) - CenterWorld;
float t;
FVector Intersect;
if(!UKismetMathLibrary::LinePlaneIntersection_OriginNormal(Point, Point + Direction * 100000, CenterWorld, CircleNormalWorld, t, Intersect))
{
return CenterWorld;
}
const FVector CenterToPoint = Intersect - CenterWorld;
FVector Result;
if(OnlyOutline)
{
Result = (CenterToPoint.GetSafeNormal() * Radius) + CenterWorld;
}else
{
const float DistanceToCenter = CenterToPoint.Size();
if(DistanceToCenter >= Radius)
{
Result = (CenterToPoint.GetSafeNormal() * Radius) + CenterWorld;
}else
{
Result = Intersect;
}
}
FVector Y = CenterToPoint.GetSafeNormal();
FVector Z = FVector::CrossProduct(Y, CircleNormalWorld.GetSafeNormal());
//Y = FVector(0, 0, 1);
//Z = FVector(1, 0, 0);
DrawDebugCircle(GetWorld(), CenterWorld, Radius, 80, FColor::Green, false, -1, 0, 1, Y, Z, false);
return Result;
}
// Fill out your copyright notice in the Description page of Project Settings.
#include "Interaction/IntenSelectableCubeScoring.h"
#include "DrawDebugHelpers.h"
#include "Intersection/IntrRay3AxisAlignedBox3.h"
#include "Kismet/KismetMathLibrary.h"
// Sets default values for this component's properties
UIntenSelectableCubeScoring::UIntenSelectableCubeScoring()
{
PrimaryComponentTick.bCanEverTick = true;
}
TPair<FVector, float> UIntenSelectableCubeScoring::GetBestPointScorePair(const FVector& ConeOrigin,
const FVector& ConeForwardDirection, const float ConeBackwardShiftDistance, const float ConeAngle,
const float LastValue, const float DeltaTime)
{
FVector Point = GetClosestSelectionPointTo(ConeOrigin, ConeForwardDirection);
float Score = Super::GetScore(ConeOrigin, ConeForwardDirection, ConeBackwardShiftDistance, ConeAngle, Point, LastValue, DeltaTime);
return TPair<FVector, float>{Point, Score};
}
FVector UIntenSelectableCubeScoring::GetClosestPointToRectangle(const FVector& StartPoint, const FVector& Direction, const FVector& Corner00, const FVector& Corner01, const FVector& Corner10, const FVector& Corner11) const
{
const float X = FVector::Distance(Corner00, Corner10);
const float Y = FVector::Distance(Corner00, Corner01);
const FVector PlaneNormal = FVector::CrossProduct(Corner10 - Corner00, Corner01 - Corner00).GetSafeNormal();
FVector Intersection;
float T;
UKismetMathLibrary::LinePlaneIntersection_OriginNormal(StartPoint, StartPoint + Direction * 10000, Corner00, PlaneNormal, T, Intersection);
FVector LocalIntersection = this->GetComponentTransform().InverseTransformPosition(Intersection);
if(LocalIntersection.Y > X / 2)
{
LocalIntersection.Y = X / 2;
}else if(LocalIntersection.Y < -X / 2)
{
LocalIntersection.Y = -X / 2;
}
if(LocalIntersection.Z > Y / 2)
{
LocalIntersection.Z = Y / 2;
}else if(LocalIntersection.Z < -Y / 2)
{
LocalIntersection.Z = -Y / 2;
}
/*
if(OnlyOutline)
{
const float DistToBottom = LocalIntersection.Z + (YLength / 2);
const float DistToLeft = LocalIntersection.Y + (XLength / 2);
if(LocalIntersection.Z < 0)
{
if(LocalIntersection.Y < 0)
{
//Bottom and left
if(DistToLeft < DistToBottom)
{
//snap left
LocalIntersection.Y = -(XLength / 2);
}else
{
//snap bottom
LocalIntersection.Z = -(YLength / 2);
}
}else
{
//bottom and right
if(XLength - DistToLeft < DistToBottom)
{
//snap right
LocalIntersection.Y = XLength / 2;
}else
{
//snap bottom
LocalIntersection.Z = -(YLength / 2);
}
}
}else
{
if(LocalIntersection.Y < 0)
{
//top and left
if(DistToLeft < YLength - DistToBottom)
{
//snap left
LocalIntersection.Y = -(XLength / 2);
}else
{
//snap top
LocalIntersection.Z = (YLength / 2);
}
}else
{
//top and right
if(XLength - DistToLeft < YLength - DistToBottom)
{
//snap right
LocalIntersection.Y = XLength / 2;
}else
{
//snap top
LocalIntersection.Z = (YLength / 2);
}
}
}
}
*/
return this->GetComponentTransform().TransformPosition(LocalIntersection);
}
bool UIntenSelectableCubeScoring::LineToLineIntersection(const FVector& FromA, const FVector& FromB, const FVector& ToA, const FVector& ToB, FVector& OutIntersection)
{
const FVector Da = ToA - FromA;
const FVector DB = ToB - FromB;
const FVector DC = FromB - FromA;
const FVector CrossDaDb = FVector::CrossProduct(Da, DB);
const float Prod = CrossDaDb.X * CrossDaDb.X + CrossDaDb.Y * CrossDaDb.Y + CrossDaDb.Z * CrossDaDb.Z;
const float Res = FVector::DotProduct(FVector::CrossProduct(DC, DB), FVector::CrossProduct(Da, DB) / Prod);
if (Res >= -0.02f && Res <= 1.02f) {
OutIntersection = FromA + Da * FVector(Res, Res, Res);
return true;
}
return false;
}
FVector UIntenSelectableCubeScoring::GetClosestSelectionPointTo(const FVector& RayOrigin, const FVector& RayDirection)
{
const FVector X = this->GetForwardVector() * XLength;
const FVector Y = this->GetRightVector() * YLength;
const FVector Z = this->GetUpVector() * ZLength;
TArray<FPlane> CubeSides;
//bottom
const FVector BottomWorld = this->GetComponentTransform().TransformPositionNoScale(- Z / 2);
CubeSides.Add(FPlane{BottomWorld, -this->GetUpVector()});
//top
const FVector TopWorld = this->GetComponentTransform().TransformPositionNoScale(Z / 2);
CubeSides.Add(FPlane{TopWorld, this->GetUpVector()});
//left
const FVector LeftWorld = this->GetComponentTransform().TransformPositionNoScale(- Y / 2);
CubeSides.Add(FPlane{LeftWorld, -this->GetRightVector()});
//right
const FVector RightWorld = this->GetComponentTransform().TransformPositionNoScale(Y / 2);
CubeSides.Add(FPlane{RightWorld, this->GetRightVector()});
//front
const FVector FrontWorld = this->GetComponentTransform().TransformPositionNoScale(-X / 2);
CubeSides.Add(FPlane{FrontWorld, -this->GetForwardVector()});
//back
const FVector BackWorld = this->GetComponentTransform().TransformPositionNoScale(X / 2);
CubeSides.Add(FPlane{BackWorld, this->GetForwardVector()});
/*
const TRay3<float> Ray{Point, Direction, false};
const TAxisAlignedBox3<float> Box;
float OutT;
if(TIntrRay3AxisAlignedBox3<float>::FindIntersection(Ray, Box, OutT))
{
}*/
float MinDistance = TNumericLimits<float>::Max();
FVector ClosestPoint = GetComponentLocation();
bool IsSet = false;
for(FPlane Plane : CubeSides)
{
const FVector PlaneToRayOrigin = RayOrigin - Plane.GetOrigin();
if(FVector::DotProduct(PlaneToRayOrigin.GetSafeNormal(), Plane.GetNormal()) < 0 && BackFaceCulling)
{
if(DrawDebug)
{
DrawDebugSolidPlane(GetWorld(), Plane, GetComponentLocation(), 20, FColor::Red.WithAlpha(9), false, -1, 0);
}
continue;
}else
{
if(DrawDebug)
{
DrawDebugSolidPlane(GetWorld(), Plane, GetComponentLocation(), 20, FColor::Green.WithAlpha(9), false, -1, 0);
}
}
FVector CurrentPoint = FMath::RayPlaneIntersection(RayOrigin, RayDirection, Plane);
FVector CurrentPointLocal = GetComponentTransform().InverseTransformPosition(CurrentPoint);
CurrentPointLocal.X = FMath::Clamp(CurrentPointLocal.X, -XLength / 2, XLength / 2);
CurrentPointLocal.Y = FMath::Clamp(CurrentPointLocal.Y, -YLength / 2, YLength / 2);
CurrentPointLocal.Z = FMath::Clamp(CurrentPointLocal.Z, -ZLength / 2, ZLength / 2);
if(OnlyOutline)
{
const float XSnapDist = (XLength/2) - FMath::Abs(CurrentPointLocal.X);
const float YSnapDist = (YLength/2) - FMath::Abs(CurrentPointLocal.Y);
const float ZSnapDist = (ZLength/2) - FMath::Abs(CurrentPointLocal.Z);
bool SnapX = true;
bool SnapY = true;
bool SnapZ = true;
if(FVector::Parallel(Plane.GetNormal(), GetRightVector()))
{
if(XSnapDist < ZSnapDist)
{
SnapZ = false;
}else
{
SnapX = false;
}
}else if(FVector::Parallel(Plane.GetNormal(), GetUpVector()))
{
if(XSnapDist < YSnapDist)
{
SnapY = false;
}else
{
SnapX = false;
}
}else if(FVector::Parallel(Plane.GetNormal(), GetForwardVector()))
{
if(YSnapDist < ZSnapDist)
{
SnapZ = false;
}else
{
SnapY = false;
}
}
if(SnapX)
{
if(CurrentPointLocal.X > 0)
{
CurrentPointLocal.X = XLength / 2;
}else
{
CurrentPointLocal.X = -XLength / 2;
}
}
if(SnapY)
{
if(CurrentPointLocal.Y > 0)
{
CurrentPointLocal.Y = YLength / 2;
}else
{
CurrentPointLocal.Y = -YLength / 2;
}
}
if(SnapZ)
{
if(CurrentPointLocal.Z > 0)
{
CurrentPointLocal.Z = ZLength / 2;
}else
{
CurrentPointLocal.Z = -ZLength / 2;
}
}
}
CurrentPoint = GetComponentTransform().TransformPosition(CurrentPointLocal);
const float Distance = FMath::PointDistToLine(CurrentPoint, RayDirection, RayOrigin);
//DrawDebugPoint(GetWorld(), CurrentPoint, 10, FColor::Black.WithAlpha(1), false, -1, 0);
//GEngine->AddOnScreenDebugMessage(INDEX_NONE, -1, FColor::Red, FString::SanitizeFloat(Distance));
if(Distance < 0.001)
{
if(MinDistance < 0.001)
{
const float DistToPlayerOld = IsSet ? FVector::Distance(RayOrigin, ClosestPoint) : TNumericLimits<float>::Max();
const float DistToPlayerNew = FVector::Distance(RayOrigin, CurrentPoint);
if(DistToPlayerNew < DistToPlayerOld)
{
MinDistance = Distance;
ClosestPoint = CurrentPoint;
IsSet = true;
}
}else
{
MinDistance = Distance;
ClosestPoint = CurrentPoint;
IsSet = true;
}
}else
{
if(Distance < MinDistance)
{
MinDistance = Distance;
ClosestPoint = CurrentPoint;
IsSet = true;
}
}
}
if(DrawDebug) DrawDebugBox(GetWorld(), GetComponentLocation(), FVector(XLength, YLength, ZLength) / 2, GetComponentRotation().Quaternion(), FColor::Green, false, -1, 0, 2);
return ClosestPoint;
}
void UIntenSelectableCubeScoring::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/IntenSelectableCylinderScoring.h"
#include "DrawDebugHelpers.h"
#include "Kismet/KismetMathLibrary.h"
// Sets default values for this component's properties
UIntenSelectableCylinderScoring::UIntenSelectableCylinderScoring()
{
PrimaryComponentTick.bCanEverTick = true;
}
TPair<FVector, float> UIntenSelectableCylinderScoring::GetBestPointScorePair(const FVector& ConeOrigin,
const FVector& ConeForwardDirection, const float ConeBackwardShiftDistance, const float ConeAngle,
const float LastValue, const float DeltaTime)
{
FVector Point = GetClosestSelectionPointTo(ConeOrigin, ConeForwardDirection);
float Score = GetScore(ConeOrigin, ConeForwardDirection, ConeBackwardShiftDistance, ConeAngle, Point, LastValue, DeltaTime);
return TPair<FVector, float>{Point, Score};
}
bool UIntenSelectableCylinderScoring::LineToLineIntersection(const FVector& FromA, const FVector& FromB, const FVector& ToA, const FVector& ToB, FVector& OutIntersection)
{
const FVector Da = ToA - FromA;
const FVector DB = ToB - FromB;
const FVector DC = FromB - FromA;
const FVector CrossDaDb = FVector::CrossProduct(Da, DB);
const float Prod = CrossDaDb.X * CrossDaDb.X + CrossDaDb.Y * CrossDaDb.Y + CrossDaDb.Z * CrossDaDb.Z;
const float Res = FVector::DotProduct(FVector::CrossProduct(DC, DB), FVector::CrossProduct(Da, DB) / Prod);
if (Res >= -0.02f && Res <= 1.02f) {
OutIntersection = FromA + Da * FVector(Res, Res, Res);
return true;
}
return false;
}
FVector UIntenSelectableCylinderScoring::GetClosestSelectionPointTo(const FVector& Point, const FVector& Direction) const
{
const FVector CylinderStartWorld = this->GetComponentTransform().TransformPosition(LinePoints[0]);
const FVector CylinderEndWorld = this->GetComponentTransform().TransformPosition(LinePoints[1]);
const FVector CylinderDir = CylinderEndWorld-CylinderStartWorld;
const FVector CrossProd = UKismetMathLibrary::Cross_VectorVector(CylinderDir, Direction); //v
const FVector LineDifference = CylinderStartWorld - Point; //u
//Project v onto u =>
const FVector Proj = LineDifference.ProjectOnTo(CrossProd);
const float ProjLength = Proj.Size();
const FVector OffsetPoint = Point + Proj;
const FVector FromA = OffsetPoint;
const FVector FromB = CylinderStartWorld;
const FVector ToA = OffsetPoint + Direction * 10000;
const FVector ToB = CylinderEndWorld;
FVector Result;
LineToLineIntersection(FromA, FromB, ToA, ToB, Result);
const FVector LineDirRes = Result - CylinderStartWorld;
if(LineDirRes.Size() > CylinderDir.Size())
{
Result = CylinderEndWorld;
}
if(!LineDirRes.GetSafeNormal().Equals(CylinderDir.GetSafeNormal()))
{
Result = CylinderStartWorld;
}
const FVector ToSphere = Result - Point;
const FVector Projection = ToSphere.ProjectOnTo(Direction);
const FVector ProjectionToSphere = ToSphere - Projection;
if(ProjLength >= Radius)
{
FVector ShiftResult = ProjectionToSphere.GetSafeNormal() * Radius;
ShiftResult -= ShiftResult.ProjectOnTo(CylinderDir);
return Result - ShiftResult;
}else
{
FVector ShiftResult = ProjectionToSphere.GetSafeNormal() * ProjLength;
ShiftResult -= ShiftResult.ProjectOnTo(CylinderDir);
return Result - ShiftResult;
}
}
void UIntenSelectableCylinderScoring::TickComponent(float DeltaTime, ELevelTick TickType,
FActorComponentTickFunction* ThisTickFunction)
{
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
if(DrawDebug)
{
const FVector StartWorld = this->GetComponentTransform().TransformPosition(LinePoints[0]);
const FVector EndWorld = this->GetComponentTransform().TransformPosition(LinePoints[1]);
DrawDebugCylinder(GetWorld(), StartWorld, EndWorld, Radius, 20,FColor::Green, false, 0, 0, 2);
}
}
// Fill out your copyright notice in the Description page of Project Settings.
#include "Interaction/IntenSelectableLineScoring.h"
#include "DrawDebugHelpers.h"
#include "Kismet/KismetMathLibrary.h"
// Sets default values for this component's properties
UIntenSelectableLineScoring::UIntenSelectableLineScoring()
{
PrimaryComponentTick.bCanEverTick = true;
}
TPair<FVector, float> UIntenSelectableLineScoring::GetBestPointScorePair(const FVector& ConeOrigin,
const FVector& ConeForwardDirection, const float ConeBackwardShiftDistance, const float ConeAngle,
const float LastValue, const float DeltaTime)
{
FVector Point = GetClosestSelectionPointTo(ConeOrigin, ConeForwardDirection);
float Score = GetScore(ConeOrigin, ConeForwardDirection, ConeBackwardShiftDistance, ConeAngle, Point, LastValue, DeltaTime);
return TPair<FVector, float>{Point, Score};
}
bool UIntenSelectableLineScoring::LineToLineIntersection(const FVector& FromA, const FVector& FromB, const FVector& ToA, const FVector& ToB, FVector& OutIntersection)
{
const FVector Da = ToA - FromA;
const FVector DB = ToB - FromB;
const FVector DC = FromB - FromA;
const FVector CrossDaDb = FVector::CrossProduct(Da, DB);
const float Prod = CrossDaDb.X * CrossDaDb.X + CrossDaDb.Y * CrossDaDb.Y + CrossDaDb.Z * CrossDaDb.Z;
const float Res = FVector::DotProduct(FVector::CrossProduct(DC, DB), FVector::CrossProduct(Da, DB) / Prod);
if (Res >= -0.02f && Res <= 1.02f) {
OutIntersection = FromA + Da * FVector(Res, Res, Res);
return true;
}
return false;
}
FVector UIntenSelectableLineScoring::GetClosestSelectionPointTo(const FVector& Point, const FVector& Direction) const
{
const FVector StartWorld = this->GetComponentTransform().TransformPosition(LinePoints[0]);
const FVector EndWorld = this->GetComponentTransform().TransformPosition(LinePoints[1]);
const FVector LineDir = EndWorld-StartWorld;
const FVector CrossProd = UKismetMathLibrary::Cross_VectorVector(LineDir, Direction); //v
const FVector LineDifference = StartWorld - Point; //u
//Project v onto u =>
const FVector Proj = LineDifference.ProjectOnTo(CrossProd);
const FVector OffsetPoint = Point + Proj;
const FVector FromA = OffsetPoint;
const FVector FromB = StartWorld;
const FVector ToA = OffsetPoint + Direction * 10000;
const FVector ToB = EndWorld;
FVector Result;
LineToLineIntersection(FromA, FromB, ToA, ToB, Result);
const FVector LineDirRes = Result - StartWorld;
if(LineDirRes.Size() > LineDir.Size())
{
Result = EndWorld;
}
if(!LineDirRes.GetSafeNormal().Equals(LineDir.GetSafeNormal()))
{
Result = StartWorld;
}
return Result;
}
void UIntenSelectableLineScoring::TickComponent(float DeltaTime, ELevelTick TickType,
FActorComponentTickFunction* ThisTickFunction)
{
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
if(DrawDebug)
{
const FVector StartWorld = this->GetComponentTransform().TransformPosition(LinePoints[0]);
const FVector EndWorld = this->GetComponentTransform().TransformPosition(LinePoints[1]);
DrawDebugLine(GetWorld(), StartWorld, EndWorld, FColor::Green, false, -1, 0, 2);
}
}
// Fill out your copyright notice in the Description page of Project Settings.
#include "Interaction/IntenSelectableMultiPointScoring.h"
#include "Kismet/KismetMathLibrary.h"
// Sets default values for this component's properties
UIntenSelectableMultiPointScoring::UIntenSelectableMultiPointScoring()
{
PrimaryComponentTick.bCanEverTick = true;
}
TPair<FVector, float> UIntenSelectableMultiPointScoring::GetBestPointScorePair(const FVector& ConeOrigin,
const FVector& ConeForwardDirection, const float ConeBackwardShiftDistance, const float ConeAngle,
const float LastValue, const float DeltaTime)
{
FVector Point = GetClosestSelectionPointTo(ConeOrigin, ConeForwardDirection);
float Score = Super::GetScore(ConeOrigin, ConeForwardDirection, ConeBackwardShiftDistance, ConeAngle, Point, LastValue, DeltaTime);
return TPair<FVector, float>{Point, Score};
}
FVector UIntenSelectableMultiPointScoring::GetClosestSelectionPointTo(const FVector& Point, const FVector& Direction) const
{
if(PointsToSelect.Num() == 0)
{
return this->GetComponentLocation();
}
FVector ClosestPoint = this->GetComponentTransform().TransformPositionNoScale(PointsToSelect[0]);
float MinDistance = UKismetMathLibrary::GetPointDistanceToLine(ClosestPoint, Point, Direction);
for(const FVector P : PointsToSelect)
{
const FVector PointToCheck = this->GetComponentTransform().TransformPositionNoScale(P);
const float Dist = UKismetMathLibrary::GetPointDistanceToLine(PointToCheck, Point, Direction);
if(Dist < MinDistance)
{
MinDistance = Dist;
ClosestPoint = PointToCheck;
}
}
return ClosestPoint;
}
// Fill out your copyright notice in the Description page of Project Settings.
#include "Interaction/IntenSelectableRectangleScoring.h"
#include "DrawDebugHelpers.h"
#include "Kismet/KismetMathLibrary.h"
// Sets default values for this component's properties
UIntenSelectableRectangleScoring::UIntenSelectableRectangleScoring()
{
PrimaryComponentTick.bCanEverTick = true;
}
TPair<FVector, float> UIntenSelectableRectangleScoring::GetBestPointScorePair(const FVector& ConeOrigin,
const FVector& ConeForwardDirection, const float ConeBackwardShiftDistance, const float ConeAngle,
const float LastValue, const float DeltaTime)
{
FVector Point = GetClosestSelectionPointTo(ConeOrigin, ConeForwardDirection);
float Score = Super::GetScore(ConeOrigin, ConeForwardDirection, ConeBackwardShiftDistance, ConeAngle, Point, LastValue, DeltaTime);
return TPair<FVector, float>{Point, Score};
}
bool UIntenSelectableRectangleScoring::LineToLineIntersection(const FVector& FromA, const FVector& FromB, const FVector& ToA, const FVector& ToB, FVector& OutIntersection)
{
const FVector Da = ToA - FromA;
const FVector DB = ToB - FromB;
const FVector DC = FromB - FromA;
const FVector CrossDaDb = FVector::CrossProduct(Da, DB);
const float Prod = CrossDaDb.X * CrossDaDb.X + CrossDaDb.Y * CrossDaDb.Y + CrossDaDb.Z * CrossDaDb.Z;
const float Res = FVector::DotProduct(FVector::CrossProduct(DC, DB), FVector::CrossProduct(Da, DB) / Prod);
if (Res >= -0.02f && Res <= 1.02f) {
OutIntersection = FromA + Da * FVector(Res, Res, Res);
return true;
}
return false;
}
FVector UIntenSelectableRectangleScoring::GetClosestSelectionPointTo(const FVector& Point, const FVector& Direction) const
{
const FVector X = this->GetRightVector() * XLength;
const FVector Y = this->GetUpVector() * YLength;
const FVector CornerWorld00 = this->GetComponentTransform().TransformPosition(FVector::ZeroVector) - (X / 2) - (Y / 2);
const FVector CornerWorld10 = CornerWorld00 + X;
const FVector CornerWorld01 = CornerWorld00 + Y;
const FVector CornerWorld11 = CornerWorld00 + X + Y;
const FVector PlaneNormal = FVector::CrossProduct(CornerWorld10 - CornerWorld00, CornerWorld01 - CornerWorld00).GetSafeNormal();
FVector Intersection;
float T;
UKismetMathLibrary::LinePlaneIntersection_OriginNormal(Point, Point + Direction * 10000, CornerWorld00, PlaneNormal, T, Intersection);
FVector LocalIntersection = this->GetComponentTransform().InverseTransformPosition(Intersection);
if(LocalIntersection.Y > XLength / 2)
{
LocalIntersection.Y = XLength / 2;
}else if(LocalIntersection.Y < -XLength / 2)
{
LocalIntersection.Y = -XLength / 2;
}
if(LocalIntersection.Z > YLength / 2)
{
LocalIntersection.Z = YLength / 2;
}else if(LocalIntersection.Z < -YLength / 2)
{
LocalIntersection.Z = -YLength / 2;
}
if(OnlyOutline)
{
const float DistToBottom = LocalIntersection.Z + (YLength / 2);
const float DistToLeft = LocalIntersection.Y + (XLength / 2);
if(LocalIntersection.Z < 0)
{
if(LocalIntersection.Y < 0)
{
//Bottom and left
if(DistToLeft < DistToBottom)
{
//snap left
LocalIntersection.Y = -(XLength / 2);
}else
{
//snap bottom
LocalIntersection.Z = -(YLength / 2);
}
}else
{
//bottom and right
if(XLength - DistToLeft < DistToBottom)
{
//snap right
LocalIntersection.Y = XLength / 2;
}else
{
//snap bottom
LocalIntersection.Z = -(YLength / 2);
}
}
}else
{
if(LocalIntersection.Y < 0)
{
//top and left
if(DistToLeft < YLength - DistToBottom)
{
//snap left
LocalIntersection.Y = -(XLength / 2);
}else
{
//snap top
LocalIntersection.Z = (YLength / 2);
}
}else
{
//top and right
if(XLength - DistToLeft < YLength - DistToBottom)
{
//snap right
LocalIntersection.Y = XLength / 2;
}else
{
//snap top
LocalIntersection.Z = (YLength / 2);
}
}
}
}
return this->GetComponentTransform().TransformPosition(LocalIntersection);
}
void UIntenSelectableRectangleScoring::TickComponent(float DeltaTime, ELevelTick TickType,
FActorComponentTickFunction* ThisTickFunction)
{
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
if(DrawDebug)
{
const FVector X = this->GetRightVector() * XLength;
const FVector Y = this->GetUpVector() * YLength;
const FVector CornerWorld00 = this->GetComponentTransform().TransformPosition(FVector::ZeroVector) - (X / 2) - (Y / 2);
const FVector CornerWorld10 = CornerWorld00 + X;
const FVector CornerWorld01 = CornerWorld00 + Y;
const FVector CornerWorld11 = CornerWorld00 + X + Y;
DrawDebugLine(GetWorld(), CornerWorld00, CornerWorld01, FColor::Green, false, -1, 0, 2);
DrawDebugLine(GetWorld(), CornerWorld00, CornerWorld10, FColor::Green, false, -1, 0, 2);
DrawDebugLine(GetWorld(), CornerWorld01, CornerWorld11, FColor::Green, false, -1, 0, 2);
DrawDebugLine(GetWorld(), CornerWorld10, CornerWorld11, FColor::Green, false, -1, 0, 2);
}
}
// Fill out your copyright notice in the Description page of Project Settings.
#include "Interaction/IntenSelectableScoring.h"
float UIntenSelectableScoring::GetScore(const FVector& ConeOrigin, const FVector& ConeForwardDirection,
const float ConeBackwardShiftDistance, const float ConeAngle, const FVector& TestPoint, const float LastValue,
const float DeltaTime)
{
const FVector ShiftedConeOrigin = ConeOrigin - (ConeForwardDirection * ConeBackwardShiftDistance);
const float D_Perspective = FMath::PointDistToLine(TestPoint, ConeForwardDirection, ShiftedConeOrigin);
const float D_Projection = (TestPoint - ShiftedConeOrigin).ProjectOnTo(ConeForwardDirection).Size();
const float Angle = FMath::RadiansToDegrees(FMath::Atan(D_Perspective / (FMath::Pow(D_Projection / 100, CompensationConstant) * 100)));
float S_Contrib = 1 - (Angle / ConeAngle);
if(S_Contrib < 0) S_Contrib = 0;
//GEngine->AddOnScreenDebugMessage(INDEX_NONE, 0, FColor::Red, GetOwner()->GetName() + " - Contrib: " + FString::FromInt(S_Contrib));
if(LastValue != 0)
{
constexpr float Interpolate = 0.5;
if(S_Contrib > LastValue)
{
CurrentScore = LastValue + (((LastValue * Interpolate) + (S_Contrib * (1-Interpolate))) - LastValue) * DeltaTime * Snappiness;
}else
{
CurrentScore = LastValue + (((LastValue * Interpolate) + (S_Contrib * (1-Interpolate))) - LastValue) * DeltaTime * Stickiness;
}
}else
{
CurrentScore = S_Contrib * Snappiness * DeltaTime;
}
return CurrentScore;
}
// Sets default values for this component's properties
UIntenSelectableScoring::UIntenSelectableScoring()
{
PrimaryComponentTick.bCanEverTick = true;
}
TPair<FVector, float> UIntenSelectableScoring::GetBestPointScorePair(const FVector& ConeOrigin,
const FVector& ConeForwardDirection, const float ConeBackwardShiftDistance, const float ConeAngle,
const float LastValue, const float DeltaTime)
{
return {};
}
void UIntenSelectableScoring::BeginPlay()
{
Super::BeginPlay();
}
#include "Interaction/IntenSelectableSinglePointScoring.h"
UIntenSelectableSinglePointScoring::UIntenSelectableSinglePointScoring()
{
PrimaryComponentTick.bCanEverTick = true;
}
TPair<FVector, float> UIntenSelectableSinglePointScoring::GetBestPointScorePair(const FVector& ConeOrigin, const FVector& ConeForwardDirection, const float ConeBackwardShiftDistance,
const float ConeAngle, const float LastValue, const float DeltaTime)
{
const FVector TestPoint = this->GetComponentLocation();
float Score = GetScore(ConeOrigin, ConeForwardDirection, ConeBackwardShiftDistance, ConeAngle, TestPoint, LastValue, DeltaTime);
return TPair<FVector, float>{TestPoint, Score};
}
void UIntenSelectableSinglePointScoring::BeginPlay()
{
Super::BeginPlay();
}
// Fill out your copyright notice in the Description page of Project Settings.
#include "Interaction/IntenSelectableSphereScoring.h"
#include "DrawDebugHelpers.h"
#include "Algo/IndexOf.h"
#include "Kismet/GameplayStatics.h"
#include "Kismet/KismetMathLibrary.h"
// Sets default values for this component's properties
UIntenSelectableSphereScoring::UIntenSelectableSphereScoring()
{
PrimaryComponentTick.bCanEverTick = true;
}
TPair<FVector, float> UIntenSelectableSphereScoring::GetBestPointScorePair(const FVector& ConeOrigin,
const FVector& ConeForwardDirection, const float ConeBackwardShiftDistance, const float ConeAngle,
const float LastValue, const float DeltaTime)
{
FVector Point = GetClosestSelectionPointTo(ConeOrigin, ConeForwardDirection);
float Score = GetScore(ConeOrigin, ConeForwardDirection, ConeBackwardShiftDistance, ConeAngle, Point, LastValue, DeltaTime);
return TPair<FVector, float>{Point, Score};
}
FVector UIntenSelectableSphereScoring::GetClosestSelectionPointTo(const FVector& Point, const FVector& Direction) const
{
const FVector CenterWorld = this->GetComponentLocation();
const FVector ToSphere = CenterWorld - Point;
const FVector Projection = ToSphere.ProjectOnTo(Direction);
const FVector ProjectionToSphere = ToSphere - Projection;
FVector Result = CenterWorld - ProjectionToSphere.GetSafeNormal() * Radius;
if(!OnlyOutline)
{
const float t = FVector::DotProduct(ToSphere, Direction.GetSafeNormal());
const FVector TPoint = Point + Direction.GetSafeNormal() * t;
const float Y = (CenterWorld - TPoint).Size();
if(Y <= Radius)
{
const float X = + FMath::Sqrt((Radius * Radius) - (Y * Y));
const FVector Result1 = Point + Direction.GetSafeNormal() * (t - X);
const FVector Result2 = Point + Direction.GetSafeNormal() * (t + X);
if(FVector::Distance(Point, Result1) < FVector::Distance(Point, Result2))
{
Result = Result1;
}else
{
Result = Result2;
}
}
/*
TArray<FHitResult> Out;
const float Dist = FVector::Distance(Point, GetComponentLocation());
if(GetWorld()->LineTraceMultiByChannel(Out, Point, Point + (Direction.GetSafeNormal() * Dist), ECollisionChannel::ECC_Visibility))
{
for(auto Hit : Out)
{
if(Hit.GetActor() == GetOwner())
{
Result = Hit.ImpactPoint;
break;
}
}
}*/
}
if(DrawDebug)
{
DrawDebugSphere(GetWorld(), CenterWorld, Radius, 20, FColor::Green, false, -1, 0, 1);
}
return Result;
}
This diff is collapsed.
#include "Pawn/RaycastSelectComponent.h"
#include <string>
#include "DrawDebugHelpers.h"
#include "Components/WidgetComponent.h"
#include "EditorFramework/AssetImportData.h"
#include "GameFramework/Character.h"
#include "Haptics/HapticFeedbackEffect_Curve.h"
#include "Interaction/RaycastSelectable.h"
#include "Misc/MessageDialog.h"
// INITIALIZATION
// Sets default values for this component's properties
URaycastSelectComponent::URaycastSelectComponent(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
PrimaryComponentTick.bCanEverTick = true;
bShowDebug = false; //otherwise the WidgetInteractionComponent debug vis is shown
InteractionSource = EWidgetInteractionSource::Custom; //can also be kept at default (World), this way, however, we efficiently reuse the line traces
ConstructorHelpers::FObjectFinder<UStaticMesh> DefaultForwardRayMesh(TEXT("StaticMesh'/RWTHVRToolkit/IntenSelect/RayMesh.RayMesh'"));
this->ForwardRayMesh = DefaultForwardRayMesh.Object;
ConstructorHelpers::FObjectFinder<UMaterialInterface> DefaultForwardRayMaterial(TEXT("Material'/RWTHVRToolkit/IntenSelect/ForwadRayMaterial.ForwadRayMaterial'"));
this->ForwardRayMaterial = DefaultForwardRayMaterial.Object;
ConstructorHelpers::FObjectFinder<UHapticFeedbackEffect_Curve> DefaultSelectionFeedbackHaptic(TEXT("HapticFeedbackEffect_Curve'/RWTHVRToolkit/IntenSelect/OnSelectHapticFeedback.OnSelectHapticFeedback'"));
this->SelectionFeedbackHaptic = DefaultSelectionFeedbackHaptic.Object;
ConstructorHelpers::FObjectFinder<USoundBase> DefaultOnSelectSound(TEXT("SoundWave'/RWTHVRToolkit/IntenSelect/OnSelectSound.OnSelectSound'"));
this->OnSelectSound = DefaultOnSelectSound.Object;
}
// Called when the game starts
void URaycastSelectComponent::BeginPlay()
{
Super::BeginPlay();
this->InitForwardRayMeshComponent();
this->InitInputBindings();
this->InteractionDistance = this->MaxSelectionDistance;
this->SetActive(SetActiveOnStart, false);
}
void URaycastSelectComponent::InitInputBindings(){
const auto InputComponent = GetOwner()->FindComponentByClass<UInputComponent>();
if(!InputComponent)
{
const FString Message = "There is no InputComponent attached to the same Actor as the RaycastComponent!";
#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;
}
// InputComponent->BindAction("Fire", IE_Pressed, this, &URaycastSelectComponent::OnFireDown);
// InputComponent->BindAction("Fire", IE_Released, this, &URaycastSelectComponent::OnFireUp);
}
void URaycastSelectComponent::InitForwardRayMeshComponent()
{
ForwardRayMeshComponent = NewObject<UStaticMeshComponent>(this, UStaticMeshComponent::StaticClass(), TEXT("ForwardRay"));
if(ForwardRayMeshComponent)
{
ForwardRayMeshComponent->SetupAttachment(this);
ForwardRayMeshComponent->SetMobility((EComponentMobility::Movable));
ForwardRayMeshComponent->RegisterComponent();
ForwardRayMeshComponent->CreationMethod = EComponentCreationMethod::Instance;
ForwardRayMeshComponent->SetCastShadow(false);
ForwardRayMeshComponent->SetCollisionEnabled(ECollisionEnabled::NoCollision);
const float MeshLength = MaxSelectionDistance > 1000 ? 1000 : MaxSelectionDistance;
ForwardRayMeshComponent->SetRelativeScale3D(FVector(MeshLength, 0.01, 0.01));
ForwardRayMeshComponent->SetRelativeLocation(FVector(MeshLength * 50, 0, 0));
//const ConstructorHelpers::FObjectFinder<UStaticMesh> CubeMesh(TEXT("/Engine/BasicShapes/Cube.Cube"));
if(ForwardRayMesh)
{
ForwardRayMeshComponent->SetStaticMesh(ForwardRayMesh);
}else
{
UE_LOG(LogTemp, Warning, TEXT("Mesh for RayComponent not set!"));
}
UMaterialInstanceDynamic* DynamicMaterial = UMaterialInstanceDynamic::Create(ForwardRayMaterial, ForwardRayMeshComponent);
this->ForwardRayMeshComponent->SetMaterial(0, DynamicMaterial);
ForwardRayMeshComponent->SetHiddenInGame(!bDrawForwardRay);
}else
{
UE_LOG(LogTemp, Error, TEXT("Error while spawning ForwardRayMesh component!"));
}
}
// SCORING FUNCTIONS
bool URaycastSelectComponent::CheckPointInCone(const FVector ConeStartPoint, const FVector ConeForward, const FVector PointToTest, const float ConeAngle)
{
const FVector DirectionToTestPoint = (PointToTest - ConeStartPoint).GetSafeNormal();
const float AngleToTestPoint = FMath::RadiansToDegrees(FMath::Acos((FVector::DotProduct(ConeForward ,DirectionToTestPoint))));
return AngleToTestPoint <= ConeAngle;
}
void URaycastSelectComponent::OnNewSelected_Implementation(UIntenSelectable* Selection)
{
UGameplayStatics::PlaySound2D(GetWorld(), OnSelectSound);
}
// RAYCASTING
TOptional<FHitResult> URaycastSelectComponent::RaytraceForFirstHit(const FVector& Start, const FVector& End) const
{
// will be filled by the Line Trace Function
TArray<FHitResult> Hits;
FCollisionQueryParams Params;
Params.AddIgnoredActor(GetOwner()->GetUniqueID()); // prevents actor hitting itself
GetWorld()->LineTraceMultiByChannel(Hits, Start, End, ECollisionChannel::ECC_Visibility, Params);
if (Hits.Num() > 0)
{
return Hits[0];
}
return {};
}
// INPUT-HANDLING
void URaycastSelectComponent::OnFireDown()
{
//start interaction of WidgetInteractionComponent
PressPointerKey(EKeys::LeftMouseButton);
IsGrabbing = true;
if(CurrentSelection)
{
CurrentSelection->HandleOnClickStartEvents(this, CurrentSelectionPoint);
LastKnownGrab = CurrentSelection;
LastKnownGrabPoint = CurrentSelectionPoint;
}
}
void URaycastSelectComponent::OnFireUp()
{
//end interaction of WidgetInteractionComponent
ReleasePointerKey(EKeys::LeftMouseButton);
if(IsGrabbing)
{
IsGrabbing = false;
if(LastKnownGrab)
{
LastKnownGrab->HandleOnClickEndEvents(this);
}
}
}
// SELECTION-HANDLING
void URaycastSelectComponent::SetActive(bool bNewActive, bool bReset)
{
if(bNewActive)
{
ForwardRayMeshComponent->SetVisibility(true);
Super::SetActive(true, bReset);
}else
{
if(CurrentSelection)
{
CurrentSelection->HandleOnSelectEndEvents(this);
CurrentSelection = nullptr;
}
if(LastKnownGrab)
{
OnFireUp();
}
ForwardRayMeshComponent->SetVisibility(false);
Super::SetActive(false, bReset);
}
}
// TICK
void URaycastSelectComponent::TickComponent(const float DeltaTime, const ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
const FVector RaycastOrigin = this->GetComponentLocation();
const FVector RaycastForward = this->GetForwardVector().GetSafeNormal();
const FVector RaycastEnd = RaycastOrigin + (RaycastForward * MaxSelectionDistance);
if(bDrawDebugRay)
{
DrawDebugLine(GetWorld(), RaycastOrigin, RaycastEnd, FColor::Green, false, 0, 0, 5);
}
TOptional<FHitResult> HitResult = this->RaytraceForFirstHit(RaycastOrigin, RaycastEnd);
if(IsGrabbing)
{
if(!this->CheckPointInCone(RaycastOrigin, RaycastForward, LastKnownGrabPoint, MaxClickStickAngle))
{
OnFireUp();
}
return;
}
URaycastSelectable* NewSelection = nullptr;
if(HitResult.IsSet())
{
AActor* HitActor = HitResult.GetValue().Actor.Get();
if(HitActor)
{
NewSelection = HitActor->FindComponentByClass<URaycastSelectable>();
if(bShowHitsOnScreen)
{
if(!NewSelection)
{
GEngine->AddOnScreenDebugMessage(INDEX_NONE, 0, FColor::Black, "Actor hit that has no RaycastSelectable!" + HitActor->GetName());
}else
{
GEngine->AddOnScreenDebugMessage(INDEX_NONE, 0, FColor::Black, HitActor->GetName());
}
}
}
}else if(bShowHitsOnScreen)
{
GEngine->AddOnScreenDebugMessage(INDEX_NONE, 0, FColor::Black, "nothing hit");
}
if(NewSelection)
{
//New valid selection
if(CurrentSelection)
{
if(CurrentSelection != NewSelection)
{
CurrentSelection->HandleOnSelectEndEvents(this);
CurrentSelectionPoint = HitResult->ImpactPoint;
NewSelection->HandleOnSelectStartEvents(this, CurrentSelectionPoint);
CurrentSelection = NewSelection;
}
}else
{
NewSelection->HandleOnSelectStartEvents(this, HitResult->ImpactPoint);
CurrentSelection = NewSelection;
CurrentSelectionPoint = HitResult->ImpactPoint;
}
}else
{
//No new valid selection
if(CurrentSelection)
{
CurrentSelection->HandleOnSelectEndEvents(this);
CurrentSelection = nullptr;
}
}
}
// Fill out your copyright notice in the Description page of Project Settings.
#include "UI/IntenSelectableWidget.h"
UIntenSelectableWidget::UIntenSelectableWidget(const FObjectInitializer& ObjectInitializer)
:Super(ObjectInitializer)
{}
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "IntenSelectableScoring.h"
#include "IntenSelectable.generated.h"
class UClickBehaviour;
class USelectionBehaviour;
class UIntenSelectComponent;
UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
class RWTHVRTOOLKIT_API UIntenSelectable : public UActorComponent
{
GENERATED_BODY()
public:
UPROPERTY(EditAnywhere, BlueprintReadWrite)
bool IsSelectable = true;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
UIntenSelectableScoring* ScoringBehaviour;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
TArray<UHoverBehaviour*> OnSelectBehaviours;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
TArray<UClickBehaviour*> OnClickBehaviours;
public:
UIntenSelectable();
TPair<FVector, float> GetBestPointScorePair(const FVector& ConeOrigin, const FVector& ConeForwardDirection, const float ConeBackwardShiftDistance, const float ConeAngle, const float LastValue, const float DeltaTime) const;
void HandleOnSelectStartEvents(const UIntenSelectComponent* IntenSelect, const FVector& Point);
void HandleOnSelectEndEvents(const UIntenSelectComponent* IntenSelect);
void HandleOnClickStartEvents(const UIntenSelectComponent* IntenSelect, const FVector& Point);
void HandleOnClickEndEvents(const UIntenSelectComponent* IntenSelect);
void InitDefaultBehaviourReferences();
void ShowErrorAndQuit(const FString& Message) const;
protected:
virtual void BeginPlay() override;
};
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "IntenSelectableScoring.h"
#include "IntenSelectableCircleScoring.generated.h"
UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
class RWTHVRTOOLKIT_API UIntenSelectableCircleScoring : public UIntenSelectableScoring
{
GENERATED_BODY()
protected:
FVector GetClosestSelectionPointTo(const FVector& Point, const FVector& Direction) const;
public:
UIntenSelectableCircleScoring();
UPROPERTY(EditAnywhere)
bool OnlyOutline = true;
UPROPERTY(EditAnywhere)
float Radius = 50;
virtual TPair<FVector, float> GetBestPointScorePair(const FVector& ConeOrigin, const FVector& ConeForwardDirection, const float ConeBackwardShiftDistance, const float ConeAngle, const float LastValue, const float DeltaTime) override;
};
#pragma once
#include "CoreMinimal.h"
#include "IntenSelectableScoring.h"
#include "IntenSelectableCubeScoring.generated.h"
UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
class RWTHVRTOOLKIT_API UIntenSelectableCubeScoring : public UIntenSelectableScoring
{
GENERATED_BODY()
protected:
static bool LineToLineIntersection(const FVector& FromA, const FVector& FromB, const FVector& ToA, const FVector& ToB, FVector& OutIntersection);
FVector GetClosestSelectionPointTo(const FVector& RayOrigin, const FVector& RayDirection);
virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
public:
UIntenSelectableCubeScoring();
UPROPERTY(EditAnywhere)
bool DrawDebug = true;
UPROPERTY(EditAnywhere)
bool BackFaceCulling = false;
UPROPERTY(EditAnywhere)
bool OnlyOutline = false;
UPROPERTY(EditAnywhere)
float XLength = 100;
UPROPERTY(EditAnywhere)
float YLength = 100;
UPROPERTY(EditAnywhere)
float ZLength = 100;
virtual TPair<FVector, float> GetBestPointScorePair(const FVector& ConeOrigin, const FVector& ConeForwardDirection, const float ConeBackwardShiftDistance, const float ConeAngle, const float LastValue, const float DeltaTime) override;
FVector GetClosestPointToRectangle(const FVector& StartPoint, const FVector& Direction, const FVector& Corner00, const FVector& Corner01, const FVector& Corner10, const FVector& Corner11) const;
};
#pragma once
#include "CoreMinimal.h"
#include "IntenSelectableScoring.h"
#include "IntenSelectableCylinderScoring.generated.h"
UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
class RWTHVRTOOLKIT_API UIntenSelectableCylinderScoring : public UIntenSelectableScoring
{
GENERATED_BODY()
protected:
static bool LineToLineIntersection(const FVector& FromA, const FVector& FromB, const FVector& ToA, const FVector& ToB, FVector& OutIntersection);
FVector GetClosestSelectionPointTo(const FVector& Point, const FVector& Direction) const;
virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
public:
UIntenSelectableCylinderScoring();
UPROPERTY(EditAnywhere)
bool DrawDebug = true;
virtual TPair<FVector, float> GetBestPointScorePair(const FVector& ConeOrigin, const FVector& ConeForwardDirection, const float ConeBackwardShiftDistance, const float ConeAngle, const float LastValue, const float DeltaTime) override;
UPROPERTY(EditAnywhere)
TArray<FVector> LinePoints{FVector::ZeroVector, FVector::ZeroVector};
UPROPERTY(EditAnywhere)
float Radius = 10;
};
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment