第一次提交
This commit is contained in:
@@ -0,0 +1,898 @@
|
||||
// Copyright 2025 https://yuewu.dev/en All Rights Reserved.
|
||||
|
||||
#include "GMS_MovementSystemComponent.h"
|
||||
#include "GameFramework/Pawn.h"
|
||||
#include "Engine/World.h"
|
||||
#include "TimerManager.h"
|
||||
#include "GameplayTagAssetInterface.h"
|
||||
#include "GameFramework/Actor.h"
|
||||
#include "GameFramework/Pawn.h"
|
||||
#include "Animation/AnimInstance.h"
|
||||
#include "Misc/DataValidation.h"
|
||||
#include "Net/Core/PushModel/PushModel.h"
|
||||
#include "Net/UnrealNetwork.h"
|
||||
#include "Settings/GMS_SettingObjectLibrary.h"
|
||||
#include "Utility/GMS_Log.h"
|
||||
#include "Utility/GMS_Math.h"
|
||||
#include "Utility/GMS_Vector.h"
|
||||
|
||||
#include UE_INLINE_GENERATED_CPP_BY_NAME(GMS_MovementSystemComponent)
|
||||
|
||||
UGMS_MovementSystemComponent::UGMS_MovementSystemComponent(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer)
|
||||
{
|
||||
PrimaryComponentTick.bCanEverTick = true;
|
||||
bWantsInitializeComponent = true;
|
||||
}
|
||||
|
||||
void UGMS_MovementSystemComponent::PostLoad()
|
||||
{
|
||||
Super::PostLoad();
|
||||
#if WITH_EDITOR
|
||||
PRAGMA_DISABLE_DEPRECATION_WARNINGS
|
||||
if (!MovementDefinitions.IsEmpty())
|
||||
{
|
||||
MovementDefinition = MovementDefinitions.Last();
|
||||
MovementDefinitions.Empty();
|
||||
}
|
||||
PRAGMA_ENABLE_DEPRECATION_WARNINGS
|
||||
#endif
|
||||
}
|
||||
|
||||
void UGMS_MovementSystemComponent::InitializeComponent()
|
||||
{
|
||||
Super::InitializeComponent();
|
||||
|
||||
OwnerPawn = Cast<APawn>(GetOwner());
|
||||
|
||||
check(OwnerPawn)
|
||||
|
||||
if (OwnerPawn)
|
||||
{
|
||||
// Set some default values here to ensure that the animation instance and the
|
||||
// camera component can read the most up-to-date values during their initialization.
|
||||
SetReplicatedViewRotation(OwnerPawn->GetViewRotation().GetNormalized(), false);
|
||||
|
||||
ViewState.Rotation = ReplicatedViewRotation;
|
||||
ViewState.PreviousYawAngle = UE_REAL_TO_FLOAT(OwnerPawn->GetViewRotation().Yaw);
|
||||
|
||||
const auto YawAngle{UE_REAL_TO_FLOAT(OwnerPawn->GetActorRotation().Yaw)};
|
||||
|
||||
LocomotionState.InputYawAngle = YawAngle;
|
||||
LocomotionState.VelocityYawAngle = YawAngle;
|
||||
}
|
||||
}
|
||||
|
||||
void UGMS_MovementSystemComponent::BeginPlay()
|
||||
{
|
||||
Super::BeginPlay();
|
||||
if (GetOwner()->GetClass()->ImplementsInterface(UGameplayTagAssetInterface::StaticClass()))
|
||||
{
|
||||
SetGameplayTagsProvider(GetOwner());
|
||||
}
|
||||
else
|
||||
{
|
||||
TArray<UActorComponent*> Components = GetOwner()->GetComponentsByInterface(UGameplayTagAssetInterface::StaticClass());
|
||||
if (Components.IsValidIndex(0))
|
||||
{
|
||||
SetGameplayTagsProvider(Components[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UGMS_MovementSystemComponent::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
|
||||
{
|
||||
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
|
||||
|
||||
FDoRepLifetimeParams Parameters;
|
||||
Parameters.bIsPushBased = true;
|
||||
|
||||
Parameters.Condition = COND_SkipOwner;
|
||||
|
||||
DOREPLIFETIME_WITH_PARAMS_FAST(ThisClass, LocomotionMode, Parameters)
|
||||
DOREPLIFETIME_WITH_PARAMS_FAST(ThisClass, OverlayMode, Parameters)
|
||||
DOREPLIFETIME_WITH_PARAMS_FAST(ThisClass, MovementSet, Parameters)
|
||||
DOREPLIFETIME_WITH_PARAMS_FAST(ThisClass, MovementDefinition, Parameters)
|
||||
|
||||
DOREPLIFETIME_WITH_PARAMS_FAST(ThisClass, ReplicatedViewRotation, Parameters)
|
||||
DOREPLIFETIME_WITH_PARAMS_FAST(ThisClass, DesiredVelocityYawAngle, Parameters)
|
||||
DOREPLIFETIME_WITH_PARAMS_FAST(ThisClass, OwnedTags, Parameters)
|
||||
}
|
||||
|
||||
UGMS_MovementSystemComponent* UGMS_MovementSystemComponent::GetMovementSystemComponent(const AActor* Actor)
|
||||
{
|
||||
return Actor != nullptr ? Actor->FindComponentByClass<UGMS_MovementSystemComponent>() : nullptr;
|
||||
}
|
||||
|
||||
bool UGMS_MovementSystemComponent::K2_FindMovementComponent(const AActor* Actor, UGMS_MovementSystemComponent*& Instance)
|
||||
{
|
||||
if (Actor == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
Instance = GetMovementSystemComponent(Actor);
|
||||
return Instance != nullptr;
|
||||
}
|
||||
|
||||
bool UGMS_MovementSystemComponent::K2_FindMovementComponentExt(const AActor* Actor, TSubclassOf<UGMS_MovementSystemComponent> DesiredClass, UGMS_MovementSystemComponent*& Instance)
|
||||
{
|
||||
if (DesiredClass)
|
||||
{
|
||||
Instance = GetMovementSystemComponent(Actor);
|
||||
return Instance != nullptr && Instance->GetClass()->IsChildOf(DesiredClass);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
FGameplayTagContainer UGMS_MovementSystemComponent::GetGameplayTags() const
|
||||
{
|
||||
if (IGameplayTagAssetInterface* TagAssetInterface = Cast<IGameplayTagAssetInterface>(GameplayTagsProvider))
|
||||
{
|
||||
FGameplayTagContainer RetTags;
|
||||
TagAssetInterface->GetOwnedGameplayTags(RetTags);
|
||||
|
||||
if (!OwnedTags.IsEmpty())
|
||||
{
|
||||
RetTags.AppendTags(OwnedTags);
|
||||
}
|
||||
|
||||
RetTags.AddTagFast(GetMovementState());
|
||||
RetTags.AddTagFast(GetRotationMode());
|
||||
|
||||
return RetTags;
|
||||
}
|
||||
return OwnedTags;
|
||||
}
|
||||
|
||||
void UGMS_MovementSystemComponent::SetGameplayTagsProvider(UObject* Provider)
|
||||
{
|
||||
if (!IsValid(Provider))
|
||||
{
|
||||
GMS_CLOG(Warning, "Passed invalid GameplayTagsProvider.");
|
||||
return;
|
||||
}
|
||||
if (IGameplayTagAssetInterface* TagAssetInterface = Cast<IGameplayTagAssetInterface>(Provider))
|
||||
{
|
||||
GameplayTagsProvider = Provider;
|
||||
}
|
||||
else
|
||||
{
|
||||
GMS_CLOG(Warning, "Passed in GameplayTagsProvider(%s) Doesn't implement GameplayTagAssetInterface, it can't provide gameplay tags.", *Provider->GetName());
|
||||
}
|
||||
}
|
||||
#pragma region GameplayTags
|
||||
void UGMS_MovementSystemComponent::AddGameplayTag(FGameplayTag TagToAdd)
|
||||
{
|
||||
AddGameplayTag(TagToAdd, true);
|
||||
}
|
||||
|
||||
void UGMS_MovementSystemComponent::RemoveGameplay(FGameplayTag TagToRemove)
|
||||
{
|
||||
RemoveGameplayTag(TagToRemove, true);
|
||||
}
|
||||
|
||||
void UGMS_MovementSystemComponent::SetGameplayTags(FGameplayTagContainer TagsToSet)
|
||||
{
|
||||
SetGameplayTags(TagsToSet, true);
|
||||
}
|
||||
|
||||
void UGMS_MovementSystemComponent::AddGameplayTag(const FGameplayTag& TagToAdd, bool bSendRpc)
|
||||
{
|
||||
if (GetOwner()->GetLocalRole() <= ROLE_SimulatedProxy)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
OwnedTags.AddTag(TagToAdd);
|
||||
|
||||
MARK_PROPERTY_DIRTY_FROM_NAME(ThisClass, OwnedTags, this)
|
||||
|
||||
if (bSendRpc)
|
||||
{
|
||||
if (GetOwner()->GetLocalRole() >= ROLE_Authority)
|
||||
{
|
||||
ClientAddGameplayTag(TagToAdd);
|
||||
}
|
||||
else
|
||||
{
|
||||
ServerAddGameplayTag(TagToAdd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UGMS_MovementSystemComponent::RemoveGameplayTag(const FGameplayTag& TagToRemove, bool bSendRpc)
|
||||
{
|
||||
if (GetOwner()->GetLocalRole() <= ROLE_SimulatedProxy)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
OwnedTags.RemoveTag(TagToRemove);
|
||||
|
||||
MARK_PROPERTY_DIRTY_FROM_NAME(ThisClass, OwnedTags, this)
|
||||
|
||||
if (bSendRpc)
|
||||
{
|
||||
if (GetOwner()->GetLocalRole() >= ROLE_Authority)
|
||||
{
|
||||
ClientRemoveGameplayTag(TagToRemove);
|
||||
}
|
||||
else
|
||||
{
|
||||
ServerRemoveGameplayTag(TagToRemove);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UGMS_MovementSystemComponent::SetGameplayTags(const FGameplayTagContainer& TagsToSet, bool bSendRpc)
|
||||
{
|
||||
if (GetOwner()->GetLocalRole() <= ROLE_SimulatedProxy)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
OwnedTags = TagsToSet;
|
||||
|
||||
MARK_PROPERTY_DIRTY_FROM_NAME(ThisClass, OwnedTags, this)
|
||||
|
||||
if (bSendRpc)
|
||||
{
|
||||
if (GetOwner()->GetLocalRole() >= ROLE_Authority)
|
||||
{
|
||||
ClientSetGameplayTags(TagsToSet);
|
||||
}
|
||||
else
|
||||
{
|
||||
ServerSetGameplayTags(TagsToSet);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UGMS_MovementSystemComponent::ClientAddGameplayTag_Implementation(const FGameplayTag& TagToAdd)
|
||||
{
|
||||
AddGameplayTag(TagToAdd, false);
|
||||
}
|
||||
|
||||
void UGMS_MovementSystemComponent::ServerAddGameplayTag_Implementation(const FGameplayTag& TagToAdd)
|
||||
{
|
||||
AddGameplayTag(TagToAdd, false);
|
||||
}
|
||||
|
||||
void UGMS_MovementSystemComponent::ClientRemoveGameplayTag_Implementation(const FGameplayTag& TagToRemove)
|
||||
{
|
||||
RemoveGameplayTag(TagToRemove, false);
|
||||
}
|
||||
|
||||
void UGMS_MovementSystemComponent::ServerRemoveGameplayTag_Implementation(const FGameplayTag& TagToRemove)
|
||||
{
|
||||
RemoveGameplayTag(TagToRemove, false);
|
||||
}
|
||||
|
||||
void UGMS_MovementSystemComponent::ClientSetGameplayTags_Implementation(const FGameplayTagContainer& TagsToSet)
|
||||
{
|
||||
SetGameplayTags(TagsToSet, false);
|
||||
}
|
||||
|
||||
void UGMS_MovementSystemComponent::ServerSetGameplayTags_Implementation(const FGameplayTagContainer& TagsToSet)
|
||||
{
|
||||
SetGameplayTags(TagsToSet, false);
|
||||
}
|
||||
#pragma endregion GameplayTags
|
||||
|
||||
#pragma region Locomotion
|
||||
|
||||
const FGMS_LocomotionState& UGMS_MovementSystemComponent::GetLocomotionState() const
|
||||
{
|
||||
return LocomotionState;
|
||||
}
|
||||
|
||||
TScriptInterface<IPoseSearchTrajectoryPredictorInterface> UGMS_MovementSystemComponent::GetTrajectoryPredictor() const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool UGMS_MovementSystemComponent::IsCrouching() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
float UGMS_MovementSystemComponent::GetMaxSpeed() const
|
||||
{
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
float UGMS_MovementSystemComponent::GetMaxAcceleration() const
|
||||
{
|
||||
return 1000.0f;
|
||||
}
|
||||
|
||||
bool UGMS_MovementSystemComponent::IsMovingOnGround() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void UGMS_MovementSystemComponent::SetDesiredVelocityYawAngle(float NewDesiredVelocityYawAngle)
|
||||
{
|
||||
COMPARE_ASSIGN_AND_MARK_PROPERTY_DIRTY(ThisClass, DesiredVelocityYawAngle, NewDesiredVelocityYawAngle, this);
|
||||
}
|
||||
|
||||
void UGMS_MovementSystemComponent::ServerSetDesiredVelocityYawAngle_Implementation(float NewDesiredVelocityYawAngle)
|
||||
{
|
||||
SetDesiredVelocityYawAngle(NewDesiredVelocityYawAngle);
|
||||
}
|
||||
|
||||
|
||||
const FGameplayTag& UGMS_MovementSystemComponent::GetLocomotionMode() const
|
||||
{
|
||||
return LocomotionMode;
|
||||
}
|
||||
|
||||
const FGMS_MovementBaseState& UGMS_MovementSystemComponent::GetMovementBase() const
|
||||
{
|
||||
return MovementBase;
|
||||
}
|
||||
|
||||
void UGMS_MovementSystemComponent::SetLocomotionMode(const FGameplayTag& NewLocomotionMode)
|
||||
{
|
||||
if (LocomotionMode != NewLocomotionMode)
|
||||
{
|
||||
const auto PreviousLocomotionMode{LocomotionMode};
|
||||
|
||||
LocomotionMode = NewLocomotionMode;
|
||||
|
||||
MARK_PROPERTY_DIRTY_FROM_NAME(ThisClass, LocomotionMode, this)
|
||||
|
||||
OnLocomotionModeChanged(PreviousLocomotionMode);
|
||||
}
|
||||
}
|
||||
|
||||
void UGMS_MovementSystemComponent::OnReplicated_LocomotionMode(const FGameplayTag& PreviousLocomotionMode)
|
||||
{
|
||||
OnLocomotionModeChanged(PreviousLocomotionMode);
|
||||
}
|
||||
|
||||
void UGMS_MovementSystemComponent::OnLocomotionModeChanged_Implementation(const FGameplayTag& PreviousLocomotionMode)
|
||||
{
|
||||
GMS_CLOG(Verbose, "locomotion mode changed from %s to %s", *PreviousLocomotionMode.ToString(), *LocomotionMode.ToString());
|
||||
OnLocomotionModeChangedEvent.Broadcast(PreviousLocomotionMode);
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
void UGMS_MovementSystemComponent::RefreshMovementBase()
|
||||
{
|
||||
}
|
||||
|
||||
#pragma region MovementSet
|
||||
|
||||
const FGameplayTag& UGMS_MovementSystemComponent::GetMovementSet() const
|
||||
{
|
||||
return MovementSet;
|
||||
}
|
||||
|
||||
const FGMS_MovementSetSetting& UGMS_MovementSystemComponent::GetMovementSetSetting() const
|
||||
{
|
||||
return MovementSetSetting;
|
||||
}
|
||||
|
||||
const FGMS_MovementStateSetting& UGMS_MovementSystemComponent::GetMovementStateSetting() const
|
||||
{
|
||||
return MovementStateSetting;
|
||||
}
|
||||
|
||||
const UGMS_MovementControlSetting_Default* UGMS_MovementSystemComponent::GetControlSetting() const
|
||||
{
|
||||
return ControlSetting;
|
||||
}
|
||||
|
||||
int32 UGMS_MovementSystemComponent::GetNumOfMovementStateSettings() const
|
||||
{
|
||||
return ControlSetting->MovementStates.Num();
|
||||
}
|
||||
|
||||
TSoftObjectPtr<const UGMS_MovementDefinition> UGMS_MovementSystemComponent::GetMovementDefinition() const
|
||||
{
|
||||
return MovementDefinition;
|
||||
}
|
||||
|
||||
TSoftObjectPtr<const UGMS_MovementDefinition> UGMS_MovementSystemComponent::GetPrevMovementDefinition() const
|
||||
{
|
||||
return PrevMovementDefinition;
|
||||
}
|
||||
|
||||
const UGMS_MovementDefinition* UGMS_MovementSystemComponent::GetLoadedMovementDefinition() const
|
||||
{
|
||||
return MovementDefinition.IsValid() ? MovementDefinition.Get() : nullptr;
|
||||
}
|
||||
|
||||
void UGMS_MovementSystemComponent::SetMovementSet(const FGameplayTag& NewMovementSet)
|
||||
{
|
||||
SetMovementSet(NewMovementSet, true);
|
||||
}
|
||||
|
||||
void UGMS_MovementSystemComponent::SetMovementDefinition(TSoftObjectPtr<UGMS_MovementDefinition> NewDefinition)
|
||||
{
|
||||
if (NewDefinition.IsNull())
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (NewDefinition != MovementDefinition)
|
||||
{
|
||||
auto LoadedDefinition = NewDefinition.LoadSynchronous();
|
||||
|
||||
if (LoadedDefinition->MovementSets.Contains(MovementSet))
|
||||
{
|
||||
InternalSetMovementDefinition(NewDefinition, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UGMS_MovementSystemComponent::LocalSetMovementDefinition(TSoftObjectPtr<UGMS_MovementDefinition> NewDefinition)
|
||||
{
|
||||
InternalSetMovementDefinition(NewDefinition, false);
|
||||
}
|
||||
|
||||
void UGMS_MovementSystemComponent::PushAvailableMovementDefinition(TSoftObjectPtr<UGMS_MovementDefinition> NewDefinition, bool bPopCurrent)
|
||||
{
|
||||
InternalSetMovementDefinition(NewDefinition, true);
|
||||
}
|
||||
|
||||
void UGMS_MovementSystemComponent::PopAvailableMovementDefinition()
|
||||
{
|
||||
// PopMovementDefinition(true);
|
||||
}
|
||||
|
||||
void UGMS_MovementSystemComponent::InternalSetMovementDefinition(const TSoftObjectPtr<UGMS_MovementDefinition> NewDefinition, bool bSendRpc)
|
||||
{
|
||||
if (!NewDefinition.IsNull() && NewDefinition != MovementDefinition)
|
||||
{
|
||||
PrevMovementDefinition = MovementDefinition;
|
||||
MovementDefinition = NewDefinition;
|
||||
MARK_PROPERTY_DIRTY_FROM_NAME(ThisClass, MovementDefinition, this)
|
||||
|
||||
OnMovementSetChanged(MovementSet);
|
||||
|
||||
if (bSendRpc)
|
||||
{
|
||||
if (GetOwner()->GetLocalRole() >= ROLE_Authority)
|
||||
{
|
||||
ClientSetMovementDefinition(NewDefinition);
|
||||
}
|
||||
else
|
||||
{
|
||||
ServerSetMovementDefinition(NewDefinition);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UGMS_MovementSystemComponent::ClientSetMovementDefinition_Implementation(const TSoftObjectPtr<UGMS_MovementDefinition>& NewDefinition)
|
||||
{
|
||||
InternalSetMovementDefinition(NewDefinition, false);
|
||||
}
|
||||
|
||||
void UGMS_MovementSystemComponent::ServerSetMovementDefinition_Implementation(const TSoftObjectPtr<UGMS_MovementDefinition>& NewDefinition)
|
||||
{
|
||||
InternalSetMovementDefinition(NewDefinition, false);
|
||||
}
|
||||
|
||||
void UGMS_MovementSystemComponent::OnReplicated_MovementDefinition()
|
||||
{
|
||||
OnMovementSetChanged(MovementSet);
|
||||
}
|
||||
|
||||
void UGMS_MovementSystemComponent::SetMovementSet(const FGameplayTag& NewMovementSet, bool bSendRpc)
|
||||
{
|
||||
if (MovementSet == NewMovementSet || GetOwner()->GetLocalRole() <= ROLE_SimulatedProxy)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const auto PreviousMovementSet{MovementSet};
|
||||
|
||||
MovementSet = NewMovementSet;
|
||||
|
||||
MARK_PROPERTY_DIRTY_FROM_NAME(ThisClass, MovementSet, this)
|
||||
|
||||
OnMovementSetChanged(PreviousMovementSet);
|
||||
|
||||
if (bSendRpc)
|
||||
{
|
||||
if (GetOwner()->GetLocalRole() >= ROLE_Authority)
|
||||
{
|
||||
ClientSetMovementSet(MovementSet);
|
||||
}
|
||||
else
|
||||
{
|
||||
ServerSetMovementSet(MovementSet);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UGMS_MovementSystemComponent::ClientSetMovementSet_Implementation(const FGameplayTag& NewMovementSet)
|
||||
{
|
||||
SetMovementSet(NewMovementSet, false);
|
||||
}
|
||||
|
||||
void UGMS_MovementSystemComponent::ServerSetMovementSet_Implementation(const FGameplayTag& NewMovementSet)
|
||||
{
|
||||
SetMovementSet(NewMovementSet, false);
|
||||
}
|
||||
|
||||
void UGMS_MovementSystemComponent::OnReplicated_MovementSet(const FGameplayTag& PreviousMovementSet)
|
||||
{
|
||||
OnMovementSetChanged(PreviousMovementSet);
|
||||
}
|
||||
|
||||
void UGMS_MovementSystemComponent::RefreshMovementSetSetting()
|
||||
{
|
||||
const UGMS_MovementDefinition* LoadedDefinition = MovementDefinition.LoadSynchronous();
|
||||
|
||||
if (!LoadedDefinition)
|
||||
{
|
||||
GMS_CLOG(Warning, "Missing valid movement definition!")
|
||||
return;
|
||||
}
|
||||
|
||||
if (!LoadedDefinition->MovementSets.Contains(MovementSet))
|
||||
{
|
||||
GMS_CLOG(Warning, "No movement set(%s) found in movement definition(%s)!", *MovementSet.ToString(), *GetNameSafe(LoadedDefinition))
|
||||
return;
|
||||
}
|
||||
MovementSetSetting = MovementDefinition->MovementSets[MovementSet];
|
||||
RefreshControlSetting();
|
||||
|
||||
// bool bFoundMovementSet{false};
|
||||
// for (int32 i = MovementDefinitions.Num() - 1; i >= 0; i--)
|
||||
// {
|
||||
// if (MovementDefinitions[i].IsNull())
|
||||
// {
|
||||
// continue;
|
||||
// }
|
||||
// if (!MovementDefinitions[i].IsValid())
|
||||
// {
|
||||
// MovementDefinitions[i].LoadSynchronous();
|
||||
// }
|
||||
// if (MovementDefinitions[i]->MovementSets.Contains(MovementSet))
|
||||
// {
|
||||
// MovementDefinition = MovementDefinitions[i].Get();
|
||||
// MovementSetSetting = MovementDefinition->MovementSets[MovementSet];
|
||||
// bFoundMovementSet = true;
|
||||
// RefreshControlSetting();
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// if (!bFoundMovementSet)
|
||||
// {
|
||||
// GMS_CLOG(Error, "No movement set(%s) found in movement definitions!", *MovementSet.ToString())
|
||||
// }
|
||||
}
|
||||
|
||||
void UGMS_MovementSystemComponent::RefreshControlSetting()
|
||||
{
|
||||
const UGMS_MovementControlSetting_Default* NewSetting = MovementSetSetting.bControlSettingPerOverlayMode && MovementSetSetting.ControlSettings.Contains(OverlayMode)
|
||||
? MovementSetSetting.ControlSettings[OverlayMode]
|
||||
: MovementSetSetting.ControlSetting;
|
||||
|
||||
if (NewSetting != nullptr && !NewSetting->MovementStates.IsEmpty())
|
||||
{
|
||||
ControlSetting = NewSetting;
|
||||
RefreshMovementStateSetting();
|
||||
ApplyMovementSetting();
|
||||
}
|
||||
else
|
||||
{
|
||||
ControlSetting = nullptr;
|
||||
GMS_CLOG(Error, "Empty MovementState settings are found in the movement set(%s) of definition(%s), which is not allowed!", *MovementSet.ToString(),
|
||||
*MovementDefinition->GetName())
|
||||
}
|
||||
}
|
||||
|
||||
void UGMS_MovementSystemComponent::OnMovementSetChanged_Implementation(const FGameplayTag& PreviousMovementSet)
|
||||
{
|
||||
RefreshMovementSetSetting();
|
||||
OnMovementSetChangedEvent.Broadcast(PreviousMovementSet);
|
||||
}
|
||||
|
||||
const FGameplayTag& UGMS_MovementSystemComponent::GetDesiredMovementState() const
|
||||
{
|
||||
return FGameplayTag::EmptyTag;
|
||||
}
|
||||
|
||||
|
||||
void UGMS_MovementSystemComponent::RefreshMovementStateSetting()
|
||||
{
|
||||
if (!IsValid(ControlSetting))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
FGMS_MovementStateSetting NewStateSetting;
|
||||
if (!ControlSetting->GetStateByTag(GetMovementState(), NewStateSetting))
|
||||
{
|
||||
checkf(!ControlSetting->MovementStates.IsEmpty(), TEXT("Found empty MovementState Settings on %s!"), *ControlSetting->GetName())
|
||||
NewStateSetting = ControlSetting->MovementStates.Last();
|
||||
SetDesiredMovement(NewStateSetting.Tag);
|
||||
GMS_CLOG(Verbose, "No MovementState setting for current movement state(%s), Change desired last one(%s) in list.", *GetMovementState().ToString(),
|
||||
*NewStateSetting.Tag.ToString());
|
||||
}
|
||||
|
||||
MovementStateSetting = NewStateSetting;
|
||||
|
||||
if (bRespectAllowedRotationModesSettings)
|
||||
{
|
||||
if (!MovementStateSetting.AllowedRotationModes.Contains(GetDesiredRotationMode()))
|
||||
{
|
||||
FGameplayTag AdjustedRotationMode = MovementStateSetting.AllowedRotationModes.Last();
|
||||
GMS_CLOG(Warning, "current movement state(%s) doesn't allow current desired rotation mode(%s), adjusted to:%s", *GetMovementState().ToString(), *GetDesiredRotationMode().ToString(),
|
||||
*AdjustedRotationMode.ToString());
|
||||
SetDesiredRotationMode(AdjustedRotationMode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UGMS_MovementSystemComponent::ApplyMovementSetting()
|
||||
{
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region MovementState
|
||||
void UGMS_MovementSystemComponent::SetDesiredMovement(const FGameplayTag& NewDesiredMovement)
|
||||
{
|
||||
}
|
||||
|
||||
void UGMS_MovementSystemComponent::CycleDesiredMovementState(bool bForward)
|
||||
{
|
||||
if (GetNumOfMovementStateSettings() == 1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
int32 Index = ControlSetting->MovementStates.IndexOfByKey(GetMovementState());
|
||||
|
||||
if (Index == INDEX_NONE)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (bForward && ControlSetting->MovementStates.IsValidIndex(Index + 1))
|
||||
{
|
||||
SetDesiredMovement(ControlSetting->MovementStates[Index + 1].Tag);
|
||||
}
|
||||
|
||||
if (!bForward && ControlSetting->MovementStates.IsValidIndex(Index - 1))
|
||||
{
|
||||
SetDesiredMovement(ControlSetting->MovementStates[Index - 1].Tag);
|
||||
}
|
||||
}
|
||||
|
||||
const FGameplayTag& UGMS_MovementSystemComponent::GetMovementState() const
|
||||
{
|
||||
return FGameplayTag::EmptyTag;
|
||||
}
|
||||
|
||||
int32 UGMS_MovementSystemComponent::GetSpeedLevel() const
|
||||
{
|
||||
return MovementStateSetting.SpeedLevel;
|
||||
}
|
||||
|
||||
float UGMS_MovementSystemComponent::GetMappedMovementSpeedLevel(float Speed) const
|
||||
{
|
||||
if (!ControlSetting)
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
float SpeedLevelAmount = ControlSetting->MovementStates.Last().SpeedLevel;
|
||||
for (int32 i = ControlSetting->MovementStates.Num() - 2; i >= 0; i--)
|
||||
{
|
||||
const FGMS_MovementStateSetting& Max = ControlSetting->MovementStates[i + 1];
|
||||
const FGMS_MovementStateSetting& Min = ControlSetting->MovementStates[i];
|
||||
// In current range.
|
||||
if (Min.Speed > 0 && Speed >= Min.Speed && Speed <= Max.Speed)
|
||||
{
|
||||
SpeedLevelAmount = FMath::GetMappedRangeValueClamped(FVector2f{Min.Speed, Max.Speed}, {static_cast<float>(Min.SpeedLevel), static_cast<float>(Max.SpeedLevel)}, Speed);
|
||||
}
|
||||
}
|
||||
GMS_CLOG(VeryVerbose, "Mapped speed(%f) to speed level(%f)", Speed, SpeedLevelAmount)
|
||||
return SpeedLevelAmount;
|
||||
}
|
||||
|
||||
|
||||
void UGMS_MovementSystemComponent::OnMovementStateChanged_Implementation(const FGameplayTag& PreviousMovementState)
|
||||
{
|
||||
RefreshMovementStateSetting();
|
||||
ApplyMovementSetting();
|
||||
OnMovementStateChangedEvent.Broadcast(PreviousMovementState);
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region Input
|
||||
|
||||
FVector UGMS_MovementSystemComponent::GetMovementIntent() const
|
||||
{
|
||||
checkf(0, TEXT("Not implemented"));
|
||||
return FVector::ZeroVector;
|
||||
}
|
||||
|
||||
void UGMS_MovementSystemComponent::RefreshInput(float DeltaTime)
|
||||
{
|
||||
LocomotionState.bHasInput = GetMovementIntent().SizeSquared() > UE_KINDA_SMALL_NUMBER;
|
||||
|
||||
if (LocomotionState.bHasInput)
|
||||
{
|
||||
LocomotionState.InputYawAngle = UE_REAL_TO_FLOAT(UGMS_Vector::DirectionToAngleXY(GetMovementIntent()));
|
||||
}
|
||||
}
|
||||
|
||||
void UGMS_MovementSystemComponent::TurnAtRate(float Direction)
|
||||
{
|
||||
if (Direction != 0 && GetRotationMode() == GMS_RotationModeTags::VelocityDirection &&
|
||||
OwnerPawn->GetLocalRole() >= ROLE_AutonomousProxy)
|
||||
{
|
||||
if (const auto Setting = ControlSetting->VelocityDirectionSetting.GetPtr<FGMS_VelocityDirectionSetting_RateBased>())
|
||||
{
|
||||
const float TurnRate =
|
||||
IsValid(Setting->TurnRateSpeedCurve)
|
||||
? Setting->TurnRateSpeedCurve->GetFloatValue(FMath::Max(1.0f, GetMappedMovementSpeedLevel(UE_REAL_TO_FLOAT(LocomotionState.Velocity.Size2D()))))
|
||||
: Setting->TurnRate;
|
||||
|
||||
float YawDelta = Direction * TurnRate * GetWorld()->GetDeltaSeconds();
|
||||
if (FMath::Abs(YawDelta) > UE_SMALL_NUMBER)
|
||||
{
|
||||
float TargetYawAngle = FMath::UnwindDegrees(OwnerPawn->GetActorRotation().Yaw + YawDelta);
|
||||
|
||||
// 或者,方法2:使用 RotateAngleAxis(如果需要保持四元数精度)
|
||||
// FQuat DeltaRotation = FQuat(FVector::UpVector, FMath::DegreesToRadians(YawDelta));
|
||||
// FQuat NewRotation = DeltaRotation * LocomotionState.RotationQuaternion;
|
||||
// NewDesiredVelocityYawAngle = NewRotation.Rotator().Yaw;
|
||||
|
||||
// FRotator RotationDelta = FRotator(0,Direction * GetVelocityDirectionSetting().TurningRate * DeltaTime,0);
|
||||
//
|
||||
// NewDesiredVelocityYawAngle = (RotationDelta.Quaternion() * LocomotionState.RotationQuaternion).Rotator().Yaw;
|
||||
|
||||
SetDesiredVelocityYawAngle(TargetYawAngle);
|
||||
if (OwnerPawn->GetLocalRole() < ROLE_Authority)
|
||||
{
|
||||
ServerSetDesiredVelocityYawAngle(TargetYawAngle);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region ViewSystem
|
||||
|
||||
const FGMS_ViewState& UGMS_MovementSystemComponent::GetViewState() const
|
||||
{
|
||||
return ViewState;
|
||||
}
|
||||
|
||||
void UGMS_MovementSystemComponent::SetReplicatedViewRotation(const FRotator& NewViewRotation, bool bSendRpc)
|
||||
{
|
||||
if (!ReplicatedViewRotation.Equals(NewViewRotation))
|
||||
{
|
||||
ReplicatedViewRotation = NewViewRotation;
|
||||
|
||||
MARK_PROPERTY_DIRTY_FROM_NAME(ThisClass, ReplicatedViewRotation, this)
|
||||
|
||||
if (bSendRpc && GetOwner()->GetLocalRole() == ROLE_AutonomousProxy)
|
||||
{
|
||||
ServerSetReplicatedViewRotation(ReplicatedViewRotation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UGMS_MovementSystemComponent::ServerSetReplicatedViewRotation_Implementation(const FRotator& NewViewRotation)
|
||||
{
|
||||
SetReplicatedViewRotation(NewViewRotation, false);
|
||||
}
|
||||
|
||||
void UGMS_MovementSystemComponent::OnReplicated_ReplicatedViewRotation()
|
||||
{
|
||||
ViewState.Rotation = MovementBase.bHasRelativeRotation ? (MovementBase.Rotation * ReplicatedViewRotation.Quaternion()).Rotator() : ReplicatedViewRotation;
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region Rotation Mode
|
||||
|
||||
const FGameplayTag& UGMS_MovementSystemComponent::GetDesiredRotationMode() const
|
||||
{
|
||||
return FGameplayTag::EmptyTag;
|
||||
}
|
||||
|
||||
void UGMS_MovementSystemComponent::SetDesiredRotationMode(const FGameplayTag& NewDesiredRotationMode)
|
||||
{
|
||||
}
|
||||
|
||||
const FGameplayTag& UGMS_MovementSystemComponent::GetRotationMode() const
|
||||
{
|
||||
return FGameplayTag::EmptyTag;
|
||||
}
|
||||
|
||||
void UGMS_MovementSystemComponent::OnRotationModeChanged_Implementation(const FGameplayTag& PreviousRotationMode)
|
||||
{
|
||||
ApplyMovementSetting();
|
||||
OnRotationModeChangedEvent.Broadcast(PreviousRotationMode);
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region OverlayMode
|
||||
const FGameplayTag& UGMS_MovementSystemComponent::GetOverlayMode() const
|
||||
{
|
||||
return OverlayMode;
|
||||
}
|
||||
|
||||
void UGMS_MovementSystemComponent::SetOverlayMode(const FGameplayTag& NewOverlayMode)
|
||||
{
|
||||
SetOverlayMode(NewOverlayMode, true);
|
||||
}
|
||||
|
||||
void UGMS_MovementSystemComponent::SetOverlayMode(const FGameplayTag& NewOverlayMode, bool bSendRpc)
|
||||
{
|
||||
if (OverlayMode == NewOverlayMode || OwnerPawn->GetLocalRole() <= ROLE_SimulatedProxy)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const auto PreviousOverlayMode{OverlayMode};
|
||||
|
||||
OverlayMode = NewOverlayMode;
|
||||
|
||||
MARK_PROPERTY_DIRTY_FROM_NAME(ThisClass, OverlayMode, this)
|
||||
|
||||
OnOverlayModeChanged(PreviousOverlayMode);
|
||||
|
||||
if (bSendRpc)
|
||||
{
|
||||
if (OwnerPawn->GetLocalRole() >= ROLE_Authority)
|
||||
{
|
||||
ClientSetOverlayMode(OverlayMode);
|
||||
}
|
||||
else
|
||||
{
|
||||
ServerSetOverlayMode(OverlayMode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UGMS_MovementSystemComponent::ClientSetOverlayMode_Implementation(const FGameplayTag& NewOverlayMode)
|
||||
{
|
||||
SetOverlayMode(NewOverlayMode, false);
|
||||
}
|
||||
|
||||
void UGMS_MovementSystemComponent::ServerSetOverlayMode_Implementation(const FGameplayTag& NewOverlayMode)
|
||||
{
|
||||
SetOverlayMode(NewOverlayMode, false);
|
||||
}
|
||||
|
||||
void UGMS_MovementSystemComponent::OnReplicated_OverlayMode(const FGameplayTag& PreviousOverlayMode)
|
||||
{
|
||||
OnOverlayModeChanged(PreviousOverlayMode);
|
||||
}
|
||||
|
||||
void UGMS_MovementSystemComponent::OnOverlayModeChanged_Implementation(const FGameplayTag& PreviousOverlayMode)
|
||||
{
|
||||
if (MovementSetSetting.bControlSettingPerOverlayMode)
|
||||
{
|
||||
RefreshControlSetting();
|
||||
}
|
||||
OnOverlayModeChangedEvent.Broadcast(PreviousOverlayMode);
|
||||
}
|
||||
#pragma endregion
|
||||
|
||||
|
||||
#if WITH_EDITOR
|
||||
EDataValidationResult UGMS_MovementSystemComponent::IsDataValid(class FDataValidationContext& Context) const
|
||||
{
|
||||
if (IsTemplate() && AnimGraphSetting == nullptr)
|
||||
{
|
||||
Context.AddError(FText::FromString("AnimGraphSetting is required!"));
|
||||
return EDataValidationResult::Invalid;
|
||||
}
|
||||
return Super::IsDataValid(Context);
|
||||
}
|
||||
#endif
|
||||
Reference in New Issue
Block a user