3#include "GripMotionControllerComponent.h"
7#include "Kismet/GameplayStatics.h"
8#include "Kismet/KismetMathLibrary.h"
9#include "Kismet/KismetSystemLibrary.h"
15 PrimaryActorTick.bCanEverTick =
true;
17 Root = CreateDefaultSubobject<USceneComponent>(
"Root");
18 Root->SetupAttachment(RootComponent);
20 MotionController = CreateDefaultSubobject<UGripMotionControllerComponent>(
"MotionController");
29 GrabSphere = CreateDefaultSubobject<USphereComponent>(
"GrabSphere");
31 GrabSphere->SetCollisionProfileName(
"OverlapAll");
32 GrabSphere->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics);
36 GrabSphere->SetRelativeLocation(FVector(2.0f, 0.0f, -2.5f));
39 HandMesh = CreateDefaultSubobject<USkeletalMeshComponent>(
"HandMesh");
42 LaserMesh = CreateDefaultSubobject<UStaticMeshComponent>(
"Laser");
44 static ConstructorHelpers::FObjectFinder<UStaticMesh> LaserMeshFinder(TEXT(
"StaticMesh'/PixoCore/Meshes/Tools/SM_LaserPointer.SM_LaserPointer'"));
45 LaserMesh->SetStaticMesh(LaserMeshFinder.Object);
48 static ConstructorHelpers::FObjectFinder<USoundCue> LaserSoundFinder(TEXT(
"SoundCue'/PixoCore/Audio/SFX/LaserToggle_Cue.LaserToggle_Cue'"));
52 TouchComponent = CreateDefaultSubobject<UWidgetInteractionComponent>(
"TouchComponent");
62 WristMenu = CreateDefaultSubobject<UChildActorComponent>(
"WristMenu");
82 APixoVRCharacter* PlayerRef = Cast<APixoVRCharacter>(UGameplayStatics::GetPlayerPawn(GetWorld(), 0));
105 FTransform ActorWorldTransformInHand;
106 if (OverlappingInfo.
OverlapActor->GetClass()->ImplementsInterface(UPixoVRStoryObject::StaticClass()))
107 ActorWorldTransformInHand = IPixoVRStoryObject::Execute_GetObjectGrabTransform(OverlappingInfo.
OverlapActor,
this);
109 ActorWorldTransformInHand = OverlappingInfo.
OverlapActor->GetTransform();
113 if (OverlappingInfo.
OverlapActor->GetClass()->ImplementsInterface(UPixoVRStoryObject::StaticClass())
114 && IPixoVRStoryObject::Execute_IsGrabbingWrongActorActive(OverlappingInfo.
OverlapActor)
117 IPixoVRStoryObject::Execute_SendWrongGrabbingNotification(OverlappingInfo.
OverlapActor);
121 if (OverlappingInfo.
OverlapActor->GetClass()->ImplementsInterface(UPixoVRStoryObject::StaticClass()) && IPixoVRStoryObject::Execute_CouldBeGrabbedByOtherHand(OverlappingInfo.
OverlapActor))
157 FTransform ActorWorldTransformInHand;
158 if (ActorRef->GetClass()->ImplementsInterface(UPixoVRStoryObject::StaticClass()))
159 ActorWorldTransformInHand = IPixoVRStoryObject::Execute_GetObjectGrabTransform(ActorRef,
this);
161 ActorWorldTransformInHand = ActorRef->GetTransform();
163 if (
MotionController->GripObjectByInterface(ActorRef, ActorWorldTransformInHand))
164 GetWorldTimerManager().SetTimerForNextTick([
this, ActorRef](){
HandHoldingObject = ActorRef;});
175 FTimerHandle TimerHandle;
190 UE_LOG(LogTemp, Error, TEXT(
"PixoVrHand - ReleaseHeldedObjectOnOtherHand - Actor reference is invalid"));
193 TArray<FBPGripPair> HoldingControllers;
195 IVRGripInterface::Execute_IsHeld(HeldActor, HoldingControllers, IsHeld);
198 APixoVRCharacter* PlayerRef = Cast<APixoVRCharacter>(UGameplayStatics::GetPlayerPawn(GetWorld(), 0));
207 if (HandHGrabbingItem->
HandMesh->GetAnimInstance()->GetClass()->ImplementsInterface(UHandAnimationInterface::StaticClass()))
215 if (HandHoldingItem->
HandMesh->GetAnimInstance()->GetClass()->ImplementsInterface(UHandAnimationInterface::StaticClass()))
226 UGameplayStatics::PlaySound2D(
this,
LaserSound);
233 UE_LOG(LogTemp, Error, TEXT(
"Grab precision can not be less then 1"));
234 return TArray<FVector>();
238 float stepSize = FingerSpline->Duration / Precision;
239 TArray<FVector> relativePointsArray;
240 for (
int i = 0; i < Precision - 1; i++)
242 float splineTime = UKismetMathLibrary::FClamp(i * stepSize, 0.0, 1.0);
243 relativePointsArray.Add(UKismetMathLibrary::TransformLocation(
244 FingerSpline->GetRelativeTransform(),
245 FingerSpline->GetLocationAtTime(splineTime, ESplineCoordinateSpace::Local,
true)));
247 return relativePointsArray;
249 UE_LOG(LogTemp, Error, TEXT(
"Spline reference is not valid"));
250 return TArray<FVector>();
255 FVector splinePointLocation;
256 FVector nextSplinePointLocation;
258 float totalLenght = 0;
260 FHitResult hitResult;
261 TArray<TEnumAsByte<EObjectTypeQuery>> traceObjectTypes;
262 traceObjectTypes.Add(UEngineTypes::ConvertToObjectType(ECC_WorldStatic));
263 traceObjectTypes.Add(UEngineTypes::ConvertToObjectType(ECC_WorldDynamic));
264 traceObjectTypes.Add(UEngineTypes::ConvertToObjectType(ECC_PhysicsBody));
265 FCollisionQueryParams queryParams;
266 queryParams.AddIgnoredActor(
this);
268 for (
int i = 0; i < RelativePointsArray.Num() - 2; i++)
270 splinePointLocation = UKismetMathLibrary::TransformLocation(
HandMesh->GetComponentTransform(),
271 RelativePointsArray[i]);
272 nextSplinePointLocation = UKismetMathLibrary::TransformLocation(
HandMesh->GetComponentTransform(),
273 RelativePointsArray[i + 1]);
278 bool didTraceHit = GetWorld()->LineTraceSingleByObjectType(hitResult, splinePointLocation,
279 nextSplinePointLocation, traceObjectTypes,
284 hitLenght = totalLenght + hitResult.Distance;
288 totalLenght = totalLenght + UKismetMathLibrary::Vector_Distance(splinePointLocation, nextSplinePointLocation);
291 hitLenght = totalLenght;
294 return UKismetMathLibrary::FClamp(hitLenght / totalLenght, 0.0, 1.0);
299 float precision = 30.0;
335 Super::Tick(DeltaTime);
339 switch (GripTypeChecker)
344 if (OverlapInfo.
OverlapActor->GetClass()->ImplementsInterface(UPixoVRStoryObject::StaticClass()))
346 return IPixoVRStoryObject::Execute_IsObjectActive(OverlapInfo.
OverlapActor)
347 || IPixoVRStoryObject::Execute_IsGrabbingWrongActorActive(OverlapInfo.
OverlapActor);
352 return OverlapInfo.
OverlapActor->GetClass()->ImplementsInterface(UPixoVRStoryObject::StaticClass());
354 return OverlapInfo.
OverlapActor->GetClass()->ImplementsInterface(UVRGripInterface::StaticClass());
375 if (
OverlapedActor->GetClass()->ImplementsInterface(UPixoVRStoryObject::StaticClass()))
377 IPixoVRStoryObject::Execute_UpdateObjectHighlight(
OverlapedActor,
false);
388 if (
OverlapedActor->GetClass()->ImplementsInterface(UPixoVRStoryObject::StaticClass()))
390 IPixoVRStoryObject::Execute_UpdateObjectHighlight(
OverlapedActor,
true);
403 if (
OverlapedActor->GetClass()->ImplementsInterface(UPixoVRStoryObject::StaticClass()))
405 IPixoVRStoryObject::Execute_UpdateObjectHighlight(
OverlapedActor,
false);
413 if (
OverlapedActor->GetClass()->ImplementsInterface(UPixoVRStoryObject::StaticClass()))
415 IPixoVRStoryObject::Execute_UpdateObjectHighlight(
OverlapedActor,
false);
428 switch (MotionSource)
430 case EControllerHand::Left:
431 MotionController->SetTrackingMotionSource(FXRMotionControllerBase::LeftHandSourceId);
432 HandMesh->SetRelativeScale3D(FVector(1.0, 1.0, -1.0));
436 case EControllerHand::Right:
437 MotionController->SetTrackingMotionSource(FXRMotionControllerBase::RightHandSourceId);
441 UE_LOG(LogTemp, Error, TEXT(
"Hand motion source is undefined!"));
450 if (
HandMesh->GetAnimInstance()->GetClass()->ImplementsInterface(UHandAnimationInterface::StaticClass()))
452 IHandAnimationInterface::Execute_SetHandActor(
HandMesh->GetAnimInstance(),
this);
455 UE_LOG(LogTemp, Error, TEXT(
"Animation blueprint does not implement PixoVRGripInterface"));
458void APixoVRHand::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps)
const
460 Super::GetLifetimeReplicatedProps(OutLifetimeProps);
474 TArray<TEnumAsByte<EObjectTypeQuery>> ObjectTypes;
475 ObjectTypes.Add(UEngineTypes::ConvertToObjectType(ECC_WorldDynamic));
476 ObjectTypes.Add(UEngineTypes::ConvertToObjectType(ECC_PhysicsBody));
477 ObjectTypes.Add(UEngineTypes::ConvertToObjectType(ECC_WorldStatic));
478 auto TraceComplex =
false;
479 TArray<AActor*> ActorsToIgnore;
480 auto IgnoreSelf =
true;
481 TArray<FHitResult> HitResults;
485 bool Hit = UKismetSystemLibrary::SphereTraceMultiForObjects(GetWorld(),
488 GetForwardVector() * 0.01),
493 EDrawDebugTrace::None,
500 for (
const auto& HitResult : HitResults)
503 if (HitResult.Actor->GetClass()->ImplementsInterface(UVRGripInterface::StaticClass()))
507 if (HitResult.Component->GetClass()->ImplementsInterface(UVRGripInterface::StaticClass()))
513 if (HitResult.BoneName != NAME_None)
515 OverlappingInfo.
Socket = HitResult.BoneName;
EGrippableTypeChecker
EGrippableTypeChecker is an enumeration that represents what type of objects we can grip.
Pixo VR Character This class represents the main character in the Pixo VR game. It extends the AVRCha...
APixoVRHand * VRHandLeft
UPROPERTY(BlueprintReadOnly, Category = "Hands")
APixoVRHand * VRHandRight
UPROPERTY(BlueprintReadOnly, Category = "Hands")
APixoVRHand is an actor class that represents a hand in the VR environment.
void SetupFingerTracePoints()
Sets up the cache of relative points for finger tracing. This function should be called during initia...
float TraceFingerForObstacle(TArray< FVector > RelativePointsArray)
Traces the finger along the given array of relative points to check for obstacles.
TArray< FVector > ThumbPositionCache
void UpdateFingerData()
Updates the finger data by tracing each finger for obstacles and storing the normalized obstacle dist...
UWidgetInteractionComponent * TouchComponent
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Components")
bool TouchComponentCooldownActive
void ManuallyPutActorToHand(AActor *ActorRef)
Manually puts an actor into the hand. Hand will try to grab this actor.
FFingerData FingerData
UPROPERTY(EditAnywhere, BlueprintReadWrite, Replicated, Category = "Animation")
bool ChangeHandAnimationNearInteractableObject
UPROPERTY(EditDefaultsOnly, Category = "Animation")
void DeactivateTouchCooldown()
Deactivates the touch cooldown of the hand.
bool InteractableObjectNearHand
UStaticMeshComponent * LaserMesh
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = "Components")
USkeletalMeshComponent * HandMesh
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = "Components")
bool IsWristMenuEnabled
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Components")
void GrabObject()
Grabs the object currently overlapped by grab sphere.
APixoVRCharacter * OwningCharacter
UPROPERTY(BlueprintReadWrite, Category = "Init")
USplineComponent * RingSpline
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Components")
bool IsObjectHighlightActive
Show highlight if hand near object that we can grab.
USplineComponent * PinkySpline
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Components")
TArray< FVector > GetRelativePointsArray(USplineComponent *FingerSpline, float Precision)
Retrieves an array of relative points along the finger spline.
TArray< FVector > MiddlePositionCache
void InitPixoVRHands(EControllerHand MotionSource, APixoVRCharacter *Character)
UGripMotionControllerComponent * MotionController
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = "Components")
virtual void BeginPlay() override
USphereComponent * GrabSphere
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = "Components")
virtual void Tick(float DeltaTime) override
void ReleaseHeldObjectOnOtherHand(AActor *HeldActor)
Releases the held object on the other hand.
USplineComponent * MiddleSpline
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Components")
void SetWristMenuEnabled(bool Enabled)
Enables or disables wrist menu.
USceneComponent * Root
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = "Components")
void GetOverlappingActor(FOverlappingInfo &OverlappingInfo)
Gets the info of actor currently overlapping with the grab sphere.
EGrippableTypeChecker GrippableTypeChecker
Flag that indicated near which objects should we change animation.
void ReleaseObject()
Releases the currently held object.
USplineComponent * ThumbSpline
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Components")
TArray< FVector > PinkyPositionCache
EControllerHand HandMotionSource
UPROPERTY(BlueprintReadWrite, Category = "Init", meta = (ExposeOnSpawn = "true"))
void OnObjectOutOfRange(const FBPActorGripInformation &GripInformation, float Distance)
Handling case when object physical constraint has been broken by range.
USplineComponent * IndexSpline
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Components")
TArray< FVector > IndexPositionCache
UObject * HandHoldingObject
UPROPERTY(BlueprintReadOnly, Replicated, Category = "PixoVR")
void OnTouchWidget(UWidgetComponent *WidgetComponent, UWidgetComponent *PreviousWidgetComponent)
Called when the hand touches a widget component.
void ToggleLaser(bool Visible)
Toggles the visibility of the laser.
USoundCue * LaserSound
UPROPERTY()
UChildActorComponent * WristMenu
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Components")
TArray< FVector > RingPositionCache
float Middle
UPROPERTY(EditAnywhere, BlueprintReadWrite)
float Pinky
UPROPERTY(EditAnywhere, BlueprintReadWrite)
float Index
UPROPERTY(EditAnywhere, BlueprintReadWrite)
float Ring
UPROPERTY(EditAnywhere, BlueprintReadWrite)
float Thumb
UPROPERTY(EditAnywhere, BlueprintReadWrite)
FOverlappingInfo is a structure that holds information about overlapping actors and components.
UPrimitiveComponent * OverlapComponent