diff --git a/Source/PHY/PHY.Build.cs b/Source/PHY/PHY.Build.cs index 5ef1d6b..79e783c 100644 --- a/Source/PHY/PHY.Build.cs +++ b/Source/PHY/PHY.Build.cs @@ -24,6 +24,7 @@ public class PHY : ModuleRules "GenericInputSystem", "GenericGameSystem", "GenericEffectsSystem", + "SmoothLocomotionSystem", "AuroraDevs_UGC", "IKRig", "AIModule" diff --git a/Source/PHY/Private/Characters/PHYCharacterBase.cpp b/Source/PHY/Private/Characters/PHYCharacterBase.cpp index 2573cb4..354d2ab 100644 --- a/Source/PHY/Private/Characters/PHYCharacterBase.cpp +++ b/Source/PHY/Private/Characters/PHYCharacterBase.cpp @@ -17,14 +17,16 @@ #include "GGA_AbilitySystemComponent.h" #include "GameFramework/CharacterMovementComponent.h" #include "Interaction/GGS_InteractionSystemComponent.h" +#include "Locomotion/PHYSLSMovementBridgeComponent.h" #include "Net/UnrealNetwork.h" #include "PHYGameplayTags.h" #include "Ragdoll/GGS_RagdollComponent.h" +#include "Components/SLSCharacterMovementComponent.h" #include "Targeting/GCS_TargetingSystemComponent.h" #include "Team/GCS_CombatTeamAgentComponent.h" APHYCharacterBase::APHYCharacterBase(const FObjectInitializer& ObjectInitializer) - : Super(ObjectInitializer) + : Super(ObjectInitializer.SetDefaultSubobjectClass(ACharacter::CharacterMovementComponentName)) { bReplicates = true; @@ -36,6 +38,18 @@ APHYCharacterBase::APHYCharacterBase(const FObjectInitializer& ObjectInitializer RagdollComponent = CreateDefaultSubobject(TEXT("RagdollComponent")); ContextEffectComponent = CreateDefaultSubobject(TEXT("ContextEffectComponent")); MeshBridgeComponent = CreateDefaultSubobject(TEXT("MeshBridgeComponent")); + SLSMovementBridgeComponent = CreateDefaultSubobject(TEXT("SLSMovementBridgeComponent")); + + if (UClass* GenericIntegrationClass = FindObject(nullptr, TEXT("/Script/GenericGameSystem.GenericIntegrationComponent"))) + { + GenericIntegrationComponent = Cast(CreateDefaultSubobject( + TEXT("GenericIntegrationComponent"), + UActorComponent::StaticClass(), + GenericIntegrationClass, + false, + false)); + } + DisplayMeshComponent = CreateDefaultSubobject(TEXT("DisplayMeshComponent")); DisplayMeshComponent->SetupAttachment(GetMesh()); DisplayMeshComponent->SetCollisionEnabled(ECollisionEnabled::NoCollision); @@ -70,6 +84,11 @@ void APHYCharacterBase::BeginPlay() ContextEffectComponent->SetGameplayTagsProvider(this); } + if (SLSMovementBridgeComponent) + { + SLSMovementBridgeComponent->InitializeSLSMovementBridge(this, GenericIntegrationComponent); + } + UGameFrameworkComponentManager::SendGameFrameworkComponentExtensionEvent(this, UGameFrameworkComponentManager::NAME_GameActorReady); } @@ -181,6 +200,11 @@ bool APHYCharacterBase::HandleInputTag(const FGameplayTag InputTag, const ETrigg if (InputTag == PHYGameplayTags::Input_Sprint) { + if (USLSCharacterMovementComponent* SLSMovementComponent = GetSLSCharacterMovementComponent()) + { + SLSMovementComponent->UpdateMovementType(bPressed ? ESLSMovementType::Sprint : ESLSMovementType::Jog); + } + if (CharacterStateComponent) { 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 (USLSCharacterMovementComponent* SLSMovementComponent = GetSLSCharacterMovementComponent()) + { + SLSMovementComponent->UpdateRotationMode(bPressed ? ESLSRotationMode::AimingDirection : ESLSRotationMode::VelocityDirection); + } + if (CharacterStateComponent) { 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; } +USLSCharacterMovementComponent* APHYCharacterBase::GetSLSCharacterMovementComponent() const +{ + return Cast(GetCharacterMovement()); +} + void APHYCharacterBase::SetMovementIntent(const FVector NewMovementIntent) { const FVector ClampedIntent = NewMovementIntent.GetClampedToMaxSize(1.0f); diff --git a/Source/PHY/Private/Locomotion/PHYSLSMovementBridgeComponent.cpp b/Source/PHY/Private/Locomotion/PHYSLSMovementBridgeComponent.cpp new file mode 100644 index 0000000..889444b --- /dev/null +++ b/Source/PHY/Private/Locomotion/PHYSLSMovementBridgeComponent.cpp @@ -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(); + if (!LocomotionSettings || !LocomotionSettings->bUseSmoothLocomotionSystem || !OwnerCharacter) + { + return false; + } + + SLSCharacterMovementComponent = Cast(OwnerCharacter->GetCharacterMovement()); + if (!SLSCharacterMovementComponent) + { + return false; + } + + const UPHYCharacterSettings* CharacterSettings = GetDefault(); + + // 首期由项目侧显式初始化,避免依赖 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; +} diff --git a/Source/PHY/Public/Characters/PHYCharacterBase.h b/Source/PHY/Public/Characters/PHYCharacterBase.h index 9ef1385..924f9f7 100644 --- a/Source/PHY/Public/Characters/PHYCharacterBase.h +++ b/Source/PHY/Public/Characters/PHYCharacterBase.h @@ -19,7 +19,9 @@ class UGGS_InteractionSystemComponent; class UGGS_RagdollComponent; class UPHYCharacterMeshBridgeComponent; class UPHYCharacterStateComponent; +class UPHYSLSMovementBridgeComponent; class USkeletalMeshComponent; +class USLSCharacterMovementComponent; /** * @brief PHY 玩家和 AI 共用角色基类。 @@ -124,6 +126,18 @@ public: UFUNCTION(BlueprintCallable, BlueprintPure, Category="PHY|Character|Animation") 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 应应用到该组件。 */ UFUNCTION(BlueprintCallable, BlueprintPure, Category="PHY|Character|Animation") USkeletalMeshComponent* GetDisplayMeshComponent() const { return DisplayMeshComponent; } @@ -248,6 +262,14 @@ protected: UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="PHY|Character|Animation") TObjectPtr MeshBridgeComponent; + /** @brief PHY 对 SLS 运动系统的桥接组件。 */ + UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="PHY|Character|Locomotion") + TObjectPtr SLSMovementBridgeComponent; + + /** @brief GenericGameSystem 可选集成入口组件。 */ + UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="PHY|Character|Locomotion") + TObjectPtr GenericIntegrationComponent; + /** @brief 显示层 Mesh 组件,承载职业和外观 Mesh。 */ UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="PHY|Character|Animation") TObjectPtr DisplayMeshComponent; diff --git a/Source/PHY/Public/Locomotion/PHYSLSMovementBridgeComponent.h b/Source/PHY/Public/Locomotion/PHYSLSMovementBridgeComponent.h new file mode 100644 index 0000000..4b16f2c --- /dev/null +++ b/Source/PHY/Public/Locomotion/PHYSLSMovementBridgeComponent.h @@ -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 OwnerCharacter; + + /** @brief SLS 核心角色运动组件。 */ + UPROPERTY(Transient, BlueprintReadOnly, Category="PHY|Locomotion|SLS") + TObjectPtr SLSCharacterMovementComponent; + + /** @brief GenericGameSystem 提供的可选集成入口。 */ + UPROPERTY(Transient, BlueprintReadOnly, Category="PHY|Locomotion|SLS") + TObjectPtr GenericIntegrationComponent; + + /** @brief 桥接初始化状态。 */ + UPROPERTY(Transient, BlueprintReadOnly, Category="PHY|Locomotion|SLS") + bool bInitialized = false; +};