Add SLS movement bridge

This commit is contained in:
2026-04-26 12:59:41 +08:00
parent 08e998324c
commit 2ed2e91381
5 changed files with 182 additions and 1 deletions

View File

@@ -24,6 +24,7 @@ public class PHY : ModuleRules
"GenericInputSystem", "GenericInputSystem",
"GenericGameSystem", "GenericGameSystem",
"GenericEffectsSystem", "GenericEffectsSystem",
"SmoothLocomotionSystem",
"AuroraDevs_UGC", "AuroraDevs_UGC",
"IKRig", "IKRig",
"AIModule" "AIModule"

View File

@@ -17,14 +17,16 @@
#include "GGA_AbilitySystemComponent.h" #include "GGA_AbilitySystemComponent.h"
#include "GameFramework/CharacterMovementComponent.h" #include "GameFramework/CharacterMovementComponent.h"
#include "Interaction/GGS_InteractionSystemComponent.h" #include "Interaction/GGS_InteractionSystemComponent.h"
#include "Locomotion/PHYSLSMovementBridgeComponent.h"
#include "Net/UnrealNetwork.h" #include "Net/UnrealNetwork.h"
#include "PHYGameplayTags.h" #include "PHYGameplayTags.h"
#include "Ragdoll/GGS_RagdollComponent.h" #include "Ragdoll/GGS_RagdollComponent.h"
#include "Components/SLSCharacterMovementComponent.h"
#include "Targeting/GCS_TargetingSystemComponent.h" #include "Targeting/GCS_TargetingSystemComponent.h"
#include "Team/GCS_CombatTeamAgentComponent.h" #include "Team/GCS_CombatTeamAgentComponent.h"
APHYCharacterBase::APHYCharacterBase(const FObjectInitializer& ObjectInitializer) APHYCharacterBase::APHYCharacterBase(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer) : Super(ObjectInitializer.SetDefaultSubobjectClass<USLSCharacterMovementComponent>(ACharacter::CharacterMovementComponentName))
{ {
bReplicates = true; bReplicates = true;
@@ -36,6 +38,18 @@ APHYCharacterBase::APHYCharacterBase(const FObjectInitializer& ObjectInitializer
RagdollComponent = CreateDefaultSubobject<UGGS_RagdollComponent>(TEXT("RagdollComponent")); RagdollComponent = CreateDefaultSubobject<UGGS_RagdollComponent>(TEXT("RagdollComponent"));
ContextEffectComponent = CreateDefaultSubobject<UGES_ContextEffectComponent>(TEXT("ContextEffectComponent")); ContextEffectComponent = CreateDefaultSubobject<UGES_ContextEffectComponent>(TEXT("ContextEffectComponent"));
MeshBridgeComponent = CreateDefaultSubobject<UPHYCharacterMeshBridgeComponent>(TEXT("MeshBridgeComponent")); MeshBridgeComponent = CreateDefaultSubobject<UPHYCharacterMeshBridgeComponent>(TEXT("MeshBridgeComponent"));
SLSMovementBridgeComponent = CreateDefaultSubobject<UPHYSLSMovementBridgeComponent>(TEXT("SLSMovementBridgeComponent"));
if (UClass* GenericIntegrationClass = FindObject<UClass>(nullptr, TEXT("/Script/GenericGameSystem.GenericIntegrationComponent")))
{
GenericIntegrationComponent = Cast<UActorComponent>(CreateDefaultSubobject(
TEXT("GenericIntegrationComponent"),
UActorComponent::StaticClass(),
GenericIntegrationClass,
false,
false));
}
DisplayMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("DisplayMeshComponent")); DisplayMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("DisplayMeshComponent"));
DisplayMeshComponent->SetupAttachment(GetMesh()); DisplayMeshComponent->SetupAttachment(GetMesh());
DisplayMeshComponent->SetCollisionEnabled(ECollisionEnabled::NoCollision); DisplayMeshComponent->SetCollisionEnabled(ECollisionEnabled::NoCollision);
@@ -70,6 +84,11 @@ void APHYCharacterBase::BeginPlay()
ContextEffectComponent->SetGameplayTagsProvider(this); ContextEffectComponent->SetGameplayTagsProvider(this);
} }
if (SLSMovementBridgeComponent)
{
SLSMovementBridgeComponent->InitializeSLSMovementBridge(this, GenericIntegrationComponent);
}
UGameFrameworkComponentManager::SendGameFrameworkComponentExtensionEvent(this, UGameFrameworkComponentManager::NAME_GameActorReady); UGameFrameworkComponentManager::SendGameFrameworkComponentExtensionEvent(this, UGameFrameworkComponentManager::NAME_GameActorReady);
} }
@@ -181,6 +200,11 @@ bool APHYCharacterBase::HandleInputTag(const FGameplayTag InputTag, const ETrigg
if (InputTag == PHYGameplayTags::Input_Sprint) if (InputTag == PHYGameplayTags::Input_Sprint)
{ {
if (USLSCharacterMovementComponent* SLSMovementComponent = GetSLSCharacterMovementComponent())
{
SLSMovementComponent->UpdateMovementType(bPressed ? ESLSMovementType::Sprint : ESLSMovementType::Jog);
}
if (CharacterStateComponent) if (CharacterStateComponent)
{ {
CharacterStateComponent->SetMovementState(bPressed ? PHYGameplayTags::State_Movement_Sprint : PHYGameplayTags::State_Movement_Run); CharacterStateComponent->SetMovementState(bPressed ? PHYGameplayTags::State_Movement_Sprint : PHYGameplayTags::State_Movement_Run);
@@ -197,6 +221,11 @@ bool APHYCharacterBase::HandleInputTag(const FGameplayTag InputTag, const ETrigg
if (InputTag == PHYGameplayTags::Input_Aim) if (InputTag == PHYGameplayTags::Input_Aim)
{ {
if (USLSCharacterMovementComponent* SLSMovementComponent = GetSLSCharacterMovementComponent())
{
SLSMovementComponent->UpdateRotationMode(bPressed ? ESLSRotationMode::AimingDirection : ESLSRotationMode::VelocityDirection);
}
if (CharacterStateComponent) if (CharacterStateComponent)
{ {
CharacterStateComponent->SetMovementSet(bPressed ? PHYGameplayTags::State_MovementSet_Aiming : PHYGameplayTags::State_MovementSet_Default); CharacterStateComponent->SetMovementSet(bPressed ? PHYGameplayTags::State_MovementSet_Aiming : PHYGameplayTags::State_MovementSet_Default);
@@ -241,6 +270,11 @@ bool APHYCharacterBase::HandleInputTag(const FGameplayTag InputTag, const ETrigg
return false; return false;
} }
USLSCharacterMovementComponent* APHYCharacterBase::GetSLSCharacterMovementComponent() const
{
return Cast<USLSCharacterMovementComponent>(GetCharacterMovement());
}
void APHYCharacterBase::SetMovementIntent(const FVector NewMovementIntent) void APHYCharacterBase::SetMovementIntent(const FVector NewMovementIntent)
{ {
const FVector ClampedIntent = NewMovementIntent.GetClampedToMaxSize(1.0f); const FVector ClampedIntent = NewMovementIntent.GetClampedToMaxSize(1.0f);

View File

@@ -0,0 +1,56 @@
// Copyright Epic Games, Inc. All Rights Reserved.
#include "Locomotion/PHYSLSMovementBridgeComponent.h"
#include UE_INLINE_GENERATED_CPP_BY_NAME(PHYSLSMovementBridgeComponent)
#include "Characters/PHYCharacterSettings.h"
#include "Components/SLSCharacterMovementComponent.h"
#include "GameFramework/Character.h"
#include "PHYConfigSettings.h"
UPHYSLSMovementBridgeComponent::UPHYSLSMovementBridgeComponent()
{
PrimaryComponentTick.bCanEverTick = false;
SetIsReplicatedByDefault(false);
}
bool UPHYSLSMovementBridgeComponent::InitializeSLSMovementBridge(ACharacter* InCharacter, UActorComponent* InGenericIntegrationComponent)
{
bInitialized = false;
OwnerCharacter = InCharacter;
GenericIntegrationComponent = InGenericIntegrationComponent;
SLSCharacterMovementComponent = nullptr;
const UPHYLocomotionSettings* LocomotionSettings = GetDefault<UPHYLocomotionSettings>();
if (!LocomotionSettings || !LocomotionSettings->bUseSmoothLocomotionSystem || !OwnerCharacter)
{
return false;
}
SLSCharacterMovementComponent = Cast<USLSCharacterMovementComponent>(OwnerCharacter->GetCharacterMovement());
if (!SLSCharacterMovementComponent)
{
return false;
}
const UPHYCharacterSettings* CharacterSettings = GetDefault<UPHYCharacterSettings>();
// 首期由项目侧显式初始化,避免依赖 SLSIntegrationComponent 的总装逻辑。
SLSCharacterMovementComponent->Config.InitComponentType = ESLSComponentInitType::ManualInit;
SLSCharacterMovementComponent->Config.MovementType = ESLSMovementType::Jog;
SLSCharacterMovementComponent->Config.RotationMode = ESLSRotationMode::VelocityDirection;
SLSCharacterMovementComponent->Config.bEnableSprintInLookingDirectionRotationMode = true;
SLSCharacterMovementComponent->ApplyBaseSLSCharacterMovementSettings();
if (CharacterSettings)
{
SLSCharacterMovementComponent->MaxWalkSpeed = CharacterSettings->DefaultMaxWalkSpeed;
SLSCharacterMovementComponent->MaxAcceleration = CharacterSettings->DefaultMaxAcceleration;
}
SLSCharacterMovementComponent->InitializeMovementComponent(SLSCharacterMovementComponent->Config);
bInitialized = true;
return true;
}

View File

@@ -19,7 +19,9 @@ class UGGS_InteractionSystemComponent;
class UGGS_RagdollComponent; class UGGS_RagdollComponent;
class UPHYCharacterMeshBridgeComponent; class UPHYCharacterMeshBridgeComponent;
class UPHYCharacterStateComponent; class UPHYCharacterStateComponent;
class UPHYSLSMovementBridgeComponent;
class USkeletalMeshComponent; class USkeletalMeshComponent;
class USLSCharacterMovementComponent;
/** /**
* @brief PHY 玩家和 AI 共用角色基类。 * @brief PHY 玩家和 AI 共用角色基类。
@@ -124,6 +126,18 @@ public:
UFUNCTION(BlueprintCallable, BlueprintPure, Category="PHY|Character|Animation") UFUNCTION(BlueprintCallable, BlueprintPure, Category="PHY|Character|Animation")
UPHYCharacterMeshBridgeComponent* GetMeshBridgeComponent() const { return MeshBridgeComponent; } UPHYCharacterMeshBridgeComponent* GetMeshBridgeComponent() const { return MeshBridgeComponent; }
/** @brief 获取 PHY SLS 运动桥接组件。 */
UFUNCTION(BlueprintCallable, BlueprintPure, Category="PHY|Character|Locomotion")
UPHYSLSMovementBridgeComponent* GetSLSMovementBridgeComponent() const { return SLSMovementBridgeComponent; }
/** @brief 获取 SLS 角色运动组件。 */
UFUNCTION(BlueprintCallable, BlueprintPure, Category="PHY|Character|Locomotion")
USLSCharacterMovementComponent* GetSLSCharacterMovementComponent() const;
/** @brief 获取 GenericGameSystem 可选集成入口组件。 */
UFUNCTION(BlueprintCallable, BlueprintPure, Category="PHY|Character|Locomotion")
UActorComponent* GetGenericIntegrationComponent() const { return GenericIntegrationComponent; }
/** @brief 获取显示层 Mesh 组件,职业和外观 Mesh 应应用到该组件。 */ /** @brief 获取显示层 Mesh 组件,职业和外观 Mesh 应应用到该组件。 */
UFUNCTION(BlueprintCallable, BlueprintPure, Category="PHY|Character|Animation") UFUNCTION(BlueprintCallable, BlueprintPure, Category="PHY|Character|Animation")
USkeletalMeshComponent* GetDisplayMeshComponent() const { return DisplayMeshComponent; } USkeletalMeshComponent* GetDisplayMeshComponent() const { return DisplayMeshComponent; }
@@ -248,6 +262,14 @@ protected:
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="PHY|Character|Animation") UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="PHY|Character|Animation")
TObjectPtr<UPHYCharacterMeshBridgeComponent> MeshBridgeComponent; TObjectPtr<UPHYCharacterMeshBridgeComponent> MeshBridgeComponent;
/** @brief PHY 对 SLS 运动系统的桥接组件。 */
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="PHY|Character|Locomotion")
TObjectPtr<UPHYSLSMovementBridgeComponent> SLSMovementBridgeComponent;
/** @brief GenericGameSystem 可选集成入口组件。 */
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="PHY|Character|Locomotion")
TObjectPtr<UActorComponent> GenericIntegrationComponent;
/** @brief 显示层 Mesh 组件,承载职业和外观 Mesh。 */ /** @brief 显示层 Mesh 组件,承载职业和外观 Mesh。 */
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="PHY|Character|Animation") UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="PHY|Character|Animation")
TObjectPtr<USkeletalMeshComponent> DisplayMeshComponent; TObjectPtr<USkeletalMeshComponent> DisplayMeshComponent;

View File

@@ -0,0 +1,68 @@
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "PHYSLSMovementBridgeComponent.generated.h"
class ACharacter;
class USLSCharacterMovementComponent;
/**
* @brief PHY 对 Smooth Locomotion System 的首期运动桥接组件。
*
* 该组件只缓存并初始化明确接入的 SLS 运动组件,不使用 SLSIntegrationComponent
* 也不承担相机系统职责。
*/
UCLASS(BlueprintType, Blueprintable)
class PHY_API UPHYSLSMovementBridgeComponent : public UActorComponent
{
GENERATED_BODY()
public:
/** @brief 创建运动桥接组件。 */
UPHYSLSMovementBridgeComponent();
/**
* @brief 初始化 SLS 运动桥接。
* @param InCharacter 拥有该桥接组件的角色。
* @param InGenericIntegrationComponent 可选的 Generic 集成入口组件。
* @return 初始化是否成功。
*/
UFUNCTION(BlueprintCallable, Category="PHY|Locomotion|SLS")
bool InitializeSLSMovementBridge(ACharacter* InCharacter, UActorComponent* InGenericIntegrationComponent);
/** @brief 获取桥接到的角色。 */
UFUNCTION(BlueprintCallable, BlueprintPure, Category="PHY|Locomotion|SLS")
ACharacter* GetOwnerCharacter() const { return OwnerCharacter; }
/** @brief 获取 SLS 角色运动组件。 */
UFUNCTION(BlueprintCallable, BlueprintPure, Category="PHY|Locomotion|SLS")
USLSCharacterMovementComponent* GetSLSCharacterMovementComponent() const { return SLSCharacterMovementComponent; }
/** @brief 获取可选的 Generic 集成入口组件。 */
UFUNCTION(BlueprintCallable, BlueprintPure, Category="PHY|Locomotion|SLS")
UActorComponent* GetGenericIntegrationComponent() const { return GenericIntegrationComponent; }
/** @brief 查询桥接是否已完成初始化。 */
UFUNCTION(BlueprintCallable, BlueprintPure, Category="PHY|Locomotion|SLS")
bool IsSLSMovementBridgeInitialized() const { return bInitialized; }
protected:
/** @brief 拥有 SLS 运动能力的角色。 */
UPROPERTY(Transient, BlueprintReadOnly, Category="PHY|Locomotion|SLS")
TObjectPtr<ACharacter> OwnerCharacter;
/** @brief SLS 核心角色运动组件。 */
UPROPERTY(Transient, BlueprintReadOnly, Category="PHY|Locomotion|SLS")
TObjectPtr<USLSCharacterMovementComponent> SLSCharacterMovementComponent;
/** @brief GenericGameSystem 提供的可选集成入口。 */
UPROPERTY(Transient, BlueprintReadOnly, Category="PHY|Locomotion|SLS")
TObjectPtr<UActorComponent> GenericIntegrationComponent;
/** @brief 桥接初始化状态。 */
UPROPERTY(Transient, BlueprintReadOnly, Category="PHY|Locomotion|SLS")
bool bInitialized = false;
};