Lovense Integration
LovenseToyAnimationControlComponent.h
1 // (CVN) - Candy Valley Network GmbH
2 
3 #pragma once
4 
5 #include <CoreMinimal.h>
6 
7 // EXTERNAL INCLUDES
8 #include <Components/ActorComponent.h>
9 
10 // INTERNAL INCLUDES
11 #include "LovenseTypes.h"
12 
13 #include "LovenseToyAnimationControlComponent.generated.h"
14 
15 
16 // Example of how a FLovenseGetAnimationData event function could be implemented. This is dummy code to get the general idea across.
17 #if false
18  class Class {
19  void LovenseGetAnimationData(TArray<class UAnimSequence*>& outAnimations, TArray<float>& outTimes);
20  void CalculatePlayRate(float deltaTime, FRandomStream& random, float& playRate);
21  void Tick(float deltaTime);
22 
23  TArray<class USkeletalMeshComponent> skeletalMeshComponents;
24  TArray<class UAnimSequence*> animations;
25  float currentAnimationTime;
26  // It's important to use FRandomStream instead of the FMath functions as it is deterministic, allowing us to "look into the future".
27  FRandomStream randomStream;
28  float currentPlayRate;
29  float currentTime;
30  float currentPlayRateTarget;
31  };
32 
33  void Class::LovenseGetAnimationData(TArray<class UAnimSequence*>& outAnimations, TArray<float>& outTimes) {
34  outAnimations.Empty(this->skeletalMeshComponents.Num());
35  outTimes.Empty(50);
36 
37  for (int32 i = 0; i < this->skeletalMeshComponents.Num(); ++i) {
38  // Need one animation for every skeletal mesh component.
39  outAnimations.Add(this->animations[i]);
40  }
41 
42  // Filling outTimes is optional. If it's empty, the component will use a fixed time step of 0.1 seconds.
43 
44  // Cache any play rate values as we want to "look into the future" and not affect the current play rate.
45  FRandomStream random = this->randomStream;
46  float playRate = this->currentPlayRate;
47 
48  int32 toyDelay = FLovenseManager::Get()->GetToyDelay();
49  float toyDelaySeconds = static_cast<float>(toyDelay) / 1000.0f;
50  // Start at the current animation time + the toy delay to account for the communication delay.
51  float animationTime = this->currentAnimationTime + toyDelaySeconds;
52  float time = this->currentTime;
53  float playRateTarget = this->currentPlayRateTarget;
54 
55  // Iterate animationTime until we have 51 time values as we can only have 50 pattern values and the first time value will be swallowed.
56  while (outTimes.Num() < 51) {
57  // Add current animation time to times array.
58  outTimes.Add(animationTime);
59  // Step the animation time forwards with the cached play rate.
60  animationTime += 0.1f * playRate;
61  // Tick the cached play rate with the cached random stream.
62  this->CalculatePlayRate(0.1f, random, time, playRateTarget, playRate);
63  }
64  }
65 
66  void Class::CalculatePlayRate(float deltaTime, FRandomStream& random, float& time, float& playRateTarget, float& playRate) {
67  // This part is important; we need to make sure to not get a value from the random stream faster than the pattern interval.
68  // Otherwise we would get a different result as we'd get fewer values from the random stream when looking into the future
69  // compared to the actual play rate update, which runs every tick.
70  // Alternatively, you could update the actual play rate every >0.1 seconds instead of every tick.
71  time += deltaTime;
72  if (time > 0.1f) {
73  // This can be as simple or as complex as you want.
74  playRateTarget = random.FRand();
75  }
76 
77  playRate = FMath::FInterpTo(playRate, playRateTarget, deltaTime, 1.0f);
78  }
79 
80  void Class::Tick(float deltaTime) {
81  // Actually update the play rate.
82  this->CalculatePlayRate(deltaTime, this->randomStream, this->currentTime, this->currentPlayRateTarget, this->currentPlayRate);
83  }
84 #endif
85 
97 DECLARE_DYNAMIC_DELEGATE_TwoParams(FLovenseGetAnimationData, TArray<class UAnimSequence*>&, outAnimations, TArray<float>&, outTimes);
98 
99 
161 UCLASS(ClassGroup = "Lovense", Meta = (BlueprintSpawnableComponent))
162 class LOVENSEINTEGRATION_API ULovenseToyAnimationControlComponent : public UActorComponent {
163  GENERATED_BODY()
164 
165 public:
174  UFUNCTION(BlueprintCallable, Category = "Lovense")
175  virtual void Initialize(
176  const TArray<USkeletalMeshComponent*>& inSkeletalMeshComponents,
177  const TArray<FName>& inBoneNames,
178  const FLovenseGetAnimationData& inGetAnimationDataDelegate
179  );
180 
185  UFUNCTION(BlueprintCallable, Category = "Lovense")
186  virtual void StartBehaviour();
187 
195  UFUNCTION(BlueprintCallable, Category = "Lovense")
196  virtual void StartTransition();
197 
203  UFUNCTION(BlueprintCallable, Category = "Lovense")
204  virtual void SetEnabled(bool value);
205 
207  UFUNCTION(BlueprintPure, Category = "Lovense")
208  FORCEINLINE bool IsEnabled() { return this->bIsEnabled; }
209 
214  UFUNCTION(BlueprintCallable, Category = "Lovense")
215  virtual void OnGamePaused();
216 
221  UFUNCTION(BlueprintCallable, Category = "Lovense")
222  virtual void OnGameUnpaused();
223 
224 public:
226 
227  // UActorComponent Interface
228  virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
229  virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
230  // End UActorComponent Interface
231 
236  FORCEINLINE float GetMaxRecordedVelocityDecaySpeed() { return this->maxRecordedVelocityDecaySpeed; }
241  FORCEINLINE void SetMaxRecordedVelocityDecaySpeed(float newDecaySpeed) { this->maxRecordedVelocityDecaySpeed = newDecaySpeed; }
246  FORCEINLINE float GetMaxRecordedVelocityDecayMinimum() { return this->maxRecordedVelocityDecayMinimum; }
251  FORCEINLINE void SetMaxRecordedVelocityDecayMinimum(float newDecayMinimum) { this->maxRecordedVelocityDecayMinimum = newDecayMinimum; }
256  FORCEINLINE float GetMaxToySpeedInterpolationSpeed() { return this->maxToySpeedInterpolationSpeed; }
261  FORCEINLINE void SetMaxToySpeedInterpolationSpeed(float newInterpolationSpeed) { this->maxToySpeedInterpolationSpeed = newInterpolationSpeed; }
267  FORCEINLINE float GetMaxToySpeedTargetDuringTransition() { return this->maxToySpeedTargetDuringTransition; }
273  FORCEINLINE void SetMaxToySpeedTargetDuringTransition(float newSpeedTargetDuringTransition) { this->maxToySpeedTargetDuringTransition = newSpeedTargetDuringTransition; }
280  FORCEINLINE FVector2D GetPatternToySpeedInputRange() { return this->patternToySpeedInputRange; }
287  FORCEINLINE void SetPatternToySpeedInputRange(FVector2D newInputRange) { this->patternToySpeedInputRange = newInputRange; }
292  FORCEINLINE const TArray<USkeletalMeshComponent*>& GetSkeletalMeshComponents() { return this->skeletalMeshComponents; }
298  FORCEINLINE const TArray<FName>& GetBoneNames() { return this->boneNames; }
304  FORCEINLINE float GeMaxRecordedVelocity() { return this->maxRecordedVelocity; }
310  FORCEINLINE float GeCurrentMaxToySpeed() { return this->currentMaxToySpeed; }
316  FORCEINLINE float GeMaxToySpeedTarget() { return this->maxToySpeedTarget; }
322  FORCEINLINE bool GeRotateClockwise() { return this->bRotateClockwise; }
323 
324 protected:
329  UFUNCTION()
330  virtual void OnPatternGenerationTimerFinished();
331 
332 protected:
337  virtual void RealtimeEvaluationUpdate(float deltaTime);
343  virtual bool GeneratePattern(const TArray<class UAnimSequence*>& animations, const TArray<float>& times, FLovensePattern& outPattern);
344 
345 protected:
351  UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Lovense|Realtime Evaluation")
352  double maxAverageVelocity;
353 
358  UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Lovense|Realtime Evaluation")
359  float maxRecordedVelocityDecaySpeed;
360 
365  UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Lovense|Realtime Evaluation")
366  float maxRecordedVelocityDecayMinimum;
367 
372  UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Lovense|Realtime Evaluation")
373  float maxToySpeedInterpolationSpeed;
374 
380  UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Lovense|Realtime Evaluation", Meta = (ClampMin = "1", ClampMax = "20", UIMin = "1", UIMax = "20"))
381  float maxToySpeedTargetDuringTransition;
382 
389  UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Lovense|Pattern Generation")
390  FVector2D patternToySpeedInputRange;
391 
396  UPROPERTY(Transient, VisibleAnywhere, BlueprintReadOnly, Category = "Lovense")
397  TArray<TObjectPtr<USkeletalMeshComponent>> skeletalMeshComponents;
398 
404  UPROPERTY(Transient, VisibleAnywhere, BlueprintReadOnly, Category = "Lovense")
405  TArray<FName> boneNames;
406 
412  UPROPERTY(Transient, VisibleAnywhere, BlueprintReadOnly, Category = "Lovense|Realtime Evaluation")
413  double maxRecordedVelocity;
414 
420  UPROPERTY(Transient, VisibleAnywhere, BlueprintReadOnly, Category = "Lovense|Realtime Evaluation")
421  float currentMaxToySpeed;
422 
428  UPROPERTY(Transient, VisibleAnywhere, BlueprintReadOnly, Category = "Lovense|Realtime Evaluation")
429  float maxToySpeedTarget;
430 
436  UPROPERTY(Transient, VisibleAnywhere, BlueprintReadOnly, Category = "Lovense|Realtime Evaluation")
437  bool bRotateClockwise;
438 
439 protected:
441  bool bIsEnabled;
448  FTimerHandle patternGenerationTimerHandle;
455  FLovenseGetAnimationData getAnimationDataDelegate;
456 };
ULovenseToyAnimationControlComponent
This component calculates Lovense command speeds based on the average bone movement of N bones on N s...
Definition: LovenseToyAnimationControlComponent.h:162
ULovenseToyAnimationControlComponent::GetMaxToySpeedTargetDuringTransition
FORCEINLINE float GetMaxToySpeedTargetDuringTransition()
Get maximum toy command speed that maxToySpeedTarget will be set to during transitions (See StartTran...
Definition: LovenseToyAnimationControlComponent.h:267
ULovenseToyAnimationControlComponent::SetMaxRecordedVelocityDecayMinimum
FORCEINLINE void SetMaxRecordedVelocityDecayMinimum(float newDecayMinimum)
Naming is a bit confusing, this is the minimum value that maxRecordedVelocity can decay to....
Definition: LovenseToyAnimationControlComponent.h:251
FLovenseManager::GetToyDelay
FORCEINLINE int32 GetToyDelay()
Get the cached "ToyDelay" config value. Toy delay is in milliseconds. Value range is 0-2000ms and d...
Definition: LovenseManager.h:671
ULovenseToyAnimationControlComponent::GetSkeletalMeshComponents
const FORCEINLINE TArray< USkeletalMeshComponent * > & GetSkeletalMeshComponents()
Get the skeletal meshes that will be evaluated. All of these components have to use the same skeleton...
Definition: LovenseToyAnimationControlComponent.h:292
ULovenseToyAnimationControlComponent::SetPatternToySpeedInputRange
FORCEINLINE void SetPatternToySpeedInputRange(FVector2D newInputRange)
Set input value range for the average velocity to toy command speed conversion. E....
Definition: LovenseToyAnimationControlComponent.h:287
ULovenseToyAnimationControlComponent::GeMaxToySpeedTarget
FORCEINLINE float GeMaxToySpeedTarget()
Get the target value that currentMaxToySpeed gets interpolated to. Is usually 20,...
Definition: LovenseToyAnimationControlComponent.h:316
FLovenseManager::Get
static FLovenseManager * Get()
Get the instance of the lovense manager. Always valid.
Definition: LovenseManager.cpp:49
ULovenseToyAnimationControlComponent::GeMaxRecordedVelocity
FORCEINLINE float GeMaxRecordedVelocity()
Get the current maximum velocity that has been calculated. Used to remap the current velocity to a to...
Definition: LovenseToyAnimationControlComponent.h:304
ULovenseToyAnimationControlComponent::GeCurrentMaxToySpeed
FORCEINLINE float GeCurrentMaxToySpeed()
Get the current maximum toy command speed. Is interpolated towards maxToySpeedTarget with maxToySpe...
Definition: LovenseToyAnimationControlComponent.h:310
ULovenseToyAnimationControlComponent::GetMaxRecordedVelocityDecayMinimum
FORCEINLINE float GetMaxRecordedVelocityDecayMinimum()
Naming is a bit confusing, this is the minimum value that maxRecordedVelocity can decay to....
Definition: LovenseToyAnimationControlComponent.h:246
ULovenseToyAnimationControlComponent::SetMaxToySpeedInterpolationSpeed
FORCEINLINE void SetMaxToySpeedInterpolationSpeed(float newInterpolationSpeed)
Set interpolation speed at which currentMaxToySpeed will be interpolated towards maxToySpeedTarget....
Definition: LovenseToyAnimationControlComponent.h:261
ULovenseToyAnimationControlComponent::GetMaxToySpeedInterpolationSpeed
FORCEINLINE float GetMaxToySpeedInterpolationSpeed()
Get interpolation speed at which currentMaxToySpeed will be interpolated towards maxToySpeedTarget....
Definition: LovenseToyAnimationControlComponent.h:256
FLovensePattern
Structure holding all necessary information for a pattern command.
Definition: LovenseTypes.h:403
ULovenseToyAnimationControlComponent::GeRotateClockwise
FORCEINLINE bool GeRotateClockwise()
Whether the toys should rotate clockwise or anticlockwise. Gets toggled in StartTransition()....
Definition: LovenseToyAnimationControlComponent.h:322
ULovenseToyAnimationControlComponent::SetMaxToySpeedTargetDuringTransition
FORCEINLINE void SetMaxToySpeedTargetDuringTransition(float newSpeedTargetDuringTransition)
Set maximum toy command speed that maxToySpeedTarget will be set to during transitions (See StartTran...
Definition: LovenseToyAnimationControlComponent.h:273
ULovenseToyAnimationControlComponent::GetBoneNames
const FORCEINLINE TArray< FName > & GetBoneNames()
Get the names of the bones of the skeletal meshes that will be evaluated. This component calculates...
Definition: LovenseToyAnimationControlComponent.h:298
ULovenseToyAnimationControlComponent::GetPatternToySpeedInputRange
FORCEINLINE FVector2D GetPatternToySpeedInputRange()
Get input value range for the average velocity to toy command speed conversion. E....
Definition: LovenseToyAnimationControlComponent.h:280
ULovenseToyAnimationControlComponent::SetMaxRecordedVelocityDecaySpeed
FORCEINLINE void SetMaxRecordedVelocityDecaySpeed(float newDecaySpeed)
Set the speed (per second) at which maxRecordedVelocity will decay at. Only relevant for realtime e...
Definition: LovenseToyAnimationControlComponent.h:241