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");
28 GrabSphere = CreateDefaultSubobject<USphereComponent>(
"GrabSphere");
30 GrabSphere->SetCollisionProfileName(
"OverlapAll");
31 GrabSphere->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics);
35 GrabSphere->SetRelativeLocation(FVector(2.0f, 0.0f, -2.5f));
38 HandMesh = CreateDefaultSubobject<USkeletalMeshComponent>(
"HandMesh");
41 LaserMesh = CreateDefaultSubobject<UStaticMeshComponent>(
"Laser");
43 static ConstructorHelpers::FObjectFinder<UStaticMesh> LaserMeshFinder(TEXT(
"StaticMesh'/PixoCore/Meshes/Tools/SM_LaserPointer.SM_LaserPointer'"));
44 LaserMesh->SetStaticMesh(LaserMeshFinder.Object);
47 static ConstructorHelpers::FObjectFinder<USoundCue> LaserSoundFinder(TEXT(
"SoundCue'/PixoCore/Audio/SFX/LaserToggle_Cue.LaserToggle_Cue'"));
51 TouchComponent = CreateDefaultSubobject<UWidgetInteractionComponent>(
"TouchComponent");
85 if (OverlappingInfo.
OverlapActor->GetClass()->ImplementsInterface(UPixoVRStoryObject::StaticClass()) && IPixoVRStoryObject::Execute_CouldBeGrabbedByOtherHand(OverlappingInfo.
OverlapActor))
121 GetWorldTimerManager().SetTimerForNextTick([
this, ActorRef](){
HandHoldingObject = ActorRef;});
132 FTimerHandle TimerHandle;
147 UE_LOG(LogTemp,
Error, TEXT(
"PixoVrHand - ReleaseHeldedObjectOnOtherHand - Actor reference is invalid"));
150 TArray<FBPGripPair> HoldingControllers;
152 IVRGripInterface::Execute_IsHeld(HeldActor, HoldingControllers, IsHeld);
155 APixoVRCharacter* PlayerRef = Cast<APixoVRCharacter>(UGameplayStatics::GetPlayerPawn(GetWorld(), 0));
157 if (IPixoVRStoryObject::Execute_HoldItemByClick(HeldActor))
180 UGameplayStatics::PlaySound2D(
this,
LaserSound);
187 UE_LOG(LogTemp,
Error, TEXT(
"Grab precision can not be less then 1"));
188 return TArray<FVector>();
192 float stepSize = FingerSpline->Duration / Precision;
193 TArray<FVector> relativePointsArray;
194 for (
int i = 0; i < Precision - 1; i++)
196 float splineTime = UKismetMathLibrary::FClamp(i * stepSize, 0.0, 1.0);
197 relativePointsArray.Add(UKismetMathLibrary::TransformLocation(
198 FingerSpline->GetRelativeTransform(),
199 FingerSpline->GetLocationAtTime(splineTime, ESplineCoordinateSpace::Local,
true)));
201 return relativePointsArray;
203 UE_LOG(LogTemp,
Error, TEXT(
"Spline reference is not valid"));
204 return TArray<FVector>();
209 FVector splinePointLocation;
210 FVector nextSplinePointLocation;
212 float totalLenght = 0;
214 FHitResult hitResult;
215 TArray<TEnumAsByte<EObjectTypeQuery>> traceObjectTypes;
216 traceObjectTypes.Add(UEngineTypes::ConvertToObjectType(ECC_WorldStatic));
217 traceObjectTypes.Add(UEngineTypes::ConvertToObjectType(ECC_WorldDynamic));
218 traceObjectTypes.Add(UEngineTypes::ConvertToObjectType(ECC_PhysicsBody));
219 FCollisionQueryParams queryParams;
220 queryParams.AddIgnoredActor(
this);
222 for (
int i = 0; i < RelativePointsArray.Num() - 2; i++)
224 splinePointLocation = UKismetMathLibrary::TransformLocation(
HandMesh->GetComponentTransform(),
225 RelativePointsArray[i]);
226 nextSplinePointLocation = UKismetMathLibrary::TransformLocation(
HandMesh->GetComponentTransform(),
227 RelativePointsArray[i + 1]);
232 bool didTraceHit = GetWorld()->LineTraceSingleByObjectType(hitResult, splinePointLocation,
233 nextSplinePointLocation, traceObjectTypes,
238 hitLenght = totalLenght + hitResult.Distance;
242 totalLenght = totalLenght + UKismetMathLibrary::Vector_Distance(splinePointLocation, nextSplinePointLocation);
245 hitLenght = totalLenght;
248 return UKismetMathLibrary::FClamp(hitLenght / totalLenght, 0.0, 1.0);
253 float precision = 30.0;
282 Super::Tick(DeltaTime);
286 switch (GripTypeChecker)
291 if (OverlapInfo.
OverlapActor->GetClass()->ImplementsInterface(UPixoVRStoryObject::StaticClass()))
292 return IPixoVRStoryObject::Execute_IsObjectActive(OverlapInfo.
OverlapActor);
295 return OverlapInfo.
OverlapActor->GetClass()->ImplementsInterface(UPixoVRStoryObject::StaticClass());
297 return OverlapInfo.
OverlapActor->GetClass()->ImplementsInterface(UVRGripInterface::StaticClass());
318 IPixoVRStoryObject::Execute_UpdateObjectHighlight(
OverlapedActor,
false);
328 IPixoVRStoryObject::Execute_UpdateObjectHighlight(OverlapInfo.
OverlapActor,
true);
340 IPixoVRStoryObject::Execute_UpdateObjectHighlight(
OverlapedActor,
false);
347 IPixoVRStoryObject::Execute_UpdateObjectHighlight(
OverlapedActor,
false);
358 switch (MotionSource)
360 case EControllerHand::Left:
361 MotionController->SetTrackingMotionSource(FXRMotionControllerBase::LeftHandSourceId);
362 HandMesh->SetRelativeScale3D(FVector(1.0, 1.0, -1.0));
365 case EControllerHand::Right:
366 MotionController->SetTrackingMotionSource(FXRMotionControllerBase::RightHandSourceId);
370 UE_LOG(LogTemp,
Error, TEXT(
"Hand motion source is undefined!"));
379 if (
HandMesh->GetAnimInstance()->GetClass()->ImplementsInterface(UHandAnimationInterface::StaticClass()))
381 IHandAnimationInterface::Execute_SetHandActor(
HandMesh->GetAnimInstance(),
this);
384 UE_LOG(LogTemp,
Error, TEXT(
"Animation blueprint does not implement PixoVRGripInterface"));
387void APixoVRHand::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps)
const
389 Super::GetLifetimeReplicatedProps(OutLifetimeProps);
403 TArray<TEnumAsByte<EObjectTypeQuery>> ObjectTypes;
404 ObjectTypes.Add(UEngineTypes::ConvertToObjectType(ECC_WorldDynamic));
405 ObjectTypes.Add(UEngineTypes::ConvertToObjectType(ECC_PhysicsBody));
406 ObjectTypes.Add(UEngineTypes::ConvertToObjectType(ECC_WorldStatic));
407 auto TraceComplex =
false;
408 TArray<AActor*> ActorsToIgnore;
409 auto IgnoreSelf =
true;
410 TArray<FHitResult> HitResults;
414 bool Hit = UKismetSystemLibrary::SphereTraceMultiForObjects(GetWorld(),
417 GetForwardVector() * 0.01),
422 EDrawDebugTrace::None,
429 for (
const auto& HitResult : HitResults)
432 if (HitResult.Actor->GetClass()->ImplementsInterface(UVRGripInterface::StaticClass()))
436 if (HitResult.Component->GetClass()->ImplementsInterface(UVRGripInterface::StaticClass()))
442 if (HitResult.BoneName != NAME_None)
444 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")
virtual void GrabLeftReleased()
UFUNCTION(BlueprintCallable, Category = "Hands")
virtual void GrabRightReleased()
UFUNCTION(BlueprintCallable, 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")
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")
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"))
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()
TArray< FVector > RingPositionCache
bool GripObjectByInterface(UObject *ObjectToGrip, const FTransform &WorldOffset, bool bWorldOffsetIsRelative=false, FName OptionalBoneToGripName=NAME_None, FName OptionalSnapToSocketName=NAME_None, bool bIsSlotGrip=false)
UFUNCTION(BlueprintCallable, Category = "GripMotionController")
bool bOffsetByHMD
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "GripMotionController|Advanced|Tracking")
bool DropObjectByInterface(UObject *ObjectToDrop=nullptr, uint8 GripIDToDrop=0, FVector OptionalAngularVelocity=FVector::ZeroVector, FVector OptionalLinearVelocity=FVector::ZeroVector)
UFUNCTION(BlueprintCallable, Category = "GripMotionController")
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