*WIP* Robot Base Class, LuckyWorldSubsystem, LuckyRobotMovementComponent

- Robot Base Class -> Handles inputs, has Mujoco settings, creates proper movement component
- LuckyWorldSubsystem -> Has Get and Ready functions for many Robot values/updates
- LuckyRobotMovementComponent -> Base component for robot movement. Can read any value or input from the owning robot. Can be reused on similar robots or custom components can be created if needed.
This commit is contained in:
Vyktori 2025-04-17 00:00:14 -04:00
parent b91d8c9412
commit b31dad8ca5
8 changed files with 757 additions and 5 deletions

View File

@ -50,14 +50,14 @@ class LUCKYMUJOCO_API AMujocoVolumeActor : public AActor
UPROPERTY(Transient, VisibleAnywhere, Category = "Mujoco | Debug") UPROPERTY(Transient, VisibleAnywhere, Category = "Mujoco | Debug")
TArray<TSoftObjectPtr<UMujocoTendonComponent>> TendonComponents; TArray<TSoftObjectPtr<UMujocoTendonComponent>> TendonComponents;
UFUNCTION(BlueprintCallable, Category = "Mujoco")
void InitializeMujoco();
template <typename ComponentType> void AssignComponentsToArray(UWorld* World, TArray<TSoftObjectPtr<ComponentType>>& ComponentArray); template <typename ComponentType> void AssignComponentsToArray(UWorld* World, TArray<TSoftObjectPtr<ComponentType>>& ComponentArray);
public: public:
AMujocoVolumeActor(); AMujocoVolumeActor();
UFUNCTION(BlueprintCallable, Category = "Mujoco")
void InitializeMujoco();
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Mujoco | Simulation", meta = (Min = 0, Max = 100, ClampMin = 0, ClampMax = 100)) UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Mujoco | Simulation", meta = (Min = 0, Max = 100, ClampMin = 0, ClampMax = 100))
int32 FrameSkip = 0; int32 FrameSkip = 0;

View File

@ -0,0 +1,30 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "Gameplay/Robot/Components/Movement/LuckyRobotMovementComponent.h"
#include "Actors/MujocoVolumeActor.h"
#include "Gameplay/Robot/LuckyRobotPawnBase.h"
ULuckyRobotMovementComponent::ULuckyRobotMovementComponent()
{
PrimaryComponentTick.bCanEverTick = true;
}
void ULuckyRobotMovementComponent::BeginPlay()
{
Super::BeginPlay();
}
void ULuckyRobotMovementComponent::InitializeMovementComponent(ALuckyRobotPawnBase* InOwningRobot)
{
if (IsValid(InOwningRobot))
{
OwningRobot = InOwningRobot;
if (GetOwningRobot())
{
MujocoVolumeActor = GetOwningRobot()->GetMujocoVolumeActor();
}
}
}

View File

@ -0,0 +1,328 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "Gameplay/Robot/LuckyRobotPawnBase.h"
#include "Actors/MujocoVolumeActor.h"
#include "Core/LuckyRobotsGameInstance.h"
#include "Gameplay/Robot/Components/Movement/LuckyRobotMovementComponent.h"
#include "Subsystems/LuckyWorldSubsystem.h"
#include "EnhancedInputComponent.h"
#include "EnhancedInputSubsystems.h"
ALuckyRobotPawnBase::ALuckyRobotPawnBase()
{
PrimaryActorTick.bCanEverTick = true;
}
void ALuckyRobotPawnBase::InitializeMujocoVolumeActor()
{
RemoveMujocoVolumeActor();
if (GetWorld() && IsValid(RobotSettings.MujocoSettings.Get()))
{
if (AMujocoVolumeActor* SpawnedVolume = GetWorld()->SpawnActorDeferred<AMujocoVolumeActor>(RobotSettings.MujocoSettings.Get(), FTransform::Identity, nullptr, nullptr, ESpawnActorCollisionHandlingMethod::AlwaysSpawn))
{
// do anything here we need to for the MujocoVolumeActor before we finalize spawning
SpawnedVolume->FinishSpawning(FTransform::Identity);
MujocoVolumeSettings = SpawnedVolume;
if (GetMujocoVolumeActor())
{
GetMujocoVolumeActor()->InitializeMujoco();
}
}
}
}
void ALuckyRobotPawnBase::InitializeMovementComponent()
{
if (!GetRobotMovementComponent() && IsValid(RobotSettings.MovementComponentClass.Get()))
{
if (UActorComponent* NewComp = AddComponentByClass(RobotSettings.MovementComponentClass.Get(), false, FTransform::Identity, false))
{
if (ULuckyRobotMovementComponent* NewMoveComp = Cast<ULuckyRobotMovementComponent>(NewComp))
{
RobotMovementComponent = NewMoveComp;
if (GetRobotMovementComponent())
{
GetRobotMovementComponent()->InitializeMovementComponent(this);
}
}
}
}
}
void ALuckyRobotPawnBase::BeginPlay()
{
Super::BeginPlay();
InitializeMujocoVolumeActor();
InitializeMovementComponent();
if (GetLuckyWorldSubsystem())
{
GetLuckyWorldSubsystem()->RegisterLuckyRobot(this);
GetLuckyWorldSubsystem()->TargetSpeedChanged.AddUniqueDynamic(this, &ALuckyRobotPawnBase::SetTargetSpeed);
}
}
void ALuckyRobotPawnBase::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
// need to check NaviPoint to see if it is paused
TaskTime += DeltaTime;
// if (HasTaskExpired())
// {
// IncrementCurrentTask();
// }
}
void ALuckyRobotPawnBase::NotifyControllerChanged()
{
Super::NotifyControllerChanged();
if (APlayerController* PlayerController = Cast<APlayerController>(Controller))
{
if (UEnhancedInputLocalPlayerSubsystem* Subsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(PlayerController->GetLocalPlayer()))
{
Subsystem->AddMappingContext(DefaultMappingContext, 0);
}
}
}
void ALuckyRobotPawnBase::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
if (!GetEnhancedInputComponent())
{
EnhancedInputComponent = Cast<UEnhancedInputComponent>(PlayerInputComponent);
}
if (GetEnhancedInputComponent())
{
EnhancedInputComponent->BindAction(MoveAction, ETriggerEvent::Started, this, &ALuckyRobotPawnBase::MoveStart);
EnhancedInputComponent->BindAction(MoveAction, ETriggerEvent::Triggered, this, &ALuckyRobotPawnBase::Move);
EnhancedInputComponent->BindAction(MoveAction, ETriggerEvent::Completed, this, &ALuckyRobotPawnBase::MoveStop);
EnhancedInputComponent->BindAction(TurnAction, ETriggerEvent::Started, this, &ALuckyRobotPawnBase::TurnStart);
EnhancedInputComponent->BindAction(TurnAction, ETriggerEvent::Triggered, this, &ALuckyRobotPawnBase::Turn);
EnhancedInputComponent->BindAction(TurnAction, ETriggerEvent::Completed, this, &ALuckyRobotPawnBase::TurnStop);
EnhancedInputComponent->BindAction(LookAction, ETriggerEvent::Triggered, this, &ALuckyRobotPawnBase::Look);
}
}
void ALuckyRobotPawnBase::MoveStart(const FInputActionValue& Value)
{
UE_LOG(LogTemp, Warning, TEXT("ALuckyRobotPawnBase :: Input :: MoveStart"));
CachedMovementInputValues.X = Value.Get<float>();
PreviousInputType = CurrentInputType;
CurrentInputType = ERobotInputType::Move;
}
void ALuckyRobotPawnBase::Move(const FInputActionValue& Value)
{
UE_LOG(LogTemp, Warning, TEXT("ALuckyRobotPawnBase :: Input :: Move (%f)"), Value.Get<float>());
CachedMovementInputValues.X = Value.Get<float>();
}
void ALuckyRobotPawnBase::MoveStop(const FInputActionValue& Value)
{
UE_LOG(LogTemp, Warning, TEXT("ALuckyRobotPawnBase :: Input :: MoveStop"));
CachedMovementInputValues.X = 0.f;
if (CurrentInputType == ERobotInputType::Move && PreviousInputType == ERobotInputType::Turn && !FMath::IsNearlyZero(CachedMovementInputValues.Y, 0.01f))
{
CurrentInputType = ERobotInputType::Turn;
}
else
{
CurrentInputType = ERobotInputType::None;
}
PreviousInputType = ERobotInputType::None;
}
void ALuckyRobotPawnBase::TurnStart(const FInputActionValue& Value)
{
UE_LOG(LogTemp, Warning, TEXT("ALuckyRobotPawnBase :: Input :: TurnStart"));
CachedMovementInputValues.Y = Value.Get<float>();
PreviousInputType = CurrentInputType;
CurrentInputType = ERobotInputType::Turn;
}
void ALuckyRobotPawnBase::Turn(const FInputActionValue& Value)
{
UE_LOG(LogTemp, Warning, TEXT("ALuckyRobotPawnBase :: Input :: Turn (%f)"), Value.Get<float>());
CachedMovementInputValues.Y = Value.Get<float>();
}
void ALuckyRobotPawnBase::TurnStop(const FInputActionValue& Value)
{
UE_LOG(LogTemp, Warning, TEXT("ALuckyRobotPawnBase :: Input :: TurnStop"));
CachedMovementInputValues.Y = 0.f;
if (CurrentInputType == ERobotInputType::Turn && PreviousInputType == ERobotInputType::Move && !FMath::IsNearlyZero(CachedMovementInputValues.X, 0.01f))
{
CurrentInputType = ERobotInputType::Move;
}
else
{
CurrentInputType = ERobotInputType::None;
}
PreviousInputType = ERobotInputType::None;
}
void ALuckyRobotPawnBase::Look(const FInputActionValue& Value)
{
UE_LOG(LogTemp, Warning, TEXT("ALuckyRobotPawnBase :: Input :: Look (%s)"), *Value.Get<FVector2D>().ToString());
}
void ALuckyRobotPawnBase::RemoveMujocoVolumeActor()
{
if (GetMujocoVolumeActor())
{
GetMujocoVolumeActor()->Destroy();
MujocoVolumeSettings.Reset();
}
}
void ALuckyRobotPawnBase::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
Super::EndPlay(EndPlayReason);
RemoveMujocoVolumeActor();
}
ULuckyWorldSubsystem* ALuckyRobotPawnBase::GetLuckyWorldSubsystem()
{
if (!LuckyWorldSubsystem.Get() && GetWorld())
{
LuckyWorldSubsystem = GetWorld()->GetSubsystem<ULuckyWorldSubsystem>();
}
return LuckyWorldSubsystem.Get();
}
int32 ALuckyRobotPawnBase::GetTaskCount()
{
if (GetLuckyRobotsGameInstance())
{
return GetLuckyRobotsGameInstance()->GetTaskNum();
}
return -1;
}
bool ALuckyRobotPawnBase::HasTaskExpired()
{
if (GetLuckyRobotsGameInstance())
{
return TaskTime >= GetFastEndTaskTime();
}
return false;
}
ULuckyRobotsGameInstance* ALuckyRobotPawnBase::GetLuckyRobotsGameInstance()
{
if (!LuckyGameInstance.Get() && GetWorld() && GetWorld()->GetGameInstance())
{
LuckyGameInstance = Cast<ULuckyRobotsGameInstance>(GetWorld()->GetGameInstance());
}
return LuckyGameInstance.Get();
}
bool ALuckyRobotPawnBase::GetInfiniteTime()
{
if (GetLuckyRobotsGameInstance())
{
return GetLuckyRobotsGameInstance()->bInfiniteTime;
}
return false;
}
float ALuckyRobotPawnBase::GetFastEndTaskTime()
{
if (GetLuckyRobotsGameInstance())
{
return GetLuckyRobotsGameInstance()->FastEndTaskTime;
}
return 0.f;
}
bool ALuckyRobotPawnBase::SetActuators(const TArray<FStretchRobotActuator>& InActuators)
{
Actuators.Empty();
Actuators = InActuators;
return !Actuators.IsEmpty();
}
// SPEED CONFIG
void ALuckyRobotPawnBase::SetTargetSpeed(const float InTargetSpeed)
{
const float OldValue = TargetSpeed;
TargetSpeed = InTargetSpeed;
Internal_TargetSpeedChanged(OldValue);
}
void ALuckyRobotPawnBase::Internal_TargetSpeedChanged(const float OldValue)
{
TargetSpeedChanged(TargetSpeed, OldValue);
}
// TORQUE LIMITER
void ALuckyRobotPawnBase::SetTorqueLimiter(const float InTorqueLimiter)
{
const float OldValue = TorqueLimiter;
TorqueLimiter = InTorqueLimiter;
Internal_TorqueLimiterChanged(OldValue);
}
void ALuckyRobotPawnBase::Internal_TorqueLimiterChanged(const float OldValue)
{
TorqueLimiterChanged(TorqueLimiter, OldValue);
}
// CURRENT TASK INDEX
void ALuckyRobotPawnBase::SetCurrentTaskIndex(const int32 InCurrentTaskIndex)
{
const int32 OldValue = CurrentTaskIndex;
CurrentTaskIndex = InCurrentTaskIndex;
Internal_CurrentTaskIndexChanged(OldValue);
}
void ALuckyRobotPawnBase::IncrementCurrentTask()
{
TaskTime = 0.f;
SetCurrentTaskIndex(GetCurrentTaskIndex() + 1);
}
void ALuckyRobotPawnBase::Internal_CurrentTaskIndexChanged(const int32 OldValue)
{
if (GetLuckyWorldSubsystem())
{
GetLuckyWorldSubsystem()->UpdateCurrentTaskIndex(CurrentTaskIndex);
}
CurrentTaskIndexChanged(CurrentTaskIndex, OldValue);
}

View File

@ -0,0 +1,75 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "Subsystems/LuckyWorldSubsystem.h"
#include "Gameplay/Robot/LuckyRobotPawnBase.h"
void ULuckyWorldSubsystem::CheckSimulationReady()
{
if (!bSimulationReady)
{
bool bReady = true;
if (!GetLuckyRobot())
{
UE_LOG(LogTemp, Log, TEXT("CheckSimulationReady -> LuckyRobot IS NOT READY"));
bReady = false;
}
// add any other false checks here if they are not ready
if (bReady)
{
bSimulationReady = true;
if (LuckyRobotSimulationReady.IsBound())
{
LuckyRobotSimulationReady.Broadcast();
}
}
}
}
void ULuckyWorldSubsystem::RegisterLuckyRobot(ALuckyRobotPawnBase* InLuckyRobot)
{
if (InLuckyRobot)
{
LuckyRobotPawn = InLuckyRobot;
if (LuckyRobotReady.IsBound())
{
LuckyRobotReady.Broadcast(GetLuckyRobot());
//LuckyRobotReady.Clear();
}
CheckSimulationReady();
}
}
void ULuckyWorldSubsystem::UpdateCurrentTaskIndex(const float InCurrentTaskIndex)
{
Robot_CurrentTaskIndex = InCurrentTaskIndex;
if (CurrentTaskIndexChanged.IsBound())
{
CurrentTaskIndexChanged.Broadcast(Robot_CurrentTaskIndex);
}
}
void ULuckyWorldSubsystem::UpdateTargetSpeed(const float InTargetSpeed)
{
Robot_TargetSpeed = InTargetSpeed;
if (TargetSpeedChanged.IsBound())
{
TargetSpeedChanged.Broadcast(Robot_TargetSpeed);
}
}
void ULuckyWorldSubsystem::UpdateTorqueLimiter(const float InTorqueLimiter)
{
Robot_TorqueLimiter = InTorqueLimiter;
if (TorqueLimiterChanged.IsBound())
{
TorqueLimiterChanged.Broadcast(Robot_TorqueLimiter);
}
}

View File

@ -0,0 +1,31 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "LuckyRobotMovementComponent.generated.h"
class AMujocoVolumeActor;
class ALuckyRobotPawnBase;
UCLASS(ClassGroup=(Custom), meta=(BlueprintSpawnableComponent), BlueprintType, Blueprintable)
class LUCKYWORLDV2_API ULuckyRobotMovementComponent : public UActorComponent
{
GENERATED_BODY()
public:
ULuckyRobotMovementComponent();
void InitializeMovementComponent(ALuckyRobotPawnBase* InOwningRobot);
ALuckyRobotPawnBase* GetOwningRobot() const { return OwningRobot.Get(); }
AMujocoVolumeActor* GetMujocoVolumeActor() const { return MujocoVolumeActor.Get(); }
protected:
virtual void BeginPlay() override;
TWeakObjectPtr<ALuckyRobotPawnBase> OwningRobot;
TWeakObjectPtr<AMujocoVolumeActor> MujocoVolumeActor;
};

View File

@ -0,0 +1,42 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "RobotSettings.generated.h"
class ULuckyRobotMovementComponent;
class AMujocoVolumeActor;
UENUM(BlueprintType)
enum class ERobotInputType : uint8
{
None UMETA(DisplayName = "None"),
Move UMETA(DisplayName = "Move"),
Turn UMETA(DisplayName = "Turn"),
Pathfinding UMETA(DisplayName = "Pathfinding")
};
UENUM(BlueprintType)
enum class ERobotInputHandlingMethod : uint8
{
None UMETA(DisplayName = "None"),
SingleInput UMETA(DisplayName = "SingleInput"),
CombinedInput UMETA(DisplayName = "CombinedInput")
};
USTRUCT(BlueprintType)
struct FRobotSettings
{
GENERATED_USTRUCT_BODY()
UPROPERTY(BlueprintReadWrite, EditDefaultsOnly, Category = "Robot Settings")
TSubclassOf<AMujocoVolumeActor> MujocoSettings;
UPROPERTY(BlueprintReadWrite, EditDefaultsOnly, Category = "Robot Settings")
TSubclassOf<ULuckyRobotMovementComponent> MovementComponentClass;
UPROPERTY(BlueprintReadWrite, EditDefaultsOnly, Category = "Robot Settings")
ERobotInputHandlingMethod InputHandlingMethod = ERobotInputHandlingMethod::CombinedInput;
};

View File

@ -0,0 +1,168 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Data/RobotSettings.h"
#include "GameFramework/Pawn.h"
#include "LuckyRobotPawnBase.generated.h"
class ULuckyWorldSubsystem;
class AMujocoVolumeActor;
struct FGoalsTaskData;
struct FStretchRobotActuator;
class ULuckyRobotsGameInstance;
class ULuckyRobotMovementComponent;
class UInputMappingContext;
class UInputAction;
struct FInputActionValue;
UCLASS()
class LUCKYWORLDV2_API ALuckyRobotPawnBase : public APawn
{
GENERATED_BODY()
public:
ALuckyRobotPawnBase();
virtual void Tick(float DeltaTime) override;
virtual void NotifyControllerChanged() override;
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
UFUNCTION(BlueprintPure, Category = "Lucky Robot Pawn")
ULuckyRobotsGameInstance* GetLuckyRobotsGameInstance();
// should this be replaced with bInfiniteTask ? and instead of setting a bool -and- loop count, we just say 0 loops is endless/infinite and the GetInfiniteTime just checks if loop count == 0
UFUNCTION(BlueprintPure, Category = "Lucky Robot Pawn")
bool GetInfiniteTime();
UFUNCTION(BlueprintPure, Category = "Lucky Robot Pawn")
float GetFastEndTaskTime();
UFUNCTION(BlueprintCallable, Category = "Lucky Robot Pawn")
bool SetActuators(const TArray<FStretchRobotActuator>& InActuators);
// SPEED CONFIG
UFUNCTION(BlueprintCallable, Category = "Lucky Robot Pawn")
void SetTargetSpeed(const float InTargetSpeed = 0.f);
UFUNCTION(BlueprintPure, Category = "Lucky Robot Pawn")
float GetTargetSpeed() const { return TargetSpeed; }
void Internal_TargetSpeedChanged(const float OldValue = 0.f);
UFUNCTION(BlueprintImplementableEvent, Category = "Lucky Robot Pawn")
void TargetSpeedChanged(const float NewValue = 0.f, const float OldValue = 0.f);
UFUNCTION(BlueprintPure, Category = "Lucky Robot Pawn")
ULuckyRobotMovementComponent* GetRobotMovementComponent() const { return RobotMovementComponent.Get(); }
// TORQUE LIMITER
UFUNCTION(BlueprintCallable, Category = "Lucky Robot Pawn")
void SetTorqueLimiter(const float InTorqueLimiter = 0.f);
UFUNCTION(BlueprintPure, Category = "Lucky Robot Pawn")
float GetTorqueLimiter() const { return TorqueLimiter; }
void Internal_TorqueLimiterChanged(const float OldValue = 0.f);
UFUNCTION(BlueprintImplementableEvent, Category = "Lucky Robot Pawn")
void TorqueLimiterChanged(const float NewValue = 0.f, const float OldValue = 0.f);
// CURRENT TASK INDEX
UFUNCTION(BlueprintCallable, Category = "Lucky Robot Pawn")
void SetCurrentTaskIndex(const int32 InCurrentTaskIndex = -1);
UFUNCTION(BlueprintPure, Category = "Lucky Robot Pawn")
int32 GetCurrentTaskIndex() const { return CurrentTaskIndex; }
UFUNCTION(BlueprintCallable, Category = "Lucky Robot Pawn")
void IncrementCurrentTask();
void Internal_CurrentTaskIndexChanged(const int32 OldValue = -1);
UFUNCTION(BlueprintImplementableEvent, Category = "Lucky Robot Pawn")
void CurrentTaskIndexChanged(const int32 NewValue = 0, const int32 OldValue = 0);
// TASK LIST
// we should have the game instance broadcast a delegate with the TaskList and we just bind to it here and update when it changes
UFUNCTION(BlueprintPure, Category = "Lucky Robot Pawn")
int32 GetTaskCount();
// TASK TIME
UFUNCTION(BlueprintPure, Category = "Lucky Robot Pawn")
bool HasTaskExpired();
// MUJOCO
UFUNCTION(BlueprintPure, Category = "Lucky Robot Pawn")
AMujocoVolumeActor* GetMujocoVolumeActor() const { return MujocoVolumeSettings.Get(); }
UFUNCTION(BlueprintCallable, Category = "Lucky Robot Pawn")
void InitializeMujocoVolumeActor();
UFUNCTION(BlueprintCallable, Category = "Lucky Robot Pawn")
void InitializeMovementComponent();
// ROBOT DATA
UPROPERTY(BlueprintReadOnly, EditDefaultsOnly, Category = "Lucky Robot Pawn")
FRobotSettings RobotSettings = FRobotSettings();
UFUNCTION(BlueprintPure, Category = "Lucky Robot Pawn")
ULuckyWorldSubsystem* GetLuckyWorldSubsystem();
// INPUTS
UFUNCTION(BlueprintPure, Category = "Lucky Robot Pawn")
UEnhancedInputComponent* GetEnhancedInputComponent() const { return EnhancedInputComponent.Get(); }
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Input, meta = (AllowPrivateAccess = "true"))
UInputMappingContext* DefaultMappingContext;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Input, meta = (AllowPrivateAccess = "true"))
UInputAction* MoveAction;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Input, meta = (AllowPrivateAccess = "true"))
UInputAction* TurnAction;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Input, meta = (AllowPrivateAccess = "true"))
UInputAction* LookAction;
void MoveStart(const FInputActionValue& Value);
void Move(const FInputActionValue& Value);
void MoveStop(const FInputActionValue& Value);
void TurnStart(const FInputActionValue& Value);
void Turn(const FInputActionValue& Value);
void TurnStop(const FInputActionValue& Value);
void Look(const FInputActionValue& Value);
protected:
virtual void BeginPlay() override;
void RemoveMujocoVolumeActor();
TWeakObjectPtr<ULuckyRobotsGameInstance> LuckyGameInstance;
TWeakObjectPtr<AMujocoVolumeActor> MujocoVolumeSettings;
TWeakObjectPtr<ULuckyRobotMovementComponent> RobotMovementComponent;
TWeakObjectPtr<ULuckyWorldSubsystem> LuckyWorldSubsystem;
TWeakObjectPtr<UEnhancedInputComponent> EnhancedInputComponent;
TArray<FStretchRobotActuator> Actuators;
float AccelerationRate = 1.f;
FVector2D CachedMovementInputValues = FVector2D::ZeroVector;
ERobotInputType PreviousInputType = ERobotInputType::None;
ERobotInputType CurrentInputType = ERobotInputType::None;
float TargetSpeed = 0.f;
float TorqueLimiter = 0.85f;
int32 CurrentTaskIndex = -1;
float TaskTime = 0.f;
};

View File

@ -0,0 +1,78 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Subsystems/WorldSubsystem.h"
#include "LuckyWorldSubsystem.generated.h"
class AMujocoVolumeActor;
class ALuckyRobotPawnBase;
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FLuckyRobotSimulationReadyDelegate);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FLuckyRobotPawnReadyDelegate, ALuckyRobotPawnBase*, LuckyRobot);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FLuckyRobotCurrentTaskChangedDelegate, const int32, NewTaskIndex);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FLuckyRobotTargetSpeedChangedDelegate, const float, NewTargetSpeed);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FLuckyRobotTorqueLimiterChangedDelegate, const float, NewTorqueLimiter);
UCLASS()
class LUCKYWORLDV2_API ULuckyWorldSubsystem : public UWorldSubsystem
{
GENERATED_BODY()
public:
// GENERAL
UPROPERTY(BlueprintAssignable, Category = "Lucky World Subsystem")
FLuckyRobotSimulationReadyDelegate LuckyRobotSimulationReady;
void CheckSimulationReady();
UFUNCTION(BlueprintCallable, Category = "Lucky World Subsystem")
bool IsSimulationReady() const { return bSimulationReady; }
// LUCKY ROBOT
void RegisterLuckyRobot(ALuckyRobotPawnBase* InLuckyRobot);
UFUNCTION(BlueprintPure, Category = "Lucky World Subsystem")
ALuckyRobotPawnBase* GetLuckyRobot() const { return LuckyRobotPawn.Get(); }
UPROPERTY(BlueprintAssignable, Category = "Lucky World Subsystem")
FLuckyRobotPawnReadyDelegate LuckyRobotReady;
// CURRENT TASK
void UpdateCurrentTaskIndex(const float InCurrentTaskIndex = -1);
UFUNCTION(BlueprintPure, Category = "Lucky World Subsystem")
float GetCurrentTaskIndex() const { return Robot_CurrentTaskIndex; }
UPROPERTY(BlueprintAssignable, Category = "Lucky World Subsystem")
FLuckyRobotCurrentTaskChangedDelegate CurrentTaskIndexChanged;
// TARGET SPEED
void UpdateTargetSpeed(const float InTargetSpeed = 0.f);
UFUNCTION(BlueprintPure, Category = "Lucky World Subsystem")
float GetTargetSpeed() const { return Robot_TargetSpeed; }
UPROPERTY(BlueprintAssignable, Category = "Lucky World Subsystem")
FLuckyRobotTargetSpeedChangedDelegate TargetSpeedChanged;
// TORQUE LIMITER
void UpdateTorqueLimiter(const float InTorqueLimiter = 0.f);
UFUNCTION(BlueprintPure, Category = "Lucky World Subsystem")
float GetTorqueLimiter() const { return Robot_TorqueLimiter; }
UPROPERTY(BlueprintAssignable, Category = "Lucky World Subsystem")
FLuckyRobotTorqueLimiterChangedDelegate TorqueLimiterChanged;
protected:
TWeakObjectPtr<ALuckyRobotPawnBase> LuckyRobotPawn;
TWeakObjectPtr<AMujocoVolumeActor> MujocoVolumeActor;
float Robot_TargetSpeed = 0.f;
float Robot_TorqueLimiter = 0.85f;
int32 Robot_CurrentTaskIndex = -1;
bool bSimulationReady = false;
};