A Demo Project for the UnrealEngineSDK
Loading...
Searching...
No Matches
VRButtonComponent.cpp
Go to the documentation of this file.
1// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved.
2
4#include "GameFramework/Character.h"
5
6 //=============================================================================
7UVRButtonComponent::UVRButtonComponent(const FObjectInitializer& ObjectInitializer)
8 : Super(ObjectInitializer)
9{
10 this->SetGenerateOverlapEvents(true);
11 this->PrimaryComponentTick.bStartWithTickEnabled = false;
12 PrimaryComponentTick.bCanEverTick = true;
13
14 LastToggleTime = 0.0f;
15 DepressDistance = 8.0f;
16 ButtonEngageDepth = 8.0f;
17 DepressSpeed = 50.0f;
18
21
23
24 bIsEnabled = true;
26 bButtonState = false;
27
28 this->SetCollisionResponseToAllChannels(ECR_Overlap);
29
31 InitialRelativeTransform = FTransform::Identity;
32
33 bReplicateMovement = false;
34}
35
36//=============================================================================
40
41void UVRButtonComponent::GetLifetimeReplicatedProps(TArray< class FLifetimeProperty > & OutLifetimeProps) const
42{
43 Super::GetLifetimeReplicatedProps(OutLifetimeProps);
44
48 DOREPLIFETIME_CONDITION(UVRButtonComponent, bButtonState, COND_InitialOnly);
49}
50
51void UVRButtonComponent::PreReplication(IRepChangedPropertyTracker & ChangedPropertyTracker)
52{
53 Super::PreReplication(ChangedPropertyTracker);
54
55 // Replicate the levers initial transform if we are replicating movement
56 //DOREPLIFETIME_ACTIVE_OVERRIDE(UVRButtonComponent, InitialRelativeTransform, bReplicateMovement);
57
58 DOREPLIFETIME_ACTIVE_OVERRIDE_PRIVATE_PROPERTY(USceneComponent, RelativeLocation, bReplicateMovement);
59 DOREPLIFETIME_ACTIVE_OVERRIDE_PRIVATE_PROPERTY(USceneComponent, RelativeRotation, bReplicateMovement);
60 DOREPLIFETIME_ACTIVE_OVERRIDE_PRIVATE_PROPERTY(USceneComponent, RelativeScale3D, bReplicateMovement);
61}
62
64{
65 Super::OnRegister();
67}
68
70{
71 // Call the base class
72 Super::BeginPlay();
73
75
76 OnComponentBeginOverlap.AddUniqueDynamic(this, &UVRButtonComponent::OnOverlapBegin);
77 OnComponentEndOverlap.AddUniqueDynamic(this, &UVRButtonComponent::OnOverlapEnd);
78}
79
80void UVRButtonComponent::TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction *ThisTickFunction)
81{
82 // Call supers tick (though I don't think any of the base classes to this actually implement it)
83 Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
84
85 const float WorldTime = GetWorld()->GetRealTimeSeconds();
86
87 if (LocalInteractingComponent.IsValid())
88 {
89 // If button was set to inactive during use
90 if (!bIsEnabled)
91 {
92 // Remove interacting component and return, next tick will begin lerping back
94 return;
95 }
96
97 FTransform OriginalBaseTransform = CalcNewComponentToWorld(InitialRelativeTransform);
98
99 float CheckDepth = FMath::Clamp(GetAxisValue(InitialLocation) - GetAxisValue(OriginalBaseTransform.InverseTransformPosition(LocalInteractingComponent->GetComponentLocation())), 0.0f, DepressDistance);
100
101 if (CheckDepth > 0.0f)
102 {
103
104 float ClampMinDepth = 0.0f;
105
106 // If active and a toggled stay, then clamp min to the toggled stay location
108 ClampMinDepth = -(ButtonEngageDepth + (1.e-2f)); // + NOT_SO_KINDA_SMALL_NUMBER
109
110 float NewDepth = FMath::Clamp(GetAxisValue(InitialComponentLoc) + (-CheckDepth), -DepressDistance, ClampMinDepth);
111 this->SetRelativeLocation(InitialRelativeTransform.TransformPosition(SetAxisValue(NewDepth)), false);
112
114 {
116 (StateChangeAuthorityType == EVRStateChangeAuthorityType::CanChangeState_Server && GetNetMode() < ENetMode::NM_Client) ||
118 {
119 if (!bToggledThisTouch && NewDepth <= (-ButtonEngageDepth) + KINDA_SMALL_NUMBER && (WorldTime - LastToggleTime) >= MinTimeBetweenEngaging)
120 {
121 LastToggleTime = WorldTime;
122 bToggledThisTouch = true;
126 }
127 }
128 }
129 }
130 }
131 else
132 {
133 // Std precision tolerance should be fine
134 if (this->GetRelativeLocation().Equals(GetTargetRelativeLocation()))
135 {
136 this->SetComponentTickEnabled(false);
137
140
141 LocalInteractingComponent.Reset(); // Just reset it here so it only does it once
143 }
144 else
145 this->SetRelativeLocation(FMath::VInterpConstantTo(this->GetRelativeLocation(), GetTargetRelativeLocation(), DeltaTime, DepressSpeed), false);
146 }
147
148
149 // Press buttons always get checked, both during press AND during lerping for if they are active or not.
151 {
153 (StateChangeAuthorityType == EVRStateChangeAuthorityType::CanChangeState_Server && GetNetMode() < ENetMode::NM_Client) ||
155 {
156 // Check for if we should set the state of the button, done here as for the press button the lerp counts for input
157 bool bCheckState = (GetAxisValue(InitialRelativeTransform.InverseTransformPosition(this->GetRelativeLocation())) <= (-ButtonEngageDepth) + KINDA_SMALL_NUMBER);
158 if (bButtonState != bCheckState && (WorldTime - LastToggleTime) >= MinTimeBetweenEngaging)
159
160 {
161 LastToggleTime = WorldTime;
162 bButtonState = bCheckState;
165 }
166 }
167 }
168
169}
170
171bool UVRButtonComponent::IsValidOverlap_Implementation(UPrimitiveComponent * OverlapComponent)
172{
173
174 // Early out on the simple checks
175 if (!OverlapComponent || OverlapComponent == GetAttachParent() || OverlapComponent->GetAttachParent() == GetAttachParent())
176 return false;
177
178 // Should return faster checking for owning character
179 AActor * OverlapOwner = OverlapComponent->GetOwner();
180 if (OverlapOwner && OverlapOwner->IsA(ACharacter::StaticClass()))
181 return true;
182
183 // Because epic motion controllers are not owned by characters have to check here too in case someone implements it like that
184 // Now since our grip controllers are a subclass to the std ones we only need to check for the base one instead of both.
185 USceneComponent * OurAttachParent = OverlapComponent->GetAttachParent();
186 if (OurAttachParent && OurAttachParent->IsA(UMotionControllerComponent::StaticClass()))
187 return true;
188
189 // Now check for if it is a grippable object and if it is currently held
190 if (OverlapComponent->GetClass()->ImplementsInterface(UVRGripInterface::StaticClass()))
191 {
192 TArray<FBPGripPair> Controllers;
193 bool bIsHeld;
194 IVRGripInterface::Execute_IsHeld(OverlapComponent, Controllers, bIsHeld);
195
196 if (bIsHeld)
197 return true;
198 }
199 else if(OverlapOwner && OverlapOwner->GetClass()->ImplementsInterface(UVRGripInterface::StaticClass()))
200 {
201 TArray<FBPGripPair> Controllers;
202 bool bIsHeld;
203 IVRGripInterface::Execute_IsHeld(OverlapOwner, Controllers, bIsHeld);
204
205 if (bIsHeld)
206 return true;
207 }
208
209 return false;
210}
211
213{
214
215 // Early out on the simple checks
216 if (!LocalInteractingComponent.IsValid() || LocalInteractingComponent == GetAttachParent() || LocalInteractingComponent->GetAttachParent() == GetAttachParent())
217 {
220 return;
221 }
222
224
225 // Should return faster checking for owning character
226 AActor * OverlapOwner = LocalInteractingComponent->GetOwner();
227 if (OverlapOwner && OverlapOwner->IsA(ACharacter::StaticClass()))
228 {
229 LocalLastInteractingActor = OverlapOwner;
230 return;
231 }
232
233 // Now check for if it is a grippable object and if it is currently held
234 if (LocalInteractingComponent->GetClass()->ImplementsInterface(UVRGripInterface::StaticClass()))
235 {
236 TArray<FBPGripPair> Controllers;
237 bool bIsHeld;
238 IVRGripInterface::Execute_IsHeld(LocalLastInteractingComponent.Get(), Controllers, bIsHeld);
239
240 if (bIsHeld && Controllers.Num())
241 {
242 AActor * ControllerOwner = Controllers[0].HoldingController != nullptr ? Controllers[0].HoldingController->GetOwner() : nullptr;
243 if (ControllerOwner)
244 {
245 LocalLastInteractingActor = ControllerOwner;
246 return;
247 }
248 }
249 }
250 else if (OverlapOwner && OverlapOwner->GetClass()->ImplementsInterface(UVRGripInterface::StaticClass()))
251 {
252 TArray<FBPGripPair> Controllers;
253 bool bIsHeld;
254 IVRGripInterface::Execute_IsHeld(OverlapOwner, Controllers, bIsHeld);
255
256 if (bIsHeld && Controllers.Num())
257 {
258 AActor * ControllerOwner = Controllers[0].HoldingController != nullptr ? Controllers[0].HoldingController->GetOwner() : nullptr;
259 if (ControllerOwner)
260 {
261 LocalLastInteractingActor = ControllerOwner;
262 return;
263 }
264 }
265 }
266
267 // Fall back to the owner, wasn't held and wasn't a character
268 if (OverlapOwner)
269 {
270 LocalLastInteractingActor = OverlapOwner;
271 return;
272 }
273
275 return;
276}
277
278void UVRButtonComponent::OnOverlapBegin(UPrimitiveComponent* OverlappedComp, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
279{
280 // Other Actor is the actor that triggered the event. Check that is not ourself.
282 {
283 LocalInteractingComponent = OtherComp;
284
285 FTransform OriginalBaseTransform = CalcNewComponentToWorld(InitialRelativeTransform);
286 FVector loc = LocalInteractingComponent->GetComponentLocation();
287 InitialLocation = OriginalBaseTransform.InverseTransformPosition(LocalInteractingComponent->GetComponentLocation());
288 InitialComponentLoc = OriginalBaseTransform.InverseTransformPosition(this->GetComponentLocation());
289 bToggledThisTouch = false;
290
291 this->SetComponentTickEnabled(true);
292
294 {
298 }
299 }
300}
301
302void UVRButtonComponent::OnOverlapEnd(UPrimitiveComponent* OverlappedComp, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex)
303{
304 if (LocalInteractingComponent.IsValid() && OtherComp == LocalInteractingComponent)
305 {
307 }
308}
309
311{
312 // If target is the half pressed
314 {
315 // 1.e-2f = MORE_KINDA_SMALL_NUMBER
316 return InitialRelativeTransform.TransformPosition(SetAxisValue(-(ButtonEngageDepth + (1.e-2f))));
317 }
318
319 // Else return going all the way back
320 return InitialRelativeTransform.GetTranslation();
321
322}
323
325{
326 switch (ButtonType)
327 {
329 {
330 }break;
332 {}break;
334 {
335 if (!bLerpToPosition)
336 {
337 float ClampMinDepth = 0.0f;
338
339 // If active and a toggled stay, then clamp min to the toggled stay location
340 if (bButtonState)
341 ClampMinDepth = -(ButtonEngageDepth + (1.e-2f)); // + NOT_SO_KINDA_SMALL_NUMBER
342
343 float NewDepth = FMath::Clamp(ClampMinDepth, -DepressDistance, ClampMinDepth);
344 this->SetRelativeLocation(InitialRelativeTransform.TransformPosition(SetAxisValue(NewDepth)), false);
345 }
346 else
347 this->SetComponentTickEnabled(true); // This will trigger the lerp to resting position
348
349 }break;
350 default:break;
351 }
352}
353
354void UVRButtonComponent::SetButtonState(bool bNewButtonState, bool bCallButtonChangedEvent, bool bSnapIntoPosition)
355{
356 // No change
357 if (bButtonState == bNewButtonState)
358 return;
359
360 bButtonState = bNewButtonState;
361 SetButtonToRestingPosition(!bSnapIntoPosition);
362 LastToggleTime = GetWorld()->GetRealTimeSeconds();
363
364 if (bCallButtonChangedEvent)
365 {
368 }
369}
370
372{
373 // Get our initial relative transform to our parent (or not if un-parented).
374 InitialRelativeTransform = this->GetRelativeTransform();
375}
376
ButtonType
UENUM()
UCLASS(Blueprintable, meta = (BlueprintSpawnableComponent), ClassGroup = (VRExpansionPlugin))
virtual void BeginPlay() override
void OnOverlapEnd(UPrimitiveComponent *OverlappedComp, AActor *OtherActor, UPrimitiveComponent *OtherComp, int32 OtherBodyIndex)
UFUNCTION()
TWeakObjectPtr< AActor > LocalLastInteractingActor
UPROPERTY(BlueprintReadOnly, Category = "VRButtonComponent")
EVRStateChangeAuthorityType StateChangeAuthorityType
UPROPERTY(EditAnywhere, BlueprintReadWrite, Replicated, Category = "VRButtonComponent|Replication")
void ResetInitialButtonLocation()
UFUNCTION(BlueprintCallable, Category = "VRButtonComponent")
bool bReplicateMovement
UPROPERTY(EditAnywhere, Replicated, BlueprintReadWrite, Category = "VRGripInterface|Replication")
float DepressDistance
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VRButtonComponent")
FVRButtonStartedInteractionSignature OnButtonBeginInteraction
UPROPERTY(BlueprintAssignable, Category = "VRButtonComponent")
FTransform_NetQuantize InitialRelativeTransform
UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_InitialRelativeTransform, Category = "VRButtonCo...
TWeakObjectPtr< UPrimitiveComponent > LocalInteractingComponent
UPROPERTY(BlueprintReadOnly, Category = "VRButtonComponent")
FVRButtonStateChangedSignature OnButtonStateChanged
UPROPERTY(BlueprintAssignable, Category = "VRButtonComponent")
float DepressSpeed
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VRButtonComponent")
void SetButtonToRestingPosition(bool bLerpToPosition=false)
UFUNCTION(BlueprintCallable, Category = "VRButtonComponent")
void SetButtonState(bool bNewButtonState, bool bCallButtonChangedEvent=true, bool bSnapIntoPosition=false)
UFUNCTION(BlueprintCallable, Category = "VRButtonComponent")
EVRInteractibleAxis ButtonAxis
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VRButtonComponent")
float ButtonEngageDepth
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VRButtonComponent")
bool bIsEnabled
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VRButtonComponent")
void ReceiveButtonStateChanged(bool bCurButtonState, AActor *LastInteractingActor, UPrimitiveComponent *InteractingComponent)
UFUNCTION(BlueprintImplementableEvent, meta = (DisplayName = "Button State Changed"))
float GetAxisValue(FVector CheckLocation)
TWeakObjectPtr< UPrimitiveComponent > LocalLastInteractingComponent
UPROPERTY(BlueprintReadOnly, Category = "VRButtonComponent")
void OnOverlapBegin(UPrimitiveComponent *OverlappedComp, AActor *OtherActor, UPrimitiveComponent *OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult &SweepResult)
UFUNCTION()
bool bSkipOverlapFiltering
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VRButtonComponent")
FVRButtonStartedInteractionSignature OnButtonEndInteraction
UPROPERTY(BlueprintAssignable, Category = "VRButtonComponent")
bool IsButtonInUse()
UFUNCTION(BlueprintPure, Category = "VRButtonComponent")
UVRButtonComponent(const FObjectInitializer &ObjectInitializer)
float MinTimeBetweenEngaging
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VRButtonComponent")
void ReceiveButtonBeginInteraction(AActor *InteractingActor, UPrimitiveComponent *InteractingComponent)
UFUNCTION(BlueprintImplementableEvent, meta = (DisplayName = "Button Started Interaction"))
void ReceiveButtonEndInteraction(AActor *LastInteractingActor, UPrimitiveComponent *LastInteractingComponent)
UFUNCTION(BlueprintImplementableEvent, meta = (DisplayName = "Button Ended Interaction"))
virtual void OnRegister() override
virtual void PreReplication(IRepChangedPropertyTracker &ChangedPropertyTracker) override
virtual void TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction *ThisTickFunction) override
FVector SetAxisValue(float SetValue)
bool IsValidOverlap(UPrimitiveComponent *OverlapComponent)
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "VRButtonComponent")
virtual FVector GetTargetRelativeLocation()
bool bButtonState
UPROPERTY(EditAnywhere,BlueprintReadWrite, Replicated, Category = "VRButtonComponent")