Skip to content
Snippets Groups Projects
Commit 593baa34 authored by Ehret's avatar Ehret
Browse files

Merge branch 'develop' into feature/desktop_camera

parents bdb8878c 67ff2f45
No related branches found
No related tags found
No related merge requests found
Showing
with 281 additions and 157 deletions
...@@ -10,8 +10,6 @@ UGrabbingBehaviorOnLineComponent::UGrabbingBehaviorOnLineComponent() ...@@ -10,8 +10,6 @@ UGrabbingBehaviorOnLineComponent::UGrabbingBehaviorOnLineComponent()
// off to improve performance if you don't need them. // off to improve performance if you don't need them.
PrimaryComponentTick.bCanEverTick = true; PrimaryComponentTick.bCanEverTick = true;
SetAbsolute(true, true, true);
this->Distance = 0; this->Distance = 0;
} }
...@@ -23,11 +21,20 @@ void UGrabbingBehaviorOnLineComponent::SetDistance(float Dist) ...@@ -23,11 +21,20 @@ void UGrabbingBehaviorOnLineComponent::SetDistance(float Dist)
this->Distance = Dist; this->Distance = Dist;
} }
float UGrabbingBehaviorOnLineComponent::GetDistance() const float UGrabbingBehaviorOnLineComponent::GetDistance() const
{ {
return this->Distance; return this->Distance;
} }
void UGrabbingBehaviorOnLineComponent::SetDiscreteNumberOfPoints(int Num)
{
NumPoints = Num;
bIsDiscrete = true;
}
void UGrabbingBehaviorOnLineComponent::HandleNewPositionAndDirection(FVector Position, FQuat Orientation) void UGrabbingBehaviorOnLineComponent::HandleNewPositionAndDirection(FVector Position, FQuat Orientation)
{ {
FVector AttachmentPoint = this->GetRelativeLocation(); FVector AttachmentPoint = this->GetRelativeLocation();
...@@ -49,6 +56,19 @@ void UGrabbingBehaviorOnLineComponent::HandleNewPositionAndDirection(FVector Pos ...@@ -49,6 +56,19 @@ void UGrabbingBehaviorOnLineComponent::HandleNewPositionAndDirection(FVector Pos
FVector NewPosition = FVector::DotProduct(FromOriginToIntersection, ConstraintAxis) * ConstraintAxis; FVector NewPosition = FVector::DotProduct(FromOriginToIntersection, ConstraintAxis) * ConstraintAxis;
NewPosition = NewPosition.GetClampedToMaxSize(Distance); NewPosition = NewPosition.GetClampedToMaxSize(Distance);
if (bIsDiscrete)
{
float lengthOfSegment = 1.f / static_cast<float>(NumPoints + 1.f);
FVector LineBeginning = -ConstraintAxis * Distance;
float LengthOnLine = (FVector::DotProduct(FromOriginToIntersection, ConstraintAxis) / Distance + 1.f) / 2.f; // is between 0 and 1
float VectorSize = FMath::CeilToFloat(LengthOnLine / lengthOfSegment);
if (VectorSize <= 0) VectorSize = 1;
if (VectorSize > NumPoints) VectorSize = NumPoints;
NewPosition = LineBeginning + VectorSize * ConstraintAxis * lengthOfSegment * Distance * 2.f;
}
NewPosition += AttachmentPoint; NewPosition += AttachmentPoint;
// transform the targeted actor which is owner of this component with calculated quaternion and posiition // transform the targeted actor which is owner of this component with calculated quaternion and posiition
...@@ -56,6 +76,7 @@ void UGrabbingBehaviorOnLineComponent::HandleNewPositionAndDirection(FVector Pos ...@@ -56,6 +76,7 @@ void UGrabbingBehaviorOnLineComponent::HandleNewPositionAndDirection(FVector Pos
GetOwner()->SetActorLocation(NewPosition); GetOwner()->SetActorLocation(NewPosition);
} }
// Called when the game starts // Called when the game starts
void UGrabbingBehaviorOnLineComponent::BeginPlay() void UGrabbingBehaviorOnLineComponent::BeginPlay()
{ {
......
...@@ -9,9 +9,6 @@ UGrabbingBehaviorOnPlaneComponent::UGrabbingBehaviorOnPlaneComponent() ...@@ -9,9 +9,6 @@ UGrabbingBehaviorOnPlaneComponent::UGrabbingBehaviorOnPlaneComponent()
// Set this component to be initialized when the game starts, and to be ticked every frame. You can turn these features // Set this component to be initialized when the game starts, and to be ticked every frame. You can turn these features
// off to improve performance if you don't need them. // off to improve performance if you don't need them.
PrimaryComponentTick.bCanEverTick = true; PrimaryComponentTick.bCanEverTick = true;
SetAbsolute(true, true, true);
// ...
} }
...@@ -43,7 +40,6 @@ void UGrabbingBehaviorOnPlaneComponent::HandleNewPositionAndDirection(FVector Po ...@@ -43,7 +40,6 @@ void UGrabbingBehaviorOnPlaneComponent::HandleNewPositionAndDirection(FVector Po
// after this NewPoint is in world position // after this NewPoint is in world position
NewPosition += AttachmentPoint; NewPosition += AttachmentPoint;
// set new position and orientation using calculated quaternion and position // set new position and orientation using calculated quaternion and position
// here rotation is not changed // here rotation is not changed
GetOwner()->SetActorLocation(NewPosition); GetOwner()->SetActorLocation(NewPosition);
......
// Fill out your copyright notice in the Description page of Project Settings.
#include "Interaction/Targetable.h"
UTargetable::UTargetable(const FObjectInitializer& ObjectInitializer)
:Super(ObjectInitializer)
{}
// 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 "Pawn/BasicVRInteractionComponent.h" #include "Pawn/BasicVRInteractionComponent.h"
...@@ -6,7 +6,10 @@ ...@@ -6,7 +6,10 @@
#include "Interaction/Clickable.h" #include "Interaction/Clickable.h"
#include "Interaction/Grabable.h" #include "Interaction/Grabable.h"
#include "Interaction/Targetable.h"
#include "Interaction/GrabbingBehaviorComponent.h" #include "Interaction/GrabbingBehaviorComponent.h"
#include "Misc/Optional.h"
#include "DrawDebugHelpers.h"
// Sets default values for this component's properties // Sets default values for this component's properties
UBasicVRInteractionComponent::UBasicVRInteractionComponent() UBasicVRInteractionComponent::UBasicVRInteractionComponent()
...@@ -24,27 +27,16 @@ void UBasicVRInteractionComponent::BeginInteraction() ...@@ -24,27 +27,16 @@ void UBasicVRInteractionComponent::BeginInteraction()
// start and end point for raytracing // start and end point for raytracing
const FTwoVectors StartEnd = GetHandRay(MaxClickDistance); const FTwoVectors StartEnd = GetHandRay(MaxClickDistance);
const FVector Start = StartEnd.v1; TOptional<FHitResult> Hit = RaytraceForFirstHit(StartEnd);
const FVector End = StartEnd.v2; if (!Hit.IsSet())
// will be filled by the Line Trace Function
FHitResult Hit;
//if hit was not found return
const FCollisionObjectQueryParams Params;
if (!GetWorld()->LineTraceSingleByObjectType(Hit, Start, End, Params))
return; return;
AActor* HitActor = Hit.GetActor(); AActor* HitActor = Hit->GetActor();
// try to cast HitActor into a Grabable if not succeeded will become a nullptr if (HitActor->Implements<UGrabable>() && Hit->Distance < MaxGrabDistance)
IGrabable* GrabableActor = Cast<IGrabable>(HitActor);
IClickable* ClickableActor = Cast<IClickable>(HitActor);
if (GrabableActor != nullptr && Hit.Distance < MaxGrabDistance)
{ {
// call grabable actors function so he reacts to our grab // call grabable actors function so he reacts to our grab
GrabableActor->OnGrabbed_Implementation(); IGrabable::Execute_OnBeginGrab(HitActor);
// save it for later, is needed every tick // save it for later, is needed every tick
Behavior = HitActor->FindComponentByClass<UGrabbingBehaviorComponent>(); Behavior = HitActor->FindComponentByClass<UGrabbingBehaviorComponent>();
...@@ -54,13 +46,12 @@ void UBasicVRInteractionComponent::BeginInteraction() ...@@ -54,13 +46,12 @@ void UBasicVRInteractionComponent::BeginInteraction()
// we save the grabbedActor in a general form to access all of AActors functions easily later // we save the grabbedActor in a general form to access all of AActors functions easily later
GrabbedActor = HitActor; GrabbedActor = HitActor;
} }
else if (ClickableActor != nullptr && Hit.Distance < MaxClickDistance) else if (HitActor->Implements<UClickable>() && Hit->Distance < MaxClickDistance)
{ {
ClickableActor->OnClicked_Implementation(Hit.Location); IClickable::Execute_OnClick(HitActor, Hit->Location);
} }
} }
void UBasicVRInteractionComponent::EndInteraction() void UBasicVRInteractionComponent::EndInteraction()
{ {
if(!InteractionRayEmitter) return; if(!InteractionRayEmitter) return;
...@@ -70,17 +61,23 @@ void UBasicVRInteractionComponent::EndInteraction() ...@@ -70,17 +61,23 @@ void UBasicVRInteractionComponent::EndInteraction()
return; return;
// let the grabbed object react to release // let the grabbed object react to release
Cast<IGrabable>(GrabbedActor)->OnReleased_Implementation(); IGrabable::Execute_OnEndGrab(GrabbedActor);
// Detach the Actor // Detach the Actor
if (GrabbedActor->FindComponentByClass<UGrabbingBehaviorComponent>() == nullptr) if (GrabbedActor->FindComponentByClass<UGrabbingBehaviorComponent>() == nullptr)
{ {
if (ComponentSimulatingPhysics) {
ComponentSimulatingPhysics->DetachFromComponent(FDetachmentTransformRules::KeepWorldTransform);
ComponentSimulatingPhysics->SetSimulatePhysics(true);
}
else {
GrabbedActor->GetRootComponent()->DetachFromComponent(FDetachmentTransformRules::KeepWorldTransform); GrabbedActor->GetRootComponent()->DetachFromComponent(FDetachmentTransformRules::KeepWorldTransform);
GrabbedActor->FindComponentByClass<UPrimitiveComponent>()->SetSimulatePhysics(bDidSimulatePhysics); }
} }
// forget about the actor // forget about the actor
GrabbedActor = nullptr; GrabbedActor = nullptr;
ComponentSimulatingPhysics = nullptr;
Behavior = nullptr; Behavior = nullptr;
} }
...@@ -89,10 +86,9 @@ void UBasicVRInteractionComponent::TickComponent(float DeltaTime, ELevelTick Tic ...@@ -89,10 +86,9 @@ void UBasicVRInteractionComponent::TickComponent(float DeltaTime, ELevelTick Tic
{ {
Super::TickComponent(DeltaTime, TickType, ThisTickFunction); Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
// if an actor is grabbed and a behavior is defined move move him accordingly if (!InteractionRayEmitter) return;
if (GrabbedActor == nullptr || InteractionRayEmitter == nullptr) return;
// if our Grabable Actor is not constrained // if our Grabable Actor is not constrained we need to calculate the position dynamically
if (Behavior != nullptr) if (Behavior != nullptr)
{ {
// specifies the hand in space // specifies the hand in space
...@@ -101,6 +97,22 @@ void UBasicVRInteractionComponent::TickComponent(float DeltaTime, ELevelTick Tic ...@@ -101,6 +97,22 @@ void UBasicVRInteractionComponent::TickComponent(float DeltaTime, ELevelTick Tic
Behavior->HandleNewPositionAndDirection(HandPos, HandQuat); Behavior->HandleNewPositionAndDirection(HandPos, HandQuat);
} }
// only raytrace for targetable objects if bool user wants to enable this feature
if (!bCanRaytraceEveryTick)
return;
const FTwoVectors StartEnd = GetHandRay(MaxClickDistance);
TOptional<FHitResult> Hit = RaytraceForFirstHit(StartEnd);
if (!Hit.IsSet())
return;
AActor* HitActor = Hit->GetActor();
// for now uses the same distance as clicking
if (HitActor->Implements<UTargetable>() && Hit->Distance < MaxClickDistance)
{
ITargetable::Execute_OnTargeted(HitActor, Hit->Location);
}
} }
void UBasicVRInteractionComponent::Initialize(USceneComponent* RayEmitter, float InMaxGrabDistance, float InMaxClickDistance) void UBasicVRInteractionComponent::Initialize(USceneComponent* RayEmitter, float InMaxGrabDistance, float InMaxClickDistance)
...@@ -114,12 +126,17 @@ void UBasicVRInteractionComponent::Initialize(USceneComponent* RayEmitter, float ...@@ -114,12 +126,17 @@ void UBasicVRInteractionComponent::Initialize(USceneComponent* RayEmitter, float
void UBasicVRInteractionComponent::HandlePhysicsAndAttachActor(AActor* HitActor) void UBasicVRInteractionComponent::HandlePhysicsAndAttachActor(AActor* HitActor)
{ {
UPrimitiveComponent* PhysicsComp = HitActor->FindComponentByClass<UPrimitiveComponent>(); UPrimitiveComponent* PhysicsSimulatingComp = GetFirstComponentSimulatingPhysics(HitActor);
const FAttachmentTransformRules Rules = FAttachmentTransformRules(EAttachmentRule::KeepWorld, false);
bDidSimulatePhysics = PhysicsComp->IsSimulatingPhysics(); // remember if we need to tun physics back on or not if (PhysicsSimulatingComp) {
PhysicsComp->SetSimulatePhysics(false); PhysicsSimulatingComp->SetSimulatePhysics(false);
FAttachmentTransformRules Rules = FAttachmentTransformRules(EAttachmentRule::KeepWorld, true); PhysicsSimulatingComp->AttachToComponent(InteractionRayEmitter, Rules);
HitActor->AttachToComponent(InteractionRayEmitter, Rules); ComponentSimulatingPhysics = PhysicsSimulatingComp;
}
else {
HitActor->GetRootComponent()->AttachToComponent(InteractionRayEmitter, Rules);
}
} }
FTwoVectors UBasicVRInteractionComponent::GetHandRay(const float Length) const FTwoVectors UBasicVRInteractionComponent::GetHandRay(const float Length) const
...@@ -130,3 +147,45 @@ FTwoVectors UBasicVRInteractionComponent::GetHandRay(const float Length) const ...@@ -130,3 +147,45 @@ FTwoVectors UBasicVRInteractionComponent::GetHandRay(const float Length) const
return FTwoVectors(Start, End); return FTwoVectors(Start, End);
} }
TOptional<FHitResult> UBasicVRInteractionComponent::RaytraceForFirstHit(const FTwoVectors& Ray) const
{
const FVector Start = Ray.v1;
const FVector End = Ray.v2;
// will be filled by the Line Trace Function
FHitResult Hit;
const FCollisionObjectQueryParams Params;
FCollisionQueryParams Params2;
Params2.AddIgnoredActor(GetOwner()->GetUniqueID()); // prevents actor hitting itself
if (GetWorld()->LineTraceSingleByObjectType(Hit, Start, End, Params, Params2))
return {Hit};
else
return {};
}
UPrimitiveComponent* GetFirstComponentSimulatingPhysics(const AActor* TargetActor)
{
TArray<UPrimitiveComponent*> PrimitiveComponents;
TargetActor->GetComponents<UPrimitiveComponent>(PrimitiveComponents);
// find any component that simulates physics, then traverse the hierarchy
for (const auto& Component : PrimitiveComponents) {
if (Component->IsSimulatingPhysics()) {
return GetHighestParentSimulatingPhysics(Component);
}
}
return nullptr;
}
// recursively goes up the hierarchy and returns the highest parent simulating physics
UPrimitiveComponent* GetHighestParentSimulatingPhysics(UPrimitiveComponent* Comp)
{
if (Cast<UPrimitiveComponent>(Comp->GetAttachParent()) && Comp->GetAttachParent()->IsSimulatingPhysics()) {
return GetHighestParentSimulatingPhysics(Cast<UPrimitiveComponent>(Comp->GetAttachParent()));
}
else {
return Comp;
}
}
...@@ -18,7 +18,7 @@ struct DISPLAYCLUSTEREXTENSIONS_API FCAVEOverlay ...@@ -18,7 +18,7 @@ struct DISPLAYCLUSTEREXTENSIONS_API FCAVEOverlay
void Register(); void Register();
void Unregister() const; void Unregister() const;
private: private:
TBaseDelegate<void, UWorld*, const UWorld::InitializationValues> On_Post_World_Initialization_Delegate; TDelegate<void(UWorld*, const UWorld::InitializationValues)> On_Post_World_Initialization_Delegate;
void OnSessionStart(UWorld* World, UWorld::InitializationValues); void OnSessionStart(UWorld* World, UWorld::InitializationValues);
FDelegateHandle SessionStartDelegate; FDelegateHandle SessionStartDelegate;
}; };
...@@ -7,7 +7,6 @@ ...@@ -7,7 +7,6 @@
#include "UObject/Interface.h" #include "UObject/Interface.h"
#include "Clickable.generated.h" #include "Clickable.generated.h"
UINTERFACE(BlueprintType) UINTERFACE(BlueprintType)
class DISPLAYCLUSTEREXTENSIONS_API UClickable : public UInterface class DISPLAYCLUSTEREXTENSIONS_API UClickable : public UInterface
{ {
...@@ -22,8 +21,6 @@ class IClickable ...@@ -22,8 +21,6 @@ class IClickable
public: public:
// function that will be called when clickable actor got clicked, and passed the world pos of the click // function that will be called when clickable actor got clicked, and passed the world pos of the click
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = Gameplay) UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = Gameplay)
void OnClicked(FVector WorldPositionOfClick); void OnClick(FVector WorldPositionOfClick);
}; };
...@@ -21,10 +21,9 @@ class IGrabable ...@@ -21,10 +21,9 @@ class IGrabable
public: public:
// function that will be called when grabbed by a pawn // function that will be called when grabbed by a pawn
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = Gameplay) UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = Gameplay)
void OnGrabbed(); void OnBeginGrab();
// called when pawn released the object // called when pawn released the object
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = Gameplay) UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = Gameplay)
void OnReleased(); void OnEndGrab();
}; };
...@@ -19,6 +19,7 @@ public: ...@@ -19,6 +19,7 @@ public:
// defining a constraint line with these 3 parameters // defining a constraint line with these 3 parameters
UFUNCTION(BlueprintCallable) void SetDistance(float Dist); UFUNCTION(BlueprintCallable) void SetDistance(float Dist);
UFUNCTION(BlueprintCallable) float GetDistance() const; UFUNCTION(BlueprintCallable) float GetDistance() const;
UFUNCTION(BlueprintCallable) void SetDiscreteNumberOfPoints(int Num);
virtual void HandleNewPositionAndDirection(FVector position, FQuat orientation) override; virtual void HandleNewPositionAndDirection(FVector position, FQuat orientation) override;
...@@ -30,8 +31,8 @@ public: ...@@ -30,8 +31,8 @@ public:
// Called every frame // Called every frame
virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override; virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
private: private:
UPROPERTY(EditAnywhere) float Distance; // distance the object can be moved from the center UPROPERTY(EditAnywhere) float Distance = 100; // distance the object can be moved from the center
UPROPERTY(EditAnywhere) bool bIsDiscrete = false;
UPROPERTY(EditAnywhere) int NumPoints = 1;
}; };
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "UObject/Object.h"
#include "UObject/Interface.h"
#include "Targetable.generated.h"
UINTERFACE(BlueprintType)
class DISPLAYCLUSTEREXTENSIONS_API UTargetable: public UInterface
{
// has to be empty, this is Unreals syntax to make it visible in blueprints
GENERATED_UINTERFACE_BODY()
};
class ITargetable
{
GENERATED_IINTERFACE_BODY()
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);
};
...@@ -26,19 +26,37 @@ public: ...@@ -26,19 +26,37 @@ public:
UPROPERTY(BlueprintReadWrite) float MaxGrabDistance = 50; UPROPERTY(BlueprintReadWrite) float MaxGrabDistance = 50;
UPROPERTY(BlueprintReadWrite) float MaxClickDistance = 500; UPROPERTY(BlueprintReadWrite) float MaxClickDistance = 500;
// Enable this if you want to interact with Targetable classes
UPROPERTY(EditAnywhere) bool bCanRaytraceEveryTick = false;
UFUNCTION(BlueprintCallable) void Initialize(USceneComponent* RayEmitter, float InMaxGrabDistance = 50, float InMaxClickDistance = 500); UFUNCTION(BlueprintCallable) void Initialize(USceneComponent* RayEmitter, float InMaxGrabDistance = 50, float InMaxClickDistance = 500);
UFUNCTION(BlueprintCallable, BlueprintPure) AActor* GetGrabbedActor() const { return GrabbedActor;} UFUNCTION(BlueprintCallable, BlueprintPure) AActor* GetGrabbedActor() const { return GrabbedActor;}
UFUNCTION(BlueprintCallable, BlueprintPure) USceneComponent* GetInteractionRayEmitter() const { return InteractionRayEmitter; } UFUNCTION(BlueprintCallable, BlueprintPure) USceneComponent* GetInteractionRayEmitter() const { return InteractionRayEmitter; }
private: private:
/* indicates if the grabbed actor was simulating physics before we grabbed it */
UPROPERTY() bool bDidSimulatePhysics;
/* Holding a reference to the actor that is currently being grabbed */ /* Holding a reference to the actor that is currently being grabbed */
UPROPERTY() AActor* GrabbedActor; UPROPERTY() AActor* GrabbedActor;
/* Holds a reference to the grabbed actors physics simulating component if there was one*/
UPROPERTY() UPrimitiveComponent* ComponentSimulatingPhysics = nullptr;
UPROPERTY() UGrabbingBehaviorComponent* Behavior = nullptr; UPROPERTY() UGrabbingBehaviorComponent* Behavior = nullptr;
UPROPERTY() USceneComponent* InteractionRayEmitter = nullptr; UPROPERTY() USceneComponent* InteractionRayEmitter = nullptr;
void HandlePhysicsAndAttachActor(AActor* HitActor); void HandlePhysicsAndAttachActor(AActor* HitActor);
FTwoVectors GetHandRay(float Length) const; FTwoVectors GetHandRay(float Length) const;
TOptional<FHitResult> RaytraceForFirstHit(const FTwoVectors& Ray) const;
}; };
// Free utility functions
/*
Returns the UPrimitiveComponent simulating physics that is highest in the hierarchy
*/
UPrimitiveComponent* GetFirstComponentSimulatingPhysics(const AActor* TargetActor);
/*
Recursive Function
If parent component simulates physics returns GetHighestParentSimulatingPhysics(Parent)
else returns Comp itself
*/
UPrimitiveComponent* GetHighestParentSimulatingPhysics(UPrimitiveComponent* Comp);
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment