Compare commits
6 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
cbb0bc5fc2 | ||
|
966c3ed39d | ||
|
e79570aeae | ||
|
a028ed8caf | ||
|
b0fec0cc7a | ||
|
b31dad8ca5 |
File diff suppressed because one or more lines are too long
@ -324,3 +324,4 @@ MaxAgentRadius=100.000000
|
||||
+ActiveGameNameRedirects=(OldGameName="/Script/TP_VehicleAdv",NewGameName="/Script/LuckyWorldV2")
|
||||
+ActiveGameNameRedirects=(OldGameName="Luckyrobots",NewGameName="/Script/LuckyWorldV2")
|
||||
+ActiveGameNameRedirects=(OldGameName="/Script/Luckyrobots",NewGameName="/Script/LuckyWorldV2")
|
||||
|
||||
|
Binary file not shown.
Binary file not shown.
BIN
Content/Blueprint/oldRobotsBP/BP_SoArm100.uasset
Normal file
BIN
Content/Blueprint/oldRobotsBP/BP_SoArm100.uasset
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Content/Blueprint/oldRobotsBP/BP_SoArm100/Meshes/STL/Base.uasset
Normal file
BIN
Content/Blueprint/oldRobotsBP/BP_SoArm100/Meshes/STL/Base.uasset
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Content/Developers/Wdev/Robots/NewBlueprint.uasset
Normal file
BIN
Content/Developers/Wdev/Robots/NewBlueprint.uasset
Normal file
Binary file not shown.
Binary file not shown.
BIN
Content/Map/EmptyTestLevel.umap
Normal file
BIN
Content/Map/EmptyTestLevel.umap
Normal file
Binary file not shown.
@ -180,7 +180,7 @@ void AMujocoVolumeActor::InitializeMujoco()
|
||||
OnMujocoCompileError.Broadcast(TEXT("Failed to create Mujoco data!"));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
AssignComponentsToArray(World, BodyComponents);
|
||||
AssignComponentsToArray(World, GeomComponents);
|
||||
AssignComponentsToArray(World, SiteComponents);
|
||||
|
@ -49,14 +49,14 @@ class LUCKYMUJOCO_API AMujocoVolumeActor : public AActor
|
||||
|
||||
UPROPERTY(Transient, VisibleAnywhere, Category = "Mujoco | Debug")
|
||||
TArray<TSoftObjectPtr<UMujocoTendonComponent>> TendonComponents;
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "Mujoco")
|
||||
void InitializeMujoco();
|
||||
|
||||
|
||||
template <typename ComponentType> void AssignComponentsToArray(UWorld* World, TArray<TSoftObjectPtr<ComponentType>>& ComponentArray);
|
||||
|
||||
public:
|
||||
AMujocoVolumeActor();
|
||||
AMujocoVolumeActor();
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "Mujoco")
|
||||
void InitializeMujoco();
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Mujoco | Simulation", meta = (Min = 0, Max = 100, ClampMin = 0, ClampMax = 100))
|
||||
int32 FrameSkip = 0;
|
||||
@ -117,4 +117,4 @@ protected:
|
||||
|
||||
virtual void BeginPlay() override;
|
||||
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
|
||||
};
|
||||
};
|
@ -0,0 +1,132 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
|
||||
#include "Gameplay/Robot/Components/Movement/LRMC_Stretch.h"
|
||||
#include "Actors/MujocoVolumeActor.h"
|
||||
#include "Gameplay/Robot/LuckyRobotPawnBase.h"
|
||||
//#include "Kismet/KismetMathLibrary.h"
|
||||
|
||||
|
||||
void ULRMC_Stretch::PerformMovement(float DeltaTime, const ERobotInputHandlingMethod InputHandlingMethod, const ERobotInputType InputType, const FVector2D& InputValues)
|
||||
{
|
||||
Super::PerformMovement(DeltaTime, InputHandlingMethod, InputType, InputValues);
|
||||
|
||||
// we can not do this because the rear actuator is not being used, so Turn would always override Move every frame with a value of 0.f
|
||||
//Move(InputValues.X);
|
||||
//Turn(InputValues.Y * TurnMod);
|
||||
|
||||
switch (InputType) {
|
||||
case ERobotInputType::None:
|
||||
switch (PreviousInputType)
|
||||
{
|
||||
case ERobotInputType::None:
|
||||
StopMovement();
|
||||
break;
|
||||
case ERobotInputType::Move:
|
||||
if (FMath::IsNearlyZero(InputValues.X))
|
||||
{
|
||||
PreviousInputType = ERobotInputType::None;
|
||||
StopMovement();
|
||||
}
|
||||
else
|
||||
{
|
||||
PreviousInputType = ERobotInputType::Move;
|
||||
Move(DeltaTime, InputValues);
|
||||
}
|
||||
break;
|
||||
case ERobotInputType::Turn:
|
||||
if (FMath::IsNearlyZero(InputValues.Y))
|
||||
{
|
||||
PreviousInputType = ERobotInputType::None;
|
||||
StopMovement();
|
||||
}
|
||||
else
|
||||
{
|
||||
PreviousInputType = ERobotInputType::Turn;
|
||||
Turn(DeltaTime, InputValues.Y);
|
||||
}
|
||||
break;
|
||||
case ERobotInputType::Pathfinding:
|
||||
if (FMath::IsNearlyZero(InputValues.X))
|
||||
{
|
||||
PreviousInputType = ERobotInputType::None;
|
||||
}
|
||||
else
|
||||
{
|
||||
PreviousInputType = ERobotInputType::Move;
|
||||
Move(DeltaTime, InputValues);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case ERobotInputType::Move:
|
||||
{
|
||||
PreviousInputType = ERobotInputType::Move;
|
||||
Move(DeltaTime, InputValues);
|
||||
}
|
||||
break;
|
||||
case ERobotInputType::Turn:
|
||||
{
|
||||
PreviousInputType = ERobotInputType::Turn;
|
||||
//Turn(DeltaTime, InputValues.Y);
|
||||
Move(DeltaTime, InputValues);
|
||||
}
|
||||
break;
|
||||
case ERobotInputType::Pathfinding:
|
||||
switch (PathfindingInputType) {
|
||||
case ERobotInputType::None:
|
||||
break;
|
||||
case ERobotInputType::Move:
|
||||
PreviousInputType = ERobotInputType::Move;
|
||||
Move(DeltaTime, InputValues);
|
||||
break;
|
||||
case ERobotInputType::Turn:
|
||||
PreviousInputType = ERobotInputType::Turn;
|
||||
Turn(DeltaTime, InputValues.Y);
|
||||
break;
|
||||
case ERobotInputType::Pathfinding:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ULRMC_Stretch::Move(const float DeltaTime, const FVector2D& InputValues) const
|
||||
{
|
||||
if (GetOwningRobot() && GetMujocoVolumeActor())
|
||||
{
|
||||
const FVector2D InterpolatedInputs = FMath::Vector2DInterpTo(PreviousSpeedValues, InputValues, DeltaTime, 3.f);
|
||||
float Input_0 = InterpolatedInputs.X;
|
||||
float Input_1 = InterpolatedInputs.X;
|
||||
|
||||
const float TargetSpeed = GetTargetSpeed();
|
||||
const float TurnMod = GetTurnModifier() * IsPathfinding() ? 2.f : 1.f;
|
||||
|
||||
Input_0 -= InterpolatedInputs.Y * TargetSpeed * TurnMod;
|
||||
Input_1 += InterpolatedInputs.Y * TargetSpeed * TurnMod;
|
||||
|
||||
Input_0 = FMath::Min<float>(Input_0, TargetSpeed) * 0.5f;
|
||||
Input_1 = FMath::Min<float>(Input_1, TargetSpeed) * 0.5f;
|
||||
|
||||
GetMujocoVolumeActor()->SetActuatorValueByIndex(0, Input_0);
|
||||
GetMujocoVolumeActor()->SetActuatorValueByIndex(1, Input_1);
|
||||
}
|
||||
}
|
||||
|
||||
void ULRMC_Stretch::Turn(const float DeltaTime, const float InValue) const
|
||||
{
|
||||
if (GetMujocoVolumeActor())
|
||||
{
|
||||
const float TurnMod = GetOwningRobot() ? GetOwningRobot()->GetTurnModifier() : 1.f;
|
||||
GetMujocoVolumeActor()->SetActuatorValueByIndex(0, InValue * -TurnMod);
|
||||
GetMujocoVolumeActor()->SetActuatorValueByIndex(1, InValue * TurnMod);
|
||||
}
|
||||
}
|
||||
|
||||
void ULRMC_Stretch::StopMovement()
|
||||
{
|
||||
if (GetMujocoVolumeActor())
|
||||
{
|
||||
GetMujocoVolumeActor()->SetActuatorValueByIndex(0, 0.f);
|
||||
GetMujocoVolumeActor()->SetActuatorValueByIndex(1, 0.f);
|
||||
}
|
||||
}
|
@ -0,0 +1,333 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
|
||||
#include "Gameplay/Robot/Components/Movement/LuckyRobotMovementComponent.h"
|
||||
#include "Actors/MujocoVolumeActor.h"
|
||||
#include "Components/SplineComponent.h"
|
||||
#include "Gameplay/Robot/LuckyRobotPawnBase.h"
|
||||
#include "Kismet/KismetMathLibrary.h"
|
||||
|
||||
|
||||
ULuckyRobotMovementComponent::ULuckyRobotMovementComponent()
|
||||
{
|
||||
PrimaryComponentTick.bCanEverTick = true;
|
||||
PrimaryComponentTick.bStartWithTickEnabled = false;
|
||||
}
|
||||
|
||||
void ULuckyRobotMovementComponent::TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
|
||||
{
|
||||
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
|
||||
|
||||
if (GetOwningRobot())
|
||||
{
|
||||
const FVector CurrentLocation = GetRobotLocation();
|
||||
CurrentRobotSpeed = UKismetMathLibrary::SafeDivide(FVector::Distance(CurrentLocation, PreviousLocation), DeltaTime);
|
||||
|
||||
if (IsPathfinding())
|
||||
{
|
||||
HandlePathfindingInputs(DeltaTime);
|
||||
}
|
||||
|
||||
InterpolateSpeedValues(DeltaTime, GetOwningRobot()->GetAccelerationRate(), GetOwningRobot()->GetDecelerationRate());
|
||||
PerformMovement(DeltaTime, RobotSettings.InputHandlingMethod, GetOwningRobot()->GetCurrentInputType(), CurrentSpeedValues);
|
||||
|
||||
PreviousLocation = CurrentLocation;
|
||||
PreviousSpeedValues = CurrentSpeedValues;
|
||||
|
||||
UE_LOG(LogTemp, Warning, TEXT("CurrentRobotSpeed (%f)"), CurrentRobotSpeed);
|
||||
}
|
||||
}
|
||||
|
||||
void ULuckyRobotMovementComponent::BeginPlay()
|
||||
{
|
||||
Super::BeginPlay();
|
||||
}
|
||||
|
||||
void ULuckyRobotMovementComponent::InitializeMovementComponent(ALuckyRobotPawnBase* InOwningRobot)
|
||||
{
|
||||
if (IsValid(InOwningRobot))
|
||||
{
|
||||
OwningRobot = InOwningRobot;
|
||||
|
||||
if (GetOwningRobot())
|
||||
{
|
||||
RobotSettings = GetOwningRobot()->RobotSettings;
|
||||
MujocoVolumeActor = GetOwningRobot()->GetMujocoVolumeActor();
|
||||
PreviousLocation = GetRobotLocation();
|
||||
}
|
||||
|
||||
SetComponentTickEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
FTransform ULuckyRobotMovementComponent::GetRobotTransform() const
|
||||
{
|
||||
if (GetOwningRobot())
|
||||
{
|
||||
return GetOwningRobot()->GetTransform();
|
||||
}
|
||||
|
||||
return FTransform::Identity;
|
||||
}
|
||||
|
||||
FVector ULuckyRobotMovementComponent::GetRobotLocation() const
|
||||
{
|
||||
if (GetOwningRobot())
|
||||
{
|
||||
return GetOwningRobot()->GetActorLocation();
|
||||
}
|
||||
|
||||
return FVector::ZeroVector;
|
||||
}
|
||||
|
||||
FVector ULuckyRobotMovementComponent::GetRobotForwardVector() const
|
||||
{
|
||||
if (GetOwningRobot())
|
||||
{
|
||||
return GetOwningRobot()->GetActorForwardVector();
|
||||
}
|
||||
|
||||
return FVector::ZeroVector;
|
||||
}
|
||||
|
||||
FVector ULuckyRobotMovementComponent::GetRobotRightVector() const
|
||||
{
|
||||
if (GetOwningRobot())
|
||||
{
|
||||
return GetOwningRobot()->GetActorRightVector();
|
||||
}
|
||||
|
||||
return FVector::ZeroVector;
|
||||
}
|
||||
|
||||
FRobotSplinePath ULuckyRobotMovementComponent::GetNavPath() const
|
||||
{
|
||||
if (GetOwningRobot())
|
||||
{
|
||||
return GetOwningRobot()->GetCurrentNavPath();
|
||||
}
|
||||
|
||||
return FRobotSplinePath();
|
||||
}
|
||||
|
||||
bool ULuckyRobotMovementComponent::IsPathfinding() const
|
||||
{
|
||||
if (GetOwningRobot())
|
||||
{
|
||||
return GetOwningRobot()->IsPathfinding();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void ULuckyRobotMovementComponent::PerformMovement(float DeltaTime, const ERobotInputHandlingMethod InputHandlingMethod, const ERobotInputType InputType, const FVector2D& SpeedValues)
|
||||
{
|
||||
//UE_LOG(LogTemp, Warning, TEXT("ULuckyRobotMovementComponent::PerformMovement IS NOT IMPLEMENTED"));
|
||||
//UE_LOG(LogTemp, Warning, TEXT("ULuckyRobotMovementComponent::PerformMovement [ DeltaTime (%f) :: InputHandlingMethod (%s) :: InputType (%s) :: InputValues (%s) ]"), DeltaTime, *UEnum::GetValueAsString(InputHandlingMethod), *UEnum::GetValueAsString(InputType), *SpeedValues.ToString());
|
||||
}
|
||||
|
||||
void ULuckyRobotMovementComponent::InterpolateSpeedValues(const float DeltaTime, const float Acceleration, const float Deceleration)
|
||||
{
|
||||
if (GetOwningRobot())
|
||||
{
|
||||
FVector2D TargetSpeedValues = GetOwningRobot()->GetMovementInputValues() * GetOwningRobot()->GetTargetSpeed();
|
||||
|
||||
const FVector Current = FVector(CurrentSpeedValues.X, CurrentSpeedValues.Y, 0.f);
|
||||
const FVector RawTarget = FVector(TargetSpeedValues.X, TargetSpeedValues.Y, 0.f);
|
||||
FVector Target = IsPathfinding() ? RawTarget.GetClampedToMaxSize(PathfindingTargetSpeed) : RawTarget;
|
||||
UE_LOG(LogTemp, Warning, TEXT("PathfindingTargetSpeed (%f)"), PathfindingTargetSpeed);
|
||||
|
||||
if (RobotSettings.InputHandlingMethod == ERobotInputHandlingMethod::SingleInput)
|
||||
{
|
||||
switch (GetOwningRobot()->GetCurrentInputType()) {
|
||||
case ERobotInputType::None:
|
||||
break;
|
||||
case ERobotInputType::Move:
|
||||
Target.Y = 0.f;
|
||||
break;
|
||||
case ERobotInputType::Turn:
|
||||
Target.X = 0.f;
|
||||
break;
|
||||
case ERobotInputType::Pathfinding:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const bool bMovement = !FMath::IsNearlyZero(Target.X, 0.01f);
|
||||
const bool bTurning = !FMath::IsNearlyZero(Target.Y, 0.01f);
|
||||
|
||||
const float MoveRate = UKismetMathLibrary::FInterpTo(Current.X, Target.X, DeltaTime, bMovement ? Acceleration : Deceleration);
|
||||
const float TurnRate = UKismetMathLibrary::FInterpTo(Current.Y, Target.Y, DeltaTime, bTurning ? Acceleration : Deceleration);
|
||||
|
||||
CurrentSpeedValues = FVector2D(MoveRate, TurnRate);
|
||||
|
||||
UE_LOG(LogTemp, Warning, TEXT("ULuckyRobotMovementComponent::InterpolatedSpeedValues (%s)"), *CurrentSpeedValues.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
void ULuckyRobotMovementComponent::HandlePathfindingInputs(const float DeltaTime)
|
||||
{
|
||||
if (GetOwningRobot())
|
||||
{
|
||||
if (USplineComponent* SplineComp = GetNavPath().GetSplinePath())
|
||||
{
|
||||
constexpr float SplineDistanceTolerance = 15.f;
|
||||
constexpr float SplineDirectionTolerance = 0.95f;
|
||||
|
||||
const bool bSingleInput = GetOwningRobot()->RobotSettings.InputHandlingMethod == ERobotInputHandlingMethod::SingleInput;
|
||||
const FTransform CurrentTransform = GetOwningRobot()->GetTransform();
|
||||
const float SplineDistance = SplineComp->GetDistanceAlongSplineAtLocation(CurrentTransform.GetLocation(), ESplineCoordinateSpace::World);
|
||||
const FVector SplineLocation = SplineComp->GetWorldLocationAtDistanceAlongSpline(SplineDistance);
|
||||
const float DistanceToSpline = FVector::Distance(CurrentTransform.GetLocation(), SplineLocation);
|
||||
PathfindingTargetLocation = bSingleInput ? GetSplineTargetPointLocation(SplineDistance) : GetSplineTargetLocation(SplineDistance);
|
||||
PathfindingDestination = GetOwningRobot()->GetPathfindingDestination();
|
||||
DrawDebugLine(GetWorld(), PathfindingTargetLocation, PathfindingTargetLocation + FVector(0.f, 0.f, 100.f), bSingleInput ? FColor::Purple : FColor::Yellow, false, 0.02f, 0, 3.f);
|
||||
DrawDebugLine(GetWorld(), CurrentTransform.GetLocation(), CurrentTransform.GetLocation() + GetRobotForwardVector() * 100.f, FColor::Green, false, 0.02f, 0, 3.f);
|
||||
DrawDebugLine(GetWorld(), CurrentTransform.GetLocation(), CurrentTransform.GetLocation() + GetRobotForwardVector() * -100.f, FColor::Blue, false, 0.02f, 0, 3.f);
|
||||
|
||||
if (FVector::Distance(CurrentTransform.GetLocation(), PathfindingDestination) <= PathfindingDestinationTolerance)
|
||||
{
|
||||
GetOwningRobot()->PathfindingComplete(true);
|
||||
GetOwningRobot()->SetPathfindingInputValues();
|
||||
return;
|
||||
}
|
||||
|
||||
PathfindingTargetSpeed = GetSplineSpeed(SplineDistance);
|
||||
|
||||
if (DistanceToSpline > SplineDistanceTolerance)
|
||||
{
|
||||
if (bSingleInput)
|
||||
{
|
||||
const FVector DirectionToSpline = (SplineLocation - CurrentTransform.GetLocation()).GetSafeNormal();
|
||||
const float DirectionDot = FVector::DotProduct(GetRobotForwardVector(), DirectionToSpline);
|
||||
if (DirectionDot >= SplineDirectionTolerance)
|
||||
{
|
||||
GetOwningRobot()->SetPathfindingInputValues(FVector2D(1.f, 0.f));
|
||||
PathfindingInputType = ERobotInputType::Move;
|
||||
}
|
||||
else
|
||||
{
|
||||
const bool bTurnRight = FVector::DotProduct(GetRobotRightVector(), DirectionToSpline) >= 0.f;
|
||||
const float DirectionDiscrepancy = (2.f - DirectionDot + 1.f) * bTurnRight ? -1.f : 1.f;
|
||||
const float TurnRate = UKismetMathLibrary::FInterpTo(1.f, DirectionDiscrepancy, DeltaTime, 1.f);
|
||||
GetOwningRobot()->SetPathfindingInputValues(FVector2D(0.f, TurnRate));
|
||||
PathfindingInputType = ERobotInputType::Turn;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const FVector DirectionToPath = (PathfindingTargetLocation - CurrentTransform.GetLocation()).GetSafeNormal();
|
||||
const float DirectionDot = FVector::DotProduct(GetRobotForwardVector(), DirectionToPath);
|
||||
UE_LOG(LogTemp, Warning, TEXT("DirectionDot :: %f"), DirectionDot);
|
||||
const float TurnRate = FVector::DotProduct(GetRobotRightVector(), DirectionToPath) >= 0.f ? -1.f : 1.f;
|
||||
if (DirectionDot >= SplineDirectionTolerance)
|
||||
{
|
||||
const float AdjustedTurnRate = TurnRate * (1.f - DirectionDot);
|
||||
GetOwningRobot()->SetPathfindingInputValues(FVector2D(1.f, AdjustedTurnRate));
|
||||
PathfindingInputType = ERobotInputType::Move;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (bSingleInput)
|
||||
{
|
||||
GetOwningRobot()->SetPathfindingInputValues(FVector2D(0.f, TurnRate));
|
||||
PathfindingInputType = ERobotInputType::Turn;
|
||||
}
|
||||
else
|
||||
{
|
||||
const float AdjustedTurnRate = TurnRate * (1.f - DirectionDot);
|
||||
GetOwningRobot()->SetPathfindingInputValues(FVector2D(GetOwningRobot()->GetMovementInputValues().X, AdjustedTurnRate));
|
||||
PathfindingInputType = ERobotInputType::Move;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FVector ULuckyRobotMovementComponent::GetSplineTargetLocation(const float CurrentDistance) const
|
||||
{
|
||||
if (GetNavPath().GetSplinePath())
|
||||
{
|
||||
constexpr float ForwardOffset = 10.f;
|
||||
const float ForwardPathCheck = FMath::Clamp<float>(GetTargetSpeed(), 15.f, 50.f) + ForwardOffset;
|
||||
const float SplineCheckDistance = CurrentDistance + ForwardPathCheck;
|
||||
if (SplineCheckDistance >= GetNavPath().GetSplinePath()->GetSplineLength())
|
||||
{
|
||||
return PathfindingDestination;
|
||||
}
|
||||
|
||||
return GetNavPath().GetSplinePath()->GetWorldLocationAtDistanceAlongSpline(CurrentDistance + ForwardPathCheck);
|
||||
}
|
||||
|
||||
return GetRobotLocation();
|
||||
}
|
||||
|
||||
FVector ULuckyRobotMovementComponent::GetSplineTargetPointLocation(const float CurrentDistance) const
|
||||
{
|
||||
if (GetNavPath().GetSplinePath())
|
||||
{
|
||||
const int32 SplinePoints = GetNavPath().GetSplinePath()->GetNumberOfSplinePoints();
|
||||
float NextSplinePointDistance = GetNavPath().GetSplinePath()->GetSplineLength();
|
||||
int32 NextSplinePointIndex = 0;
|
||||
for (int32 x = 0; x < SplinePoints; x++)
|
||||
{
|
||||
const float PointDistance = GetNavPath().GetSplinePath()->GetDistanceAlongSplineAtSplinePoint(x);
|
||||
if (PointDistance > CurrentDistance && PointDistance < NextSplinePointDistance)
|
||||
{
|
||||
NextSplinePointDistance = PointDistance;
|
||||
NextSplinePointIndex = x;
|
||||
}
|
||||
}
|
||||
|
||||
return GetNavPath().GetSplinePath()->GetWorldLocationAtSplinePoint(NextSplinePointIndex);
|
||||
}
|
||||
|
||||
return GetRobotLocation();
|
||||
}
|
||||
|
||||
float ULuckyRobotMovementComponent::GetSplineSpeed(const float CurrentDistance) const
|
||||
{
|
||||
if (GetOwningRobot())
|
||||
{
|
||||
return GetOwningRobot()->GetCurrentNavPath().SplinePathSpeedModifier.EditorCurveData.Eval(CurrentDistance);
|
||||
}
|
||||
|
||||
return 5.f;
|
||||
}
|
||||
|
||||
float ULuckyRobotMovementComponent::GetSpeedLimit() const
|
||||
{
|
||||
if (GetOwningRobot())
|
||||
{
|
||||
return GetOwningRobot()->RobotSettings.SpeedLimit;
|
||||
}
|
||||
|
||||
return 5.f;
|
||||
}
|
||||
|
||||
void ULuckyRobotMovementComponent::StopMovement()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
float ULuckyRobotMovementComponent::GetTargetSpeed() const
|
||||
{
|
||||
return IsPathfinding() ? PathfindingTargetSpeed : GetSpeedLimit();
|
||||
}
|
||||
|
||||
float ULuckyRobotMovementComponent::GetTargetSpeedMod() const
|
||||
{
|
||||
return UKismetMathLibrary::SafeDivide(GetTargetSpeed(), CurrentRobotSpeed);
|
||||
}
|
||||
|
||||
float ULuckyRobotMovementComponent::GetTurnModifier() const
|
||||
{
|
||||
if (GetOwningRobot())
|
||||
{
|
||||
return GetOwningRobot()->GetTurnModifier();
|
||||
}
|
||||
|
||||
return 1.f;
|
||||
}
|
@ -0,0 +1,196 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
|
||||
#include "Gameplay/Robot/Data/RobotSettings.h"
|
||||
#include "Components/SplineComponent.h"
|
||||
#include "Gameplay/Robot/LuckyRobotPawnBase.h"
|
||||
#include "Kismet/KismetMathLibrary.h"
|
||||
|
||||
void FRobotSplinePath::GenerateSplinePath(ALuckyRobotPawnBase* InRobot, const FRobotNavPath& InNavPath)
|
||||
{
|
||||
if (IsValid(InRobot) && !InNavPath.NavPoints.IsEmpty())
|
||||
{
|
||||
Robot = InRobot;
|
||||
NavPath = InNavPath;
|
||||
|
||||
if (GetRobot())
|
||||
{
|
||||
USplineComponent* OldSplinePath = GetSplinePath();
|
||||
|
||||
if (UActorComponent* NewComp = GetRobot()->AddComponentByClass(USplineComponent::StaticClass(), false, FTransform::Identity, false))
|
||||
{
|
||||
if (USplineComponent* NewSplineComp = Cast<USplineComponent>(NewComp))
|
||||
{
|
||||
NewSplineComp->ClearSplinePoints();
|
||||
NewSplineComp->SetAbsolute(true, true, true);
|
||||
int32 PointIndex = 0;
|
||||
for (auto const& NavPoint : NavPath.NavPoints)
|
||||
{
|
||||
NewSplineComp->AddSplinePointAtIndex(NavPoint.Location, PointIndex, ESplineCoordinateSpace::World, false);
|
||||
PointIndex++;
|
||||
}
|
||||
|
||||
NewSplineComp->UpdateSpline();
|
||||
SplinePath = NewSplineComp;
|
||||
RegenerateSplinePathValues();
|
||||
|
||||
// begin debug
|
||||
if (GetSplinePath())
|
||||
{
|
||||
GetSplinePath()->SetVisibility(true);
|
||||
GetSplinePath()->SetHiddenInGame(false);
|
||||
}
|
||||
// end debug
|
||||
}
|
||||
}
|
||||
|
||||
if (IsValid(OldSplinePath))
|
||||
{
|
||||
OldSplinePath->DestroyComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FRobotSplinePath::RegenerateSplinePathValues()
|
||||
{
|
||||
if (GetRobot() && GetSplinePath())
|
||||
{
|
||||
constexpr float SplinePredictionTime = 1.f;
|
||||
constexpr float SplinePredictionDistanceMin = 64.f;
|
||||
const float SpeedLimit = GetRobot()->RobotSettings.SpeedLimit;
|
||||
const float TurnSpeedLimit = GetRobot()->RobotSettings.TurnSpeedLimit;
|
||||
const float TurnSpeedMod = UKismetMathLibrary::SafeDivide(TurnSpeedLimit, SpeedLimit);
|
||||
const float TargetSpeed = FMath::Min<float>(GetRobot()->GetTargetSpeed(), SpeedLimit);
|
||||
const float SplinePredictionDistance = FMath::Max<float>(SplinePredictionTime * TargetSpeed, SplinePredictionDistanceMin);
|
||||
constexpr float TangentClamp = 128.f;
|
||||
const int32 SplinePoints = GetSplinePath()->GetNumberOfSplinePoints();
|
||||
|
||||
const bool bSingleInput = GetRobot()->RobotSettings.InputHandlingMethod == ERobotInputHandlingMethod::SingleInput;
|
||||
|
||||
if (bSingleInput)
|
||||
{
|
||||
for (int32 x = 0; x < SplinePoints; x++)
|
||||
{
|
||||
GetSplinePath()->SetTangentAtSplinePoint(x, FVector::ZeroVector, ESplineCoordinateSpace::Local, false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int32 x = 0; x < SplinePoints; x++)
|
||||
{
|
||||
if (x < SplinePoints)
|
||||
{
|
||||
GetSplinePath()->SetSplinePointType(x, ESplinePointType::CurveCustomTangent, false);
|
||||
|
||||
const FVector PointLoc1 = GetSplinePath()->GetSplinePointAt(x - 1, ESplineCoordinateSpace::World).Position;
|
||||
const FVector PointLoc2 = GetSplinePath()->GetSplinePointAt(x, ESplineCoordinateSpace::World).Position;
|
||||
const FVector PointLoc3 = GetSplinePath()->GetSplinePointAt(x + 1, ESplineCoordinateSpace::World).Position;
|
||||
const float Distance1 = FVector::Dist(PointLoc1, PointLoc2);
|
||||
const float Distance2 = FVector::Dist(PointLoc2, PointLoc3);
|
||||
|
||||
constexpr float PointDistanceMod = 0.33f;
|
||||
const float TangentMin = FMath::Min<float>(SplinePredictionDistance * 10.f, TangentClamp);
|
||||
const FVector ArriveTangent = (PointLoc3 - PointLoc1).GetSafeNormal() * FMath::Min<float>(Distance1 * PointDistanceMod, TangentMin);
|
||||
const FVector LeaveTangent = (PointLoc3 - PointLoc1).GetSafeNormal() * FMath::Min<float>(Distance2 * PointDistanceMod, TangentMin);
|
||||
|
||||
UE_LOG(LogTemp, Warning, TEXT("RegenerateSplinePathValues ArriveTangent (%s)"), *ArriveTangent.ToString());
|
||||
UE_LOG(LogTemp, Warning, TEXT("RegenerateSplinePathValues LeaveTangent (%s)"), *LeaveTangent.ToString());
|
||||
|
||||
GetSplinePath()->SetTangentsAtSplinePoint(x, ArriveTangent, LeaveTangent, ESplineCoordinateSpace::World, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GetSplinePath()->UpdateSpline();
|
||||
const float SplineLength = GetSplinePath()->GetSplineLength();
|
||||
SplinePathSpeedModifier.EditorCurveData.Reset();
|
||||
constexpr float MinSpeedMod = 0.4f;
|
||||
constexpr float SplinePrecision = 10.f;
|
||||
|
||||
if (bSingleInput)
|
||||
{
|
||||
const float SectionSpeedClamp = FMath::Min<float>(SpeedLimit * MinSpeedMod, TargetSpeed);
|
||||
const float DecelerationStep = SplinePredictionDistance + SplinePrecision;
|
||||
SplinePathSpeedModifier.EditorCurveData.AddKey(0.f, SectionSpeedClamp);
|
||||
SplinePathSpeedModifier.EditorCurveData.AddKey(SplineLength, TargetSpeed * MinSpeedMod);
|
||||
|
||||
const float FirstSectionEnd = GetSplinePath()->GetDistanceAlongSplineAtSplinePoint(1);
|
||||
if (FirstSectionEnd >= DecelerationStep)
|
||||
{
|
||||
SplinePathSpeedModifier.EditorCurveData.AddKey(SplinePrecision, TargetSpeed);
|
||||
}
|
||||
|
||||
for (int32 y = 1; y < SplinePoints; y++)
|
||||
{
|
||||
const float SectionStart = GetSplinePath()->GetDistanceAlongSplineAtSplinePoint(y - 1);
|
||||
const float SectionEnd = GetSplinePath()->GetDistanceAlongSplineAtSplinePoint(y);
|
||||
const float SectionDistance = SectionEnd - SectionStart;
|
||||
|
||||
if (SectionDistance >= DecelerationStep)
|
||||
{
|
||||
SplinePathSpeedModifier.EditorCurveData.AddKey(SectionEnd - SplinePredictionDistance, SectionSpeedClamp);
|
||||
SplinePathSpeedModifier.EditorCurveData.AddKey(SectionEnd - DecelerationStep, TargetSpeed);
|
||||
}
|
||||
else
|
||||
{
|
||||
SplinePathSpeedModifier.EditorCurveData.AddKey(SectionStart, SectionSpeedClamp);
|
||||
}
|
||||
|
||||
SplinePathSpeedModifier.EditorCurveData.AddKey(SectionEnd, SectionSpeedClamp);
|
||||
|
||||
if (y < SplinePoints)
|
||||
{
|
||||
const float NextSectionEnd = GetSplinePath()->GetDistanceAlongSplineAtSplinePoint(y + 1);
|
||||
const float NextSectionDistance = NextSectionEnd - SectionEnd;
|
||||
|
||||
if (NextSectionDistance >= DecelerationStep)
|
||||
{
|
||||
SplinePathSpeedModifier.EditorCurveData.AddKey(SectionEnd + SplinePrecision, TargetSpeed);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const int32 SplineIntervals = UKismetMathLibrary::SafeDivide(SplineLength, SplinePrecision);
|
||||
for (int32 z = SplineIntervals; z >= 0; z--)
|
||||
{
|
||||
if (z == 0)
|
||||
{
|
||||
SplinePathSpeedModifier.EditorCurveData.AddKey(0.f, TargetSpeed * MinSpeedMod);
|
||||
}
|
||||
else if (z == SplineIntervals)
|
||||
{
|
||||
SplinePathSpeedModifier.EditorCurveData.AddKey(SplineLength, TargetSpeed * MinSpeedMod);
|
||||
}
|
||||
else
|
||||
{
|
||||
constexpr float MaxSpeedMod = 1.f;
|
||||
const float SplineDistance = z * SplinePrecision;
|
||||
const float DistanceToPathEnd = SplineLength - SplineDistance;
|
||||
const float PathEndMod = DistanceToPathEnd <= SplinePredictionDistance ? FMath::Max<float>(UKismetMathLibrary::SafeDivide(DistanceToPathEnd, SplinePredictionDistance), 0.f) : 1.f;
|
||||
const FVector IntervalTangent = GetSplinePath()->GetTangentAtDistanceAlongSpline(SplineDistance, ESplineCoordinateSpace::Local);
|
||||
const float IntervalCurve = FMath::Min<float>(TangentClamp, IntervalTangent.Length());
|
||||
const float IntervalAlpha = FMath::Max<float>(1.f - UKismetMathLibrary::SafeDivide(IntervalCurve, TangentClamp), 0.f);
|
||||
const float SpeedMod = (MaxSpeedMod - IntervalAlpha) * PathEndMod;
|
||||
const float ClampedSpeed = FMath::Max<float>(SpeedLimit * SpeedMod, SpeedLimit * TurnSpeedMod);
|
||||
UE_LOG(LogTemp, Warning, TEXT("SpeedMod :: (%f - %f) * %f = %f"), MaxSpeedMod, IntervalAlpha, PathEndMod, SpeedMod);
|
||||
SplinePathSpeedModifier.EditorCurveData.AddKey(SplineDistance, ClampedSpeed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PathfindingDestination = GetSplinePath()->GetWorldLocationAtDistanceAlongSpline(SplineLength);
|
||||
|
||||
// begin debug
|
||||
|
||||
const int32 SplineIntervals = UKismetMathLibrary::SafeDivide(SplineLength, SplinePrecision);
|
||||
for (int32 z = SplineIntervals; z >= 0; z--)
|
||||
{
|
||||
UE_LOG(LogTemp, Warning, TEXT("SpeedCurveValue [%f :: %f]"), z * SplinePrecision, SplinePathSpeedModifier.EditorCurveData.Eval(z * SplinePrecision));
|
||||
}
|
||||
|
||||
// end debug
|
||||
}
|
||||
}
|
@ -0,0 +1,430 @@
|
||||
// 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()
|
||||
{
|
||||
InitializeMujocoVolumeActor();
|
||||
InitializeMovementComponent();
|
||||
|
||||
if (GetLuckyWorldSubsystem())
|
||||
{
|
||||
GetLuckyWorldSubsystem()->RegisterLuckyRobot(this);
|
||||
|
||||
GetLuckyWorldSubsystem()->TargetSpeedChanged.AddUniqueDynamic(this, &ALuckyRobotPawnBase::SetTargetSpeed);
|
||||
GetLuckyWorldSubsystem()->RobotNavPathChanged.AddUniqueDynamic(this, &ALuckyRobotPawnBase::SetRobotNavPath);
|
||||
}
|
||||
|
||||
Super::BeginPlay();
|
||||
}
|
||||
|
||||
bool ALuckyRobotPawnBase::HasMovementValue() const
|
||||
{
|
||||
return !FMath::IsNearlyZero(CachedMovementInputValues.X, 0.01f);
|
||||
}
|
||||
|
||||
bool ALuckyRobotPawnBase::HasTurnValue() const
|
||||
{
|
||||
return !FMath::IsNearlyZero(CachedMovementInputValues.Y, 0.01f);
|
||||
}
|
||||
|
||||
void ALuckyRobotPawnBase::Tick(float DeltaTime)
|
||||
{
|
||||
Super::Tick(DeltaTime);
|
||||
|
||||
// need to check NaviPoint to see if it is paused
|
||||
TaskTime += DeltaTime;
|
||||
|
||||
// if (HasTaskExpired())
|
||||
// {
|
||||
// IncrementCurrentTask();
|
||||
// }
|
||||
|
||||
UE_LOG(LogTemp, Warning, TEXT("ROBOT TARGET SPEED %f"), TargetSpeed);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
EnhancedInputComponent->BindAction(TogglePathfindingAction, ETriggerEvent::Started, this, &ALuckyRobotPawnBase::TogglePathfinding);
|
||||
}
|
||||
}
|
||||
|
||||
void ALuckyRobotPawnBase::MoveStart(const FInputActionValue& Value)
|
||||
{
|
||||
UE_LOG(LogTemp, Warning, TEXT("ALuckyRobotPawnBase :: Input :: MoveStart"));
|
||||
|
||||
CachedMovementInputValues.X = Value.Get<float>();
|
||||
|
||||
if (CurrentInputType != ERobotInputType::Move)
|
||||
{
|
||||
if (CurrentInputType == ERobotInputType::Turn && HasTurnValue())
|
||||
{
|
||||
PreviousInputType = ERobotInputType::Turn;
|
||||
}
|
||||
else
|
||||
{
|
||||
PreviousInputType = ERobotInputType::None;
|
||||
}
|
||||
|
||||
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 = Value.Get<float>();
|
||||
|
||||
if (CurrentInputType == ERobotInputType::Move)
|
||||
{
|
||||
switch (PreviousInputType) {
|
||||
case ERobotInputType::None:
|
||||
CurrentInputType = ERobotInputType::None;
|
||||
PreviousInputType = ERobotInputType::None;
|
||||
break;
|
||||
case ERobotInputType::Move:
|
||||
if (PreviousInputType == ERobotInputType::Turn && HasTurnValue())
|
||||
{
|
||||
CurrentInputType = ERobotInputType::Turn;
|
||||
|
||||
PreviousInputType = HasMovementValue() ? ERobotInputType::Move : ERobotInputType::None;
|
||||
}
|
||||
break;
|
||||
case ERobotInputType::Turn:
|
||||
CurrentInputType = ERobotInputType::Turn;
|
||||
PreviousInputType = HasMovementValue() ? ERobotInputType::Move : ERobotInputType::None;
|
||||
break;
|
||||
case ERobotInputType::Pathfinding:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ALuckyRobotPawnBase::TurnStart(const FInputActionValue& Value)
|
||||
{
|
||||
UE_LOG(LogTemp, Warning, TEXT("ALuckyRobotPawnBase :: Input :: TurnStart"));
|
||||
|
||||
CachedMovementInputValues.Y = Value.Get<float>();
|
||||
|
||||
if (CurrentInputType != ERobotInputType::Turn)
|
||||
{
|
||||
if (CurrentInputType == ERobotInputType::Move && HasMovementValue())
|
||||
{
|
||||
PreviousInputType = ERobotInputType::Move;
|
||||
}
|
||||
else
|
||||
{
|
||||
PreviousInputType = ERobotInputType::None;
|
||||
}
|
||||
|
||||
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 = Value.Get<float>();
|
||||
|
||||
if (CurrentInputType == ERobotInputType::Turn)
|
||||
{
|
||||
const bool bHasTurnInput = !FMath::IsNearlyZero(CachedMovementInputValues.Y, 0.01f);
|
||||
switch (PreviousInputType) {
|
||||
case ERobotInputType::None:
|
||||
CurrentInputType = ERobotInputType::None;
|
||||
PreviousInputType = ERobotInputType::None;
|
||||
break;
|
||||
case ERobotInputType::Move:
|
||||
CurrentInputType = ERobotInputType::Move;
|
||||
PreviousInputType = bHasTurnInput ? ERobotInputType::Turn : ERobotInputType::None;
|
||||
break;
|
||||
case ERobotInputType::Turn:
|
||||
if (PreviousInputType == ERobotInputType::Move && !FMath::IsNearlyZero(CachedMovementInputValues.X, 0.01f))
|
||||
{
|
||||
CurrentInputType = ERobotInputType::Move;
|
||||
|
||||
PreviousInputType = bHasTurnInput ? ERobotInputType::Turn : ERobotInputType::None;
|
||||
}
|
||||
break;
|
||||
case ERobotInputType::Pathfinding:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ALuckyRobotPawnBase::Look(const FInputActionValue& Value)
|
||||
{
|
||||
UE_LOG(LogTemp, Warning, TEXT("ALuckyRobotPawnBase :: Input :: Look (%s)"), *Value.Get<FVector2D>().ToString());
|
||||
}
|
||||
|
||||
void ALuckyRobotPawnBase::TogglePathfinding(const FInputActionValue& Value)
|
||||
{
|
||||
PreviousInputType = ERobotInputType::None;
|
||||
CurrentInputType = IsPathfinding() ? ERobotInputType::None : ERobotInputType::Pathfinding;
|
||||
}
|
||||
|
||||
void ALuckyRobotPawnBase::BeginPathfinding()
|
||||
{
|
||||
PreviousInputType = ERobotInputType::None;
|
||||
CurrentInputType = ERobotInputType::Pathfinding;
|
||||
}
|
||||
|
||||
void ALuckyRobotPawnBase::PathfindingComplete(const bool bSuccess)
|
||||
{
|
||||
CurrentInputType = ERobotInputType::None;
|
||||
PreviousInputType = ERobotInputType::Pathfinding;
|
||||
|
||||
UE_LOG(LogTemp, Warning, TEXT("ALuckyRobotPawnBase::PathfindingComplete"));
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
void ALuckyRobotPawnBase::SetRobotNavPath(const FRobotNavPath& InRobotNavPath)
|
||||
{
|
||||
CurrentSplinePath.GenerateSplinePath(this, InRobotNavPath);
|
||||
|
||||
Internal_RobotNavPathChanged(CurrentSplinePath);
|
||||
}
|
||||
|
||||
void ALuckyRobotPawnBase::Internal_RobotNavPathChanged(const FRobotSplinePath& NewNavPath)
|
||||
{
|
||||
// testing
|
||||
BeginPathfinding();
|
||||
//
|
||||
|
||||
RobotNavPathChanged(NewNavPath);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
GetCurrentNavPath().RegenerateSplinePathValues();
|
||||
|
||||
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);
|
||||
}
|
104
Source/LuckyWorldV2/Private/Subsystems/LuckyWorldSubsystem.cpp
Normal file
104
Source/LuckyWorldV2/Private/Subsystems/LuckyWorldSubsystem.cpp
Normal file
@ -0,0 +1,104 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
|
||||
#include "Subsystems/LuckyWorldSubsystem.h"
|
||||
|
||||
#include "NavigationPath.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);
|
||||
}
|
||||
}
|
||||
|
||||
void ULuckyWorldSubsystem::UpdateRobotNavPath(const FRobotNavPath& InRobotNavPath)
|
||||
{
|
||||
RobotNavPath = InRobotNavPath;
|
||||
|
||||
if (RobotNavPathChanged.IsBound())
|
||||
{
|
||||
RobotNavPathChanged.Broadcast(RobotNavPath);
|
||||
}
|
||||
}
|
||||
|
||||
FRobotNavPath ULuckyWorldSubsystem::GenerateRobotNavPath_Navigation(UNavigationPath* InNavPath)
|
||||
{
|
||||
FRobotNavPath NewNavPath = FRobotNavPath();
|
||||
|
||||
if (IsValid(InNavPath))
|
||||
{
|
||||
for (auto const& Point : InNavPath->PathPoints)
|
||||
{
|
||||
FRobotNavPoint NewPoint = FRobotNavPoint();
|
||||
NewPoint.Location = Point;
|
||||
NewNavPath.NavPoints.Add(NewPoint);
|
||||
}
|
||||
}
|
||||
|
||||
return NewNavPath;
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "LuckyRobotMovementComponent.h"
|
||||
#include "LRMC_Stretch.generated.h"
|
||||
|
||||
|
||||
UCLASS(ClassGroup=(Custom), meta=(BlueprintSpawnableComponent))
|
||||
class LUCKYWORLDV2_API ULRMC_Stretch : public ULuckyRobotMovementComponent
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
virtual void PerformMovement(float DeltaTime, const ERobotInputHandlingMethod InputHandlingMethod, const ERobotInputType InputType, const FVector2D& InputValues) override;
|
||||
|
||||
protected:
|
||||
ERobotInputType PreviousInputType = ERobotInputType::None;
|
||||
|
||||
void Move(const float DeltaTime, const FVector2D& InputValues) const;
|
||||
void Turn(const float DeltaTime, const float InValue) const;
|
||||
virtual void StopMovement() override;
|
||||
};
|
@ -0,0 +1,80 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Components/ActorComponent.h"
|
||||
#include "Gameplay/Robot/Data/RobotSettings.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();
|
||||
|
||||
virtual void TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
|
||||
|
||||
virtual void PerformMovement(float DeltaTime, const ERobotInputHandlingMethod InputHandlingMethod, const ERobotInputType InputType, const FVector2D& SpeedValues);
|
||||
|
||||
void InitializeMovementComponent(ALuckyRobotPawnBase* InOwningRobot);
|
||||
|
||||
ALuckyRobotPawnBase* GetOwningRobot() const { return OwningRobot.Get(); }
|
||||
|
||||
AMujocoVolumeActor* GetMujocoVolumeActor() const { return MujocoVolumeActor.Get(); }
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "Robot Values")
|
||||
FTransform GetRobotTransform() const;
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "Robot Values")
|
||||
FVector GetRobotLocation() const;
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "Robot Values")
|
||||
FVector GetRobotForwardVector() const;
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "Robot Values")
|
||||
FVector GetRobotRightVector() const;
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "Robot Values")
|
||||
FRobotSplinePath GetNavPath() const;
|
||||
|
||||
bool IsPathfinding() const;
|
||||
void HandlePathfindingInputs(const float DeltaTime);
|
||||
|
||||
FVector GetSplineTargetLocation(const float CurrentDistance) const;
|
||||
FVector GetSplineTargetPointLocation(const float CurrentDistance) const;
|
||||
float GetSplineSpeed(const float CurrentDistance) const;
|
||||
float GetSpeedLimit() const;
|
||||
|
||||
virtual void StopMovement();
|
||||
float GetTargetSpeed() const;
|
||||
float GetTargetSpeedMod() const;
|
||||
float GetTurnModifier() const;
|
||||
|
||||
protected:
|
||||
virtual void BeginPlay() override;
|
||||
|
||||
TWeakObjectPtr<ALuckyRobotPawnBase> OwningRobot;
|
||||
TWeakObjectPtr<AMujocoVolumeActor> MujocoVolumeActor;
|
||||
|
||||
FRobotSettings RobotSettings = FRobotSettings();
|
||||
|
||||
ERobotInputType PathfindingInputType = ERobotInputType::None;
|
||||
|
||||
virtual void InterpolateSpeedValues(const float DeltaTime, const float Acceleration, const float Deceleration);
|
||||
|
||||
FVector2D CurrentSpeedValues = FVector2D::ZeroVector;
|
||||
FVector2D PreviousSpeedValues = FVector2D::ZeroVector;
|
||||
float PathfindingTargetSpeed = 0.f;
|
||||
float PathfindingDestinationTolerance = 10.f;
|
||||
FVector PathfindingTargetLocation = FVector::ZeroVector;
|
||||
FVector PathfindingDestination = FVector::ZeroVector;
|
||||
|
||||
float CurrentRobotSpeed = 0.f;
|
||||
FVector PreviousLocation = FVector::ZeroVector;
|
||||
};
|
103
Source/LuckyWorldV2/Public/Gameplay/Robot/Data/RobotSettings.h
Normal file
103
Source/LuckyWorldV2/Public/Gameplay/Robot/Data/RobotSettings.h
Normal file
@ -0,0 +1,103 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "RobotSettings.generated.h"
|
||||
|
||||
|
||||
class ALuckyRobotPawnBase;
|
||||
class USplineComponent;
|
||||
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")
|
||||
float SpeedLimit = 15.f;
|
||||
|
||||
UPROPERTY(BlueprintReadWrite, EditDefaultsOnly, Category = "Robot Settings")
|
||||
float TurnSpeedLimit = 10.f;
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
struct FRobotNavPoint
|
||||
{
|
||||
GENERATED_USTRUCT_BODY()
|
||||
|
||||
UPROPERTY(BlueprintReadWrite, EditDefaultsOnly, Category = "Robot Nav Point")
|
||||
FVector Location = FVector::ZeroVector;
|
||||
|
||||
UPROPERTY(BlueprintReadWrite, EditDefaultsOnly, Category = "Robot Nav Point")
|
||||
bool bDestination = false;
|
||||
};
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
struct FRobotNavPath
|
||||
{
|
||||
GENERATED_USTRUCT_BODY()
|
||||
|
||||
UPROPERTY(BlueprintReadWrite, EditDefaultsOnly, Category = "Robot Nav Path")
|
||||
TArray<FRobotNavPoint> NavPoints;
|
||||
};
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
struct FRobotSplinePath
|
||||
{
|
||||
GENERATED_USTRUCT_BODY()
|
||||
|
||||
UPROPERTY(BlueprintReadOnly, Category = "Robot Spline Path")
|
||||
TWeakObjectPtr<ALuckyRobotPawnBase> Robot;
|
||||
|
||||
UPROPERTY(BlueprintReadOnly, Category = "Robot Spline Path")
|
||||
FRobotNavPath NavPath = FRobotNavPath();
|
||||
|
||||
UPROPERTY(BlueprintReadOnly, Category = "Robot Spline Path")
|
||||
TWeakObjectPtr<USplineComponent> SplinePath;
|
||||
|
||||
UPROPERTY(BlueprintReadOnly, Category = "Robot Spline Path")
|
||||
FRuntimeFloatCurve SplinePathSpeedModifier = FRuntimeFloatCurve();
|
||||
|
||||
UPROPERTY(BlueprintReadOnly, Category = "Robot Spline Path")
|
||||
FVector PathfindingDestination = FVector::ZeroVector;
|
||||
|
||||
ALuckyRobotPawnBase* GetRobot() const { return Robot.Get(); }
|
||||
void GenerateSplinePath(ALuckyRobotPawnBase* InRobot, const FRobotNavPath& InNavPath);
|
||||
void RegenerateSplinePathValues();
|
||||
USplineComponent* GetSplinePath() const { return SplinePath.Get(); }
|
||||
|
||||
FRobotSplinePath() {}
|
||||
FRobotSplinePath(ALuckyRobotPawnBase* InRobot, const FRobotNavPath& InNavPath)
|
||||
{
|
||||
GenerateSplinePath(InRobot, InNavPath);
|
||||
}
|
||||
};
|
225
Source/LuckyWorldV2/Public/Gameplay/Robot/LuckyRobotPawnBase.h
Normal file
225
Source/LuckyWorldV2/Public/Gameplay/Robot/LuckyRobotPawnBase.h
Normal file
@ -0,0 +1,225 @@
|
||||
// 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()
|
||||
bool SetActuators(const TArray<FStretchRobotActuator>& InActuators);
|
||||
|
||||
// SPEED CONFIG
|
||||
UFUNCTION()
|
||||
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()
|
||||
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();
|
||||
|
||||
// NAV ROBOT PATH CHANGED
|
||||
UFUNCTION()
|
||||
void SetRobotNavPath(const FRobotNavPath& InRobotNavPath);
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "Lucky Robot Pawn")
|
||||
FRobotSplinePath& GetCurrentNavPath() { return CurrentSplinePath; }
|
||||
|
||||
void Internal_RobotNavPathChanged(const FRobotSplinePath& NewNavPath);
|
||||
|
||||
UFUNCTION(BlueprintImplementableEvent, Category = "Lucky Robot Pawn")
|
||||
void RobotNavPathChanged(const FRobotSplinePath& NewNavPath);
|
||||
|
||||
// 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;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Input, meta = (AllowPrivateAccess = "true"))
|
||||
UInputAction* TogglePathfindingAction;
|
||||
|
||||
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);
|
||||
|
||||
void TogglePathfinding(const FInputActionValue& Value);
|
||||
void BeginPathfinding();
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "Lucky Robot Pawn")
|
||||
ERobotInputType GetCurrentInputType() const { return CurrentInputType; }
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "Lucky Robot Pawn")
|
||||
FVector2D GetMovementInputValues() const { return CachedMovementInputValues; }
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "Lucky Robot Pawn")
|
||||
float GetAccelerationRate() const { return AccelerationRate; }
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "Lucky Robot Pawn")
|
||||
float GetDecelerationRate() const { return DecelerationRate; }
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "Lucky Robot Pawn")
|
||||
float GetTurnModifier() const { return TurnModifier; }
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Lucky Robot Pawn")
|
||||
float AccelerationRate = 1.5f;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Lucky Robot Pawn")
|
||||
float DecelerationRate = 3.f;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Input")
|
||||
float TargetSpeed = 0.f;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Input")
|
||||
float TurnModifier = 1.f;
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "Input")
|
||||
void SetPathfindingInputValues(const FVector2D InValues = FVector2D::ZeroVector) { CachedMovementInputValues = InValues; }
|
||||
|
||||
bool IsPathfinding() const { return CurrentInputType == ERobotInputType::Pathfinding; }
|
||||
FVector GetPathfindingDestination() const { return CurrentSplinePath.PathfindingDestination; }
|
||||
|
||||
void PathfindingComplete(const bool bSuccess = false);
|
||||
|
||||
protected:
|
||||
virtual void BeginPlay() override;
|
||||
|
||||
bool HasMovementValue() const;
|
||||
bool HasTurnValue() const;
|
||||
|
||||
void RemoveMujocoVolumeActor();
|
||||
|
||||
TWeakObjectPtr<ULuckyRobotsGameInstance> LuckyGameInstance;
|
||||
TWeakObjectPtr<AMujocoVolumeActor> MujocoVolumeSettings;
|
||||
TWeakObjectPtr<ULuckyRobotMovementComponent> RobotMovementComponent;
|
||||
TWeakObjectPtr<ULuckyWorldSubsystem> LuckyWorldSubsystem;
|
||||
TWeakObjectPtr<UEnhancedInputComponent> EnhancedInputComponent;
|
||||
|
||||
TArray<FStretchRobotActuator> Actuators;
|
||||
|
||||
FVector2D CachedMovementInputValues = FVector2D::ZeroVector;
|
||||
|
||||
ERobotInputType PreviousInputType = ERobotInputType::None;
|
||||
ERobotInputType CurrentInputType = ERobotInputType::None;
|
||||
|
||||
float TorqueLimiter = 0.85f;
|
||||
int32 CurrentTaskIndex = -1;
|
||||
float TaskTime = 0.f;
|
||||
|
||||
UPROPERTY()
|
||||
FRobotSplinePath CurrentSplinePath = FRobotSplinePath();
|
||||
};
|
97
Source/LuckyWorldV2/Public/Subsystems/LuckyWorldSubsystem.h
Normal file
97
Source/LuckyWorldV2/Public/Subsystems/LuckyWorldSubsystem.h
Normal file
@ -0,0 +1,97 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Gameplay/Robot/Data/RobotSettings.h"
|
||||
#include "Subsystems/WorldSubsystem.h"
|
||||
#include "LuckyWorldSubsystem.generated.h"
|
||||
|
||||
|
||||
class UNavigationPath;
|
||||
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);
|
||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FLuckyRobotNavPathChangedDelegate, const FRobotNavPath&, NewRobotNavPath);
|
||||
|
||||
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;
|
||||
|
||||
// ROBOT NAV PATH
|
||||
UFUNCTION(BlueprintCallable, Category = "Lucky World Subsystem")
|
||||
void UpdateRobotNavPath(const FRobotNavPath& InRobotNavPath);
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "Lucky World Subsystem")
|
||||
FRobotNavPath GetRobotNavPath() const { return RobotNavPath; }
|
||||
|
||||
UPROPERTY(BlueprintAssignable, Category = "Lucky World Subsystem")
|
||||
FLuckyRobotNavPathChangedDelegate RobotNavPathChanged;
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "Lucky World Subsystem")
|
||||
FRobotNavPath GenerateRobotNavPath_Navigation(UNavigationPath* InNavPath);
|
||||
|
||||
protected:
|
||||
TWeakObjectPtr<ALuckyRobotPawnBase> LuckyRobotPawn;
|
||||
TWeakObjectPtr<AMujocoVolumeActor> MujocoVolumeActor;
|
||||
|
||||
UPROPERTY()
|
||||
FRobotNavPath RobotNavPath = FRobotNavPath();
|
||||
|
||||
float Robot_TargetSpeed = 0.f;
|
||||
float Robot_TorqueLimiter = 0.85f;
|
||||
int32 Robot_CurrentTaskIndex = -1;
|
||||
|
||||
bool bSimulationReady = false;
|
||||
};
|
Loading…
x
Reference in New Issue
Block a user