Add PHY character framework
This commit is contained in:
7
Config/DefaultPHYCharacter.ini
Normal file
7
Config/DefaultPHYCharacter.ini
Normal file
@@ -0,0 +1,7 @@
|
||||
[/Script/PHY.PHYCharacterSettings]
|
||||
bEnableGenericGameInteraction=True
|
||||
bEnableContextEffects=True
|
||||
DefaultMaxWalkSpeed=500.000000
|
||||
DefaultSprintSpeed=650.000000
|
||||
DefaultMaxAcceleration=2048.000000
|
||||
DefaultInteractionOption=0
|
||||
10
PHY.uproject
10
PHY.uproject
@@ -18,6 +18,14 @@
|
||||
"Editor"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "GameplayAbilities",
|
||||
"Enabled": true
|
||||
},
|
||||
{
|
||||
"Name": "ModularGameplay",
|
||||
"Enabled": true
|
||||
},
|
||||
{
|
||||
"Name": "GenericCombatSystem",
|
||||
"Enabled": true,
|
||||
@@ -47,4 +55,4 @@
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,25 @@ public class PHY : ModuleRules
|
||||
{
|
||||
PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
|
||||
|
||||
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "EnhancedInput", "GameplayTags" });
|
||||
PublicDependencyModuleNames.AddRange(new string[]
|
||||
{
|
||||
"Core",
|
||||
"CoreUObject",
|
||||
"Engine",
|
||||
"InputCore",
|
||||
"EnhancedInput",
|
||||
"GameplayTags",
|
||||
"GameplayAbilities",
|
||||
"GameplayTasks",
|
||||
"ModularGameplay",
|
||||
"GenericGameplayAbilities",
|
||||
"GenericCombatSystem",
|
||||
"GenericInputSystem",
|
||||
"GenericGameSystem",
|
||||
"GenericEffectsSystem",
|
||||
"AuroraDevs_UGC",
|
||||
"AIModule"
|
||||
});
|
||||
|
||||
PrivateDependencyModuleNames.AddRange(new string[] { });
|
||||
|
||||
|
||||
41
Source/PHY/Private/AI/PHYAIController.cpp
Normal file
41
Source/PHY/Private/AI/PHYAIController.cpp
Normal file
@@ -0,0 +1,41 @@
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#include "AI/PHYAIController.h"
|
||||
|
||||
#include UE_INLINE_GENERATED_CPP_BY_NAME(PHYAIController)
|
||||
|
||||
#include "AbilitySystemComponent.h"
|
||||
#include "Characters/PHYAICharacter.h"
|
||||
|
||||
APHYAICharacter* APHYAIController::GetPHYAICharacter() const
|
||||
{
|
||||
return Cast<APHYAICharacter>(GetPawn());
|
||||
}
|
||||
|
||||
bool APHYAIController::RequestInteraction(const int32 OptionIndex)
|
||||
{
|
||||
APHYAICharacter* PHYCharacter = GetPHYAICharacter();
|
||||
return PHYCharacter ? PHYCharacter->RequestInteraction(OptionIndex) : false;
|
||||
}
|
||||
|
||||
void APHYAIController::SetCombatTarget(AActor* TargetActor)
|
||||
{
|
||||
if (APHYAICharacter* PHYCharacter = GetPHYAICharacter())
|
||||
{
|
||||
PHYCharacter->SetCombatTargetActor(TargetActor);
|
||||
}
|
||||
}
|
||||
|
||||
bool APHYAIController::ActivateAbilityByTag(const FGameplayTag AbilityTag)
|
||||
{
|
||||
APHYAICharacter* PHYCharacter = GetPHYAICharacter();
|
||||
UAbilitySystemComponent* AbilitySystemComponent = PHYCharacter ? PHYCharacter->GetAbilitySystemComponent() : nullptr;
|
||||
if (!AbilitySystemComponent || !AbilityTag.IsValid())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
FGameplayTagContainer AbilityTags;
|
||||
AbilityTags.AddTag(AbilityTag);
|
||||
return AbilitySystemComponent->TryActivateAbilitiesByTag(AbilityTags);
|
||||
}
|
||||
7
Source/PHY/Private/Camera/PHYUGCSpringArmComponent.cpp
Normal file
7
Source/PHY/Private/Camera/PHYUGCSpringArmComponent.cpp
Normal file
@@ -0,0 +1,7 @@
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#include "Camera/PHYUGCSpringArmComponent.h"
|
||||
|
||||
#include UE_INLINE_GENERATED_CPP_BY_NAME(PHYUGCSpringArmComponent)
|
||||
|
||||
// 当前包装层只解除抽象限制,后续相机专家可在这里集中扩展 UGC 项目逻辑。
|
||||
37
Source/PHY/Private/Characters/PHYAICharacter.cpp
Normal file
37
Source/PHY/Private/Characters/PHYAICharacter.cpp
Normal file
@@ -0,0 +1,37 @@
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#include "Characters/PHYAICharacter.h"
|
||||
|
||||
#include UE_INLINE_GENERATED_CPP_BY_NAME(PHYAICharacter)
|
||||
|
||||
#include "GGA_AbilitySystemComponent.h"
|
||||
|
||||
APHYAICharacter::APHYAICharacter(const FObjectInitializer& ObjectInitializer)
|
||||
: Super(ObjectInitializer)
|
||||
{
|
||||
AbilitySystemComponent = CreateDefaultSubobject<UGGA_AbilitySystemComponent>(TEXT("AbilitySystemComponent"));
|
||||
AbilitySystemComponent->SetIsReplicated(true);
|
||||
AbilitySystemComponent->SetReplicationMode(EGameplayEffectReplicationMode::Mixed);
|
||||
}
|
||||
|
||||
void APHYAICharacter::BeginPlay()
|
||||
{
|
||||
Super::BeginPlay();
|
||||
|
||||
InitializeAIAbilitySystem();
|
||||
}
|
||||
|
||||
void APHYAICharacter::PossessedBy(AController* NewController)
|
||||
{
|
||||
Super::PossessedBy(NewController);
|
||||
|
||||
InitializeAIAbilitySystem();
|
||||
}
|
||||
|
||||
void APHYAICharacter::InitializeAIAbilitySystem()
|
||||
{
|
||||
if (AbilitySystemComponent)
|
||||
{
|
||||
InitializeAbilitySystem(AbilitySystemComponent, this);
|
||||
}
|
||||
}
|
||||
580
Source/PHY/Private/Characters/PHYCharacterBase.cpp
Normal file
580
Source/PHY/Private/Characters/PHYCharacterBase.cpp
Normal file
@@ -0,0 +1,580 @@
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#include "Characters/PHYCharacterBase.h"
|
||||
|
||||
#include UE_INLINE_GENERATED_CPP_BY_NAME(PHYCharacterBase)
|
||||
|
||||
#include "AbilitySystemComponent.h"
|
||||
#include "Camera/CameraComponent.h"
|
||||
#include "Characters/PHYCharacterSettings.h"
|
||||
#include "Characters/PHYCharacterStateComponent.h"
|
||||
#include "Components/CapsuleComponent.h"
|
||||
#include "Components/GameFrameworkComponentManager.h"
|
||||
#include "Components/SkeletalMeshComponent.h"
|
||||
#include "Feedback/GES_ContextEffectComponent.h"
|
||||
#include "GCS_CombatSystemComponent.h"
|
||||
#include "GGA_AbilitySystemComponent.h"
|
||||
#include "GameFramework/CharacterMovementComponent.h"
|
||||
#include "Interaction/GGS_InteractionSystemComponent.h"
|
||||
#include "Net/UnrealNetwork.h"
|
||||
#include "PHYGameplayTags.h"
|
||||
#include "Ragdoll/GGS_RagdollComponent.h"
|
||||
#include "Targeting/GCS_TargetingSystemComponent.h"
|
||||
#include "Team/GCS_CombatTeamAgentComponent.h"
|
||||
|
||||
APHYCharacterBase::APHYCharacterBase(const FObjectInitializer& ObjectInitializer)
|
||||
: Super(ObjectInitializer)
|
||||
{
|
||||
bReplicates = true;
|
||||
|
||||
CharacterStateComponent = CreateDefaultSubobject<UPHYCharacterStateComponent>(TEXT("CharacterStateComponent"));
|
||||
CombatSystemComponent = CreateDefaultSubobject<UGCS_CombatSystemComponent>(TEXT("CombatSystemComponent"));
|
||||
TargetingSystemComponent = CreateDefaultSubobject<UGCS_TargetingSystemComponent>(TEXT("TargetingSystemComponent"));
|
||||
CombatTeamAgentComponent = CreateDefaultSubobject<UGCS_CombatTeamAgentComponent>(TEXT("CombatTeamAgentComponent"));
|
||||
InteractionSystemComponent = CreateDefaultSubobject<UGGS_InteractionSystemComponent>(TEXT("InteractionSystemComponent"));
|
||||
RagdollComponent = CreateDefaultSubobject<UGGS_RagdollComponent>(TEXT("RagdollComponent"));
|
||||
ContextEffectComponent = CreateDefaultSubobject<UGES_ContextEffectComponent>(TEXT("ContextEffectComponent"));
|
||||
}
|
||||
|
||||
void APHYCharacterBase::PreInitializeComponents()
|
||||
{
|
||||
Super::PreInitializeComponents();
|
||||
|
||||
UGameFrameworkComponentManager::AddGameFrameworkComponentReceiver(this);
|
||||
}
|
||||
|
||||
void APHYCharacterBase::BeginPlay()
|
||||
{
|
||||
Super::BeginPlay();
|
||||
|
||||
ApplyCharacterSettings();
|
||||
|
||||
if (RagdollComponent)
|
||||
{
|
||||
RagdollComponent->SetMeshComponent(GetMesh());
|
||||
}
|
||||
|
||||
if (ContextEffectComponent)
|
||||
{
|
||||
ContextEffectComponent->SetGameplayTagsProvider(this);
|
||||
}
|
||||
|
||||
UGameFrameworkComponentManager::SendGameFrameworkComponentExtensionEvent(this, UGameFrameworkComponentManager::NAME_GameActorReady);
|
||||
}
|
||||
|
||||
void APHYCharacterBase::EndPlay(const EEndPlayReason::Type EndPlayReason)
|
||||
{
|
||||
UGameFrameworkComponentManager::RemoveGameFrameworkComponentReceiver(this);
|
||||
|
||||
Super::EndPlay(EndPlayReason);
|
||||
}
|
||||
|
||||
void APHYCharacterBase::PossessedBy(AController* NewController)
|
||||
{
|
||||
Super::PossessedBy(NewController);
|
||||
|
||||
if (CharacterStateComponent)
|
||||
{
|
||||
CharacterStateComponent->SetMovementIntent(FVector::ZeroVector);
|
||||
}
|
||||
}
|
||||
|
||||
void APHYCharacterBase::OnRep_Controller()
|
||||
{
|
||||
Super::OnRep_Controller();
|
||||
|
||||
if (CharacterStateComponent)
|
||||
{
|
||||
CharacterStateComponent->SetMovementIntent(FVector::ZeroVector);
|
||||
}
|
||||
}
|
||||
|
||||
UAbilitySystemComponent* APHYCharacterBase::GetAbilitySystemComponent() const
|
||||
{
|
||||
return CachedAbilitySystemComponent;
|
||||
}
|
||||
|
||||
void APHYCharacterBase::GetOwnedGameplayTags(FGameplayTagContainer& TagContainer) const
|
||||
{
|
||||
if (CachedAbilitySystemComponent)
|
||||
{
|
||||
CachedAbilitySystemComponent->GetOwnedGameplayTags(TagContainer);
|
||||
}
|
||||
|
||||
if (CharacterStateComponent)
|
||||
{
|
||||
CharacterStateComponent->GetOwnedStateTags(TagContainer);
|
||||
}
|
||||
}
|
||||
|
||||
void APHYCharacterBase::InitializeAbilitySystem(UAbilitySystemComponent* NewAbilitySystemComponent, AActor* OwnerActor)
|
||||
{
|
||||
if (!NewAbilitySystemComponent || !OwnerActor)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (CachedAbilitySystemComponent == NewAbilitySystemComponent && bAbilitySystemReady)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
CachedAbilitySystemComponent = NewAbilitySystemComponent;
|
||||
|
||||
if (UGGA_AbilitySystemComponent* GGAAbilitySystemComponent = Cast<UGGA_AbilitySystemComponent>(NewAbilitySystemComponent))
|
||||
{
|
||||
GGAAbilitySystemComponent->InitializeAbilitySystem(OwnerActor, this);
|
||||
}
|
||||
else
|
||||
{
|
||||
NewAbilitySystemComponent->InitAbilityActorInfo(OwnerActor, this);
|
||||
}
|
||||
|
||||
bAbilitySystemReady = true;
|
||||
}
|
||||
|
||||
void APHYCharacterBase::ClearAbilitySystem()
|
||||
{
|
||||
if (UGGA_AbilitySystemComponent* GGAAbilitySystemComponent = Cast<UGGA_AbilitySystemComponent>(CachedAbilitySystemComponent))
|
||||
{
|
||||
GGAAbilitySystemComponent->UninitializeAbilitySystem();
|
||||
}
|
||||
|
||||
CachedAbilitySystemComponent = nullptr;
|
||||
bAbilitySystemReady = false;
|
||||
}
|
||||
|
||||
bool APHYCharacterBase::HandleInputTag(const FGameplayTag InputTag, const ETriggerEvent TriggerEvent)
|
||||
{
|
||||
if (!InputTag.IsValid() || IGCS_CombatEntityInterface::Execute_IsDead(this))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const bool bPressed = TriggerEvent == ETriggerEvent::Started || TriggerEvent == ETriggerEvent::Triggered;
|
||||
const bool bReleased = TriggerEvent == ETriggerEvent::Completed || TriggerEvent == ETriggerEvent::Canceled;
|
||||
|
||||
if (InputTag == PHYGameplayTags::Input_Jump)
|
||||
{
|
||||
if (bPressed)
|
||||
{
|
||||
Jump();
|
||||
}
|
||||
else if (bReleased)
|
||||
{
|
||||
StopJumping();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (InputTag == PHYGameplayTags::Input_Sprint)
|
||||
{
|
||||
if (CharacterStateComponent)
|
||||
{
|
||||
CharacterStateComponent->SetMovementState(bPressed ? PHYGameplayTags::State_Movement_Sprint : PHYGameplayTags::State_Movement_Run);
|
||||
}
|
||||
|
||||
if (UCharacterMovementComponent* MoveComponent = GetCharacterMovement())
|
||||
{
|
||||
const UPHYCharacterSettings* Settings = GetDefault<UPHYCharacterSettings>();
|
||||
MoveComponent->MaxWalkSpeed = bPressed ? Settings->DefaultSprintSpeed : Settings->DefaultMaxWalkSpeed;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (InputTag == PHYGameplayTags::Input_Aim)
|
||||
{
|
||||
if (CharacterStateComponent)
|
||||
{
|
||||
CharacterStateComponent->SetMovementSet(bPressed ? PHYGameplayTags::State_MovementSet_Aiming : PHYGameplayTags::State_MovementSet_Default);
|
||||
CharacterStateComponent->SetRotationMode(bPressed ? PHYGameplayTags::State_Rotation_Strafe : PHYGameplayTags::State_Rotation_OrientToMovement);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (InputTag == PHYGameplayTags::Input_LockOn && bPressed)
|
||||
{
|
||||
if (TargetingSystemComponent)
|
||||
{
|
||||
if (TargetingSystemComponent->GetTargetedActor())
|
||||
{
|
||||
SetCombatTargetActor(nullptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
TargetingSystemComponent->SearchForActorToTarget();
|
||||
SetCombatTargetActor(TargetingSystemComponent->GetTargetedActor());
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (InputTag == PHYGameplayTags::Input_Interact && bPressed)
|
||||
{
|
||||
const UPHYCharacterSettings* Settings = GetDefault<UPHYCharacterSettings>();
|
||||
return RequestInteraction(Settings->DefaultInteractionOption);
|
||||
}
|
||||
|
||||
const FGameplayTag AbilityTag = GetAbilityTagForInputTag(InputTag);
|
||||
if (AbilityTag.IsValid() && bPressed && CachedAbilitySystemComponent)
|
||||
{
|
||||
FGameplayTagContainer AbilityTags;
|
||||
AbilityTags.AddTag(AbilityTag);
|
||||
return CachedAbilitySystemComponent->TryActivateAbilitiesByTag(AbilityTags);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void APHYCharacterBase::SetMovementIntent(const FVector NewMovementIntent)
|
||||
{
|
||||
const FVector ClampedIntent = NewMovementIntent.GetClampedToMaxSize(1.0f);
|
||||
|
||||
if (CharacterStateComponent)
|
||||
{
|
||||
CharacterStateComponent->SetMovementIntent(ClampedIntent);
|
||||
}
|
||||
|
||||
if (!HasAuthority())
|
||||
{
|
||||
ServerSetMovementIntent(ClampedIntent);
|
||||
}
|
||||
}
|
||||
|
||||
void APHYCharacterBase::SetCombatTargetActor(AActor* NewCombatTargetActor)
|
||||
{
|
||||
if (CharacterStateComponent)
|
||||
{
|
||||
CharacterStateComponent->SetCombatTargetActor(NewCombatTargetActor);
|
||||
}
|
||||
|
||||
if (TargetingSystemComponent)
|
||||
{
|
||||
TargetingSystemComponent->SetTargetedActor(NewCombatTargetActor);
|
||||
}
|
||||
|
||||
if (!HasAuthority())
|
||||
{
|
||||
ServerSetCombatTargetActor(NewCombatTargetActor);
|
||||
}
|
||||
}
|
||||
|
||||
bool APHYCharacterBase::RequestInteraction(const int32 OptionIndex)
|
||||
{
|
||||
const UPHYCharacterSettings* Settings = GetDefault<UPHYCharacterSettings>();
|
||||
if (!Settings->bEnableGenericGameInteraction || !InteractionSystemComponent)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!HasAuthority())
|
||||
{
|
||||
ServerRequestInteraction(OptionIndex);
|
||||
return true;
|
||||
}
|
||||
|
||||
InteractionSystemComponent->SearchInteractableActors();
|
||||
InteractionSystemComponent->StartInteraction(OptionIndex);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool APHYCharacterBase::RequestInstantInteraction(const int32 OptionIndex)
|
||||
{
|
||||
const UPHYCharacterSettings* Settings = GetDefault<UPHYCharacterSettings>();
|
||||
if (!Settings->bEnableGenericGameInteraction || !InteractionSystemComponent)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!HasAuthority())
|
||||
{
|
||||
ServerRequestInstantInteraction(OptionIndex);
|
||||
return true;
|
||||
}
|
||||
|
||||
InteractionSystemComponent->SearchInteractableActors();
|
||||
InteractionSystemComponent->InstantInteraction(OptionIndex);
|
||||
return true;
|
||||
}
|
||||
|
||||
void APHYCharacterBase::EndInteraction()
|
||||
{
|
||||
if (!InteractionSystemComponent)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!HasAuthority())
|
||||
{
|
||||
ServerEndInteraction();
|
||||
return;
|
||||
}
|
||||
|
||||
InteractionSystemComponent->EndInteraction();
|
||||
}
|
||||
|
||||
void APHYCharacterBase::CycleInteractionTarget(const bool bNext)
|
||||
{
|
||||
if (!InteractionSystemComponent)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!HasAuthority())
|
||||
{
|
||||
ServerCycleInteractionTarget(bNext);
|
||||
return;
|
||||
}
|
||||
|
||||
InteractionSystemComponent->CycleInteractableActors(bNext);
|
||||
}
|
||||
|
||||
AActor* APHYCharacterBase::GetCombatTargetActor_Implementation() const
|
||||
{
|
||||
if (CharacterStateComponent && CharacterStateComponent->GetCombatTargetActor())
|
||||
{
|
||||
return CharacterStateComponent->GetCombatTargetActor();
|
||||
}
|
||||
|
||||
return TargetingSystemComponent ? TargetingSystemComponent->GetTargetedActor() : nullptr;
|
||||
}
|
||||
|
||||
const UDataTable* APHYCharacterBase::GetComboDefinitionTable_Implementation() const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
USceneComponent* APHYCharacterBase::GetCombatTargetObject_Implementation() const
|
||||
{
|
||||
const AActor* TargetActor = IGCS_CombatEntityInterface::Execute_GetCombatTargetActor(this);
|
||||
return TargetActor ? TargetActor->GetRootComponent() : nullptr;
|
||||
}
|
||||
|
||||
bool APHYCharacterBase::QueryAbilityActions_Implementation(FGameplayTagContainer AbilityTags, FGameplayTagContainer SourceTags, FGameplayTagContainer TargetTags, TArray<FGCS_AbilityAction>& AbilityActions)
|
||||
{
|
||||
(void)AbilityTags;
|
||||
(void)SourceTags;
|
||||
(void)TargetTags;
|
||||
AbilityActions.Reset();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool APHYCharacterBase::QueryAbilityActionsByContext_Implementation(UObject* Context, FGameplayTagContainer AbilityTags, FGameplayTagContainer SourceTags, FGameplayTagContainer TargetTags, TArray<FGCS_AbilityAction>& AbilityActions)
|
||||
{
|
||||
(void)Context;
|
||||
(void)AbilityTags;
|
||||
(void)SourceTags;
|
||||
(void)TargetTags;
|
||||
AbilityActions.Reset();
|
||||
return false;
|
||||
}
|
||||
|
||||
UObject* APHYCharacterBase::QueryWeapon_Implementation(const FGameplayTagQuery& Query) const
|
||||
{
|
||||
UObject* Weapon = CharacterStateComponent ? CharacterStateComponent->GetCurrentWeapon() : nullptr;
|
||||
if (!Weapon || Query.IsEmpty())
|
||||
{
|
||||
return Weapon;
|
||||
}
|
||||
|
||||
if (const IGameplayTagAssetInterface* WeaponTagsProvider = Cast<IGameplayTagAssetInterface>(Weapon))
|
||||
{
|
||||
FGameplayTagContainer WeaponTags;
|
||||
WeaponTagsProvider->GetOwnedGameplayTags(WeaponTags);
|
||||
return Query.Matches(WeaponTags) ? Weapon : nullptr;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void APHYCharacterBase::SetRotationMode_Implementation(const FGameplayTag NewRotationMode)
|
||||
{
|
||||
if (CharacterStateComponent)
|
||||
{
|
||||
CharacterStateComponent->SetRotationMode(NewRotationMode);
|
||||
}
|
||||
}
|
||||
|
||||
FGameplayTag APHYCharacterBase::GetRotationMode_Implementation() const
|
||||
{
|
||||
return CharacterStateComponent ? CharacterStateComponent->GetRotationMode() : FGameplayTag();
|
||||
}
|
||||
|
||||
void APHYCharacterBase::SetMovementSet_Implementation(const FGameplayTag NewMovementSet)
|
||||
{
|
||||
if (CharacterStateComponent)
|
||||
{
|
||||
CharacterStateComponent->SetMovementSet(NewMovementSet);
|
||||
}
|
||||
}
|
||||
|
||||
FGameplayTag APHYCharacterBase::GetMovementSet_Implementation() const
|
||||
{
|
||||
return CharacterStateComponent ? CharacterStateComponent->GetMovementSet() : FGameplayTag();
|
||||
}
|
||||
|
||||
void APHYCharacterBase::SetMovementState_Implementation(const FGameplayTag NewMovementState)
|
||||
{
|
||||
if (CharacterStateComponent)
|
||||
{
|
||||
CharacterStateComponent->SetMovementState(NewMovementState);
|
||||
}
|
||||
}
|
||||
|
||||
FGameplayTag APHYCharacterBase::GetMovementState_Implementation() const
|
||||
{
|
||||
return CharacterStateComponent ? CharacterStateComponent->GetMovementState() : FGameplayTag();
|
||||
}
|
||||
|
||||
void APHYCharacterBase::StartDeath_Implementation()
|
||||
{
|
||||
if (CharacterStateComponent && CharacterStateComponent->IsDead())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (CharacterStateComponent)
|
||||
{
|
||||
CharacterStateComponent->SetDead(true);
|
||||
}
|
||||
|
||||
if (CachedAbilitySystemComponent)
|
||||
{
|
||||
CachedAbilitySystemComponent->CancelAllAbilities();
|
||||
}
|
||||
|
||||
if (UCharacterMovementComponent* MoveComponent = GetCharacterMovement())
|
||||
{
|
||||
MoveComponent->DisableMovement();
|
||||
}
|
||||
|
||||
if (UCapsuleComponent* Capsule = GetCapsuleComponent())
|
||||
{
|
||||
Capsule->SetCollisionEnabled(ECollisionEnabled::NoCollision);
|
||||
}
|
||||
}
|
||||
|
||||
void APHYCharacterBase::FinishDeath_Implementation()
|
||||
{
|
||||
if (RagdollComponent && !RagdollComponent->IsRagdolling())
|
||||
{
|
||||
RagdollComponent->StartRagdoll();
|
||||
}
|
||||
}
|
||||
|
||||
bool APHYCharacterBase::IsDead_Implementation() const
|
||||
{
|
||||
return CharacterStateComponent && CharacterStateComponent->IsDead();
|
||||
}
|
||||
|
||||
FVector APHYCharacterBase::GetMovementIntent_Implementation() const
|
||||
{
|
||||
return CharacterStateComponent ? CharacterStateComponent->GetMovementIntent() : FVector::ZeroVector;
|
||||
}
|
||||
|
||||
UObject* APHYCharacterBase::GetCurrentWeapon_Implementation(UObject* Context) const
|
||||
{
|
||||
(void)Context;
|
||||
return CharacterStateComponent ? CharacterStateComponent->GetCurrentWeapon() : nullptr;
|
||||
}
|
||||
|
||||
void APHYCharacterBase::SetCurrentWeapon_Implementation(UObject* Weapon)
|
||||
{
|
||||
if (CharacterStateComponent)
|
||||
{
|
||||
CharacterStateComponent->SetCurrentWeapon(Weapon);
|
||||
}
|
||||
}
|
||||
|
||||
bool APHYCharacterBase::GetRelativeTransformToSocket_Implementation(const USkeletalMeshComponent* InSkeletalMeshComponent, const UStaticMesh* StaticMesh, const USkeletalMesh* SkeletalMesh, const FName SocketName, FTransform& OutTransform) const
|
||||
{
|
||||
(void)StaticMesh;
|
||||
(void)SkeletalMesh;
|
||||
|
||||
if (!InSkeletalMeshComponent || SocketName.IsNone() || !InSkeletalMeshComponent->DoesSocketExist(SocketName))
|
||||
{
|
||||
OutTransform = FTransform::Identity;
|
||||
return false;
|
||||
}
|
||||
|
||||
OutTransform = InSkeletalMeshComponent->GetSocketTransform(SocketName, RTS_Component);
|
||||
return true;
|
||||
}
|
||||
|
||||
FGameplayTag APHYCharacterBase::GetAbilityTagForInputTag(const FGameplayTag InputTag) const
|
||||
{
|
||||
if (InputTag == PHYGameplayTags::Input_Attack_Primary)
|
||||
{
|
||||
return PHYGameplayTags::Ability_Attack_Primary;
|
||||
}
|
||||
|
||||
if (InputTag == PHYGameplayTags::Input_Attack_Secondary)
|
||||
{
|
||||
return PHYGameplayTags::Ability_Attack_Secondary;
|
||||
}
|
||||
|
||||
if (InputTag == PHYGameplayTags::Input_Jump)
|
||||
{
|
||||
return PHYGameplayTags::Ability_Jump;
|
||||
}
|
||||
|
||||
if (InputTag == PHYGameplayTags::Input_Interact)
|
||||
{
|
||||
return PHYGameplayTags::Ability_Interact;
|
||||
}
|
||||
|
||||
return FGameplayTag();
|
||||
}
|
||||
|
||||
void APHYCharacterBase::ApplyCharacterSettings()
|
||||
{
|
||||
const UPHYCharacterSettings* Settings = GetDefault<UPHYCharacterSettings>();
|
||||
|
||||
if (UCharacterMovementComponent* MoveComponent = GetCharacterMovement())
|
||||
{
|
||||
MoveComponent->MaxWalkSpeed = Settings->DefaultMaxWalkSpeed;
|
||||
MoveComponent->MaxAcceleration = Settings->DefaultMaxAcceleration;
|
||||
}
|
||||
|
||||
if (CharacterStateComponent && GetCharacterMovement() && GetCharacterMovement()->IsFalling())
|
||||
{
|
||||
CharacterStateComponent->SetMovementState(PHYGameplayTags::State_Movement_Falling);
|
||||
}
|
||||
}
|
||||
|
||||
void APHYCharacterBase::ServerSetMovementIntent_Implementation(const FVector NewMovementIntent)
|
||||
{
|
||||
if (CharacterStateComponent)
|
||||
{
|
||||
CharacterStateComponent->SetMovementIntent(NewMovementIntent);
|
||||
}
|
||||
}
|
||||
|
||||
void APHYCharacterBase::ServerSetCombatTargetActor_Implementation(AActor* NewCombatTargetActor)
|
||||
{
|
||||
SetCombatTargetActor(NewCombatTargetActor);
|
||||
}
|
||||
|
||||
void APHYCharacterBase::ServerRequestInteraction_Implementation(const int32 OptionIndex)
|
||||
{
|
||||
RequestInteraction(OptionIndex);
|
||||
}
|
||||
|
||||
void APHYCharacterBase::ServerRequestInstantInteraction_Implementation(const int32 OptionIndex)
|
||||
{
|
||||
RequestInstantInteraction(OptionIndex);
|
||||
}
|
||||
|
||||
void APHYCharacterBase::ServerEndInteraction_Implementation()
|
||||
{
|
||||
EndInteraction();
|
||||
}
|
||||
|
||||
void APHYCharacterBase::ServerCycleInteractionTarget_Implementation(const bool bNext)
|
||||
{
|
||||
CycleInteractionTarget(bNext);
|
||||
}
|
||||
7
Source/PHY/Private/Characters/PHYCharacterSettings.cpp
Normal file
7
Source/PHY/Private/Characters/PHYCharacterSettings.cpp
Normal file
@@ -0,0 +1,7 @@
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#include "Characters/PHYCharacterSettings.h"
|
||||
|
||||
#include UE_INLINE_GENERATED_CPP_BY_NAME(PHYCharacterSettings)
|
||||
|
||||
// 角色配置只承载默认值,实际初始化由角色基类按需读取。
|
||||
89
Source/PHY/Private/Characters/PHYCharacterStateComponent.cpp
Normal file
89
Source/PHY/Private/Characters/PHYCharacterStateComponent.cpp
Normal file
@@ -0,0 +1,89 @@
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#include "Characters/PHYCharacterStateComponent.h"
|
||||
|
||||
#include UE_INLINE_GENERATED_CPP_BY_NAME(PHYCharacterStateComponent)
|
||||
|
||||
#include "Net/UnrealNetwork.h"
|
||||
#include "PHYGameplayTags.h"
|
||||
|
||||
UPHYCharacterStateComponent::UPHYCharacterStateComponent(const FObjectInitializer& ObjectInitializer)
|
||||
: Super(ObjectInitializer)
|
||||
{
|
||||
SetIsReplicatedByDefault(true);
|
||||
|
||||
MovementState = PHYGameplayTags::State_Movement_Walk;
|
||||
MovementSet = PHYGameplayTags::State_MovementSet_Default;
|
||||
RotationMode = PHYGameplayTags::State_Rotation_OrientToMovement;
|
||||
}
|
||||
|
||||
void UPHYCharacterStateComponent::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
|
||||
{
|
||||
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
|
||||
|
||||
DOREPLIFETIME(ThisClass, bDead);
|
||||
DOREPLIFETIME(ThisClass, CombatTargetActor);
|
||||
DOREPLIFETIME(ThisClass, CurrentWeapon);
|
||||
DOREPLIFETIME(ThisClass, MovementIntent);
|
||||
DOREPLIFETIME(ThisClass, MovementState);
|
||||
DOREPLIFETIME(ThisClass, MovementSet);
|
||||
DOREPLIFETIME(ThisClass, RotationMode);
|
||||
}
|
||||
|
||||
void UPHYCharacterStateComponent::SetDead(const bool bNewDead)
|
||||
{
|
||||
bDead = bNewDead;
|
||||
}
|
||||
|
||||
void UPHYCharacterStateComponent::SetCombatTargetActor(AActor* NewCombatTargetActor)
|
||||
{
|
||||
CombatTargetActor = NewCombatTargetActor;
|
||||
}
|
||||
|
||||
void UPHYCharacterStateComponent::SetCurrentWeapon(UObject* NewCurrentWeapon)
|
||||
{
|
||||
CurrentWeapon = NewCurrentWeapon;
|
||||
}
|
||||
|
||||
void UPHYCharacterStateComponent::SetMovementIntent(const FVector NewMovementIntent)
|
||||
{
|
||||
MovementIntent = NewMovementIntent.GetClampedToMaxSize(1.0f);
|
||||
}
|
||||
|
||||
void UPHYCharacterStateComponent::SetMovementState(const FGameplayTag NewMovementState)
|
||||
{
|
||||
MovementState = NewMovementState;
|
||||
}
|
||||
|
||||
void UPHYCharacterStateComponent::SetMovementSet(const FGameplayTag NewMovementSet)
|
||||
{
|
||||
MovementSet = NewMovementSet;
|
||||
}
|
||||
|
||||
void UPHYCharacterStateComponent::SetRotationMode(const FGameplayTag NewRotationMode)
|
||||
{
|
||||
RotationMode = NewRotationMode;
|
||||
}
|
||||
|
||||
void UPHYCharacterStateComponent::GetOwnedStateTags(FGameplayTagContainer& OutTags) const
|
||||
{
|
||||
if (bDead)
|
||||
{
|
||||
OutTags.AddTag(PHYGameplayTags::State_Dead);
|
||||
}
|
||||
|
||||
if (MovementState.IsValid())
|
||||
{
|
||||
OutTags.AddTag(MovementState);
|
||||
}
|
||||
|
||||
if (MovementSet.IsValid())
|
||||
{
|
||||
OutTags.AddTag(MovementSet);
|
||||
}
|
||||
|
||||
if (RotationMode.IsValid())
|
||||
{
|
||||
OutTags.AddTag(RotationMode);
|
||||
}
|
||||
}
|
||||
51
Source/PHY/Private/Characters/PHYPlayerCharacter.cpp
Normal file
51
Source/PHY/Private/Characters/PHYPlayerCharacter.cpp
Normal file
@@ -0,0 +1,51 @@
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#include "Characters/PHYPlayerCharacter.h"
|
||||
|
||||
#include UE_INLINE_GENERATED_CPP_BY_NAME(PHYPlayerCharacter)
|
||||
|
||||
#include "Camera/CameraComponent.h"
|
||||
#include "Camera/PHYUGCSpringArmComponent.h"
|
||||
#include "GameFramework/SpringArmComponent.h"
|
||||
#include "Player/PHYPlayerState.h"
|
||||
|
||||
APHYPlayerCharacter::APHYPlayerCharacter(const FObjectInitializer& ObjectInitializer)
|
||||
: Super(ObjectInitializer)
|
||||
{
|
||||
CameraBoom = CreateDefaultSubobject<UPHYUGCSpringArmComponent>(TEXT("CameraBoom"));
|
||||
CameraBoom->SetupAttachment(GetRootComponent());
|
||||
CameraBoom->TargetArmLength = 320.0f;
|
||||
CameraBoom->bUsePawnControlRotation = true;
|
||||
|
||||
FollowCamera = CreateDefaultSubobject<UCameraComponent>(TEXT("FollowCamera"));
|
||||
FollowCamera->SetupAttachment(CameraBoom, USpringArmComponent::SocketName);
|
||||
FollowCamera->bUsePawnControlRotation = false;
|
||||
}
|
||||
|
||||
void APHYPlayerCharacter::PossessedBy(AController* NewController)
|
||||
{
|
||||
Super::PossessedBy(NewController);
|
||||
|
||||
InitializeAbilitySystemFromPlayerState();
|
||||
}
|
||||
|
||||
void APHYPlayerCharacter::OnRep_PlayerState()
|
||||
{
|
||||
Super::OnRep_PlayerState();
|
||||
|
||||
InitializeAbilitySystemFromPlayerState();
|
||||
}
|
||||
|
||||
void APHYPlayerCharacter::InitializeAbilitySystemFromPlayerState()
|
||||
{
|
||||
APHYPlayerState* PHYPlayerState = GetPlayerState<APHYPlayerState>();
|
||||
if (!PHYPlayerState)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (UAbilitySystemComponent* PlayerASC = PHYPlayerState->GetAbilitySystemComponent())
|
||||
{
|
||||
InitializeAbilitySystem(PlayerASC, PHYPlayerState);
|
||||
}
|
||||
}
|
||||
@@ -10,4 +10,13 @@ namespace PHYGameplayTags
|
||||
UE_DEFINE_GAMEPLAY_TAG(State_LockedOn, "State.LockedOn");
|
||||
UE_DEFINE_GAMEPLAY_TAG(State_Interacting, "State.Interacting");
|
||||
UE_DEFINE_GAMEPLAY_TAG(State_UI_Open, "State.UI.Open");
|
||||
UE_DEFINE_GAMEPLAY_TAG(State_Dead, "State.Dead");
|
||||
UE_DEFINE_GAMEPLAY_TAG(State_Movement_Walk, "State.Movement.Walk");
|
||||
UE_DEFINE_GAMEPLAY_TAG(State_Movement_Run, "State.Movement.Run");
|
||||
UE_DEFINE_GAMEPLAY_TAG(State_Movement_Sprint, "State.Movement.Sprint");
|
||||
UE_DEFINE_GAMEPLAY_TAG(State_Movement_Falling, "State.Movement.Falling");
|
||||
UE_DEFINE_GAMEPLAY_TAG(State_MovementSet_Default, "State.MovementSet.Default");
|
||||
UE_DEFINE_GAMEPLAY_TAG(State_MovementSet_Aiming, "State.MovementSet.Aiming");
|
||||
UE_DEFINE_GAMEPLAY_TAG(State_Rotation_OrientToMovement, "State.Rotation.OrientToMovement");
|
||||
UE_DEFINE_GAMEPLAY_TAG(State_Rotation_Strafe, "State.Rotation.Strafe");
|
||||
}
|
||||
|
||||
19
Source/PHY/Private/Player/PHYPlayerCameraManager.cpp
Normal file
19
Source/PHY/Private/Player/PHYPlayerCameraManager.cpp
Normal file
@@ -0,0 +1,19 @@
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#include "Player/PHYPlayerCameraManager.h"
|
||||
|
||||
#include UE_INLINE_GENERATED_CPP_BY_NAME(PHYPlayerCameraManager)
|
||||
|
||||
#include "Player/PHYPlayerController.h"
|
||||
|
||||
FRotator APHYPlayerCameraManager::GetRotationInput_Implementation() const
|
||||
{
|
||||
const APHYPlayerController* PHYController = Cast<APHYPlayerController>(PCOwner);
|
||||
return PHYController ? PHYController->GetCachedRotationInput() : FRotator::ZeroRotator;
|
||||
}
|
||||
|
||||
FVector APHYPlayerCameraManager::GetMovementControlInput_Implementation() const
|
||||
{
|
||||
const APHYPlayerController* PHYController = Cast<APHYPlayerController>(PCOwner);
|
||||
return PHYController ? PHYController->GetCachedMovementControlInput() : FVector::ZeroVector;
|
||||
}
|
||||
138
Source/PHY/Private/Player/PHYPlayerController.cpp
Normal file
138
Source/PHY/Private/Player/PHYPlayerController.cpp
Normal file
@@ -0,0 +1,138 @@
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#include "Player/PHYPlayerController.h"
|
||||
|
||||
#include UE_INLINE_GENERATED_CPP_BY_NAME(PHYPlayerController)
|
||||
|
||||
#include "Characters/PHYPlayerCharacter.h"
|
||||
#include "GIPS_InputSystemComponent.h"
|
||||
#include "InputActionValue.h"
|
||||
#include "Player/PHYPlayerCameraManager.h"
|
||||
#include "PHYGameplayTags.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
// 将 EnhancedInput 的多种值类型统一成二维输入,便于移动和视角路径共用。
|
||||
FVector2D ExtractAxis2D(const FInputActionValue& Value)
|
||||
{
|
||||
switch (Value.GetValueType())
|
||||
{
|
||||
case EInputActionValueType::Axis1D:
|
||||
return FVector2D(Value.Get<float>(), 0.0f);
|
||||
case EInputActionValueType::Axis2D:
|
||||
return Value.Get<FVector2D>();
|
||||
case EInputActionValueType::Axis3D:
|
||||
{
|
||||
const FVector Axis3D = Value.Get<FVector>();
|
||||
return FVector2D(Axis3D.X, Axis3D.Y);
|
||||
}
|
||||
default:
|
||||
return FVector2D::ZeroVector;
|
||||
}
|
||||
}
|
||||
|
||||
bool IsInputReleased(const ETriggerEvent TriggerEvent)
|
||||
{
|
||||
return TriggerEvent == ETriggerEvent::Completed || TriggerEvent == ETriggerEvent::Canceled;
|
||||
}
|
||||
}
|
||||
|
||||
APHYPlayerController::APHYPlayerController(const FObjectInitializer& ObjectInitializer)
|
||||
: Super(ObjectInitializer)
|
||||
{
|
||||
PlayerCameraManagerClass = APHYPlayerCameraManager::StaticClass();
|
||||
|
||||
InputSystemComponent = CreateDefaultSubobject<UGIPS_InputSystemComponent>(TEXT("InputSystemComponent"));
|
||||
}
|
||||
|
||||
void APHYPlayerController::BeginPlay()
|
||||
{
|
||||
Super::BeginPlay();
|
||||
|
||||
BindInputEvents();
|
||||
}
|
||||
|
||||
void APHYPlayerController::OnPossess(APawn* InPawn)
|
||||
{
|
||||
Super::OnPossess(InPawn);
|
||||
|
||||
BindInputEvents();
|
||||
}
|
||||
|
||||
APHYPlayerCharacter* APHYPlayerController::GetPHYPlayerCharacter() const
|
||||
{
|
||||
return Cast<APHYPlayerCharacter>(GetPawn());
|
||||
}
|
||||
|
||||
void APHYPlayerController::BindInputEvents()
|
||||
{
|
||||
if (!InputSystemComponent)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
InputSystemComponent->OnReceivedInput.RemoveDynamic(this, &ThisClass::OnReceivedInput);
|
||||
InputSystemComponent->OnReceivedInput.AddDynamic(this, &ThisClass::OnReceivedInput);
|
||||
}
|
||||
|
||||
void APHYPlayerController::OnReceivedInput(const FInputActionInstance& ActionData, const FGameplayTag& InputTag, const ETriggerEvent TriggerEvent)
|
||||
{
|
||||
if (InputTag == PHYGameplayTags::Input_Move)
|
||||
{
|
||||
HandleMoveInput(ActionData, TriggerEvent);
|
||||
return;
|
||||
}
|
||||
|
||||
if (InputTag == PHYGameplayTags::Input_Look)
|
||||
{
|
||||
HandleLookInput(ActionData, TriggerEvent);
|
||||
return;
|
||||
}
|
||||
|
||||
if (APHYPlayerCharacter* PHYCharacter = GetPHYPlayerCharacter())
|
||||
{
|
||||
PHYCharacter->HandleInputTag(InputTag, TriggerEvent);
|
||||
}
|
||||
}
|
||||
|
||||
bool APHYPlayerController::HandleMoveInput(const FInputActionInstance& ActionData, const ETriggerEvent TriggerEvent)
|
||||
{
|
||||
APHYPlayerCharacter* PHYCharacter = GetPHYPlayerCharacter();
|
||||
if (!PHYCharacter)
|
||||
{
|
||||
CachedMovementInput = FVector2D::ZeroVector;
|
||||
return false;
|
||||
}
|
||||
|
||||
CachedMovementInput = IsInputReleased(TriggerEvent) ? FVector2D::ZeroVector : ExtractAxis2D(ActionData.GetValue());
|
||||
|
||||
const FRotator CurrentControlRotation = GetControlRotation();
|
||||
const FRotator YawRotation(0.0f, CurrentControlRotation.Yaw, 0.0f);
|
||||
const FVector ForwardDirection = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::X);
|
||||
const FVector RightDirection = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::Y);
|
||||
|
||||
const FVector WorldIntent = (ForwardDirection * CachedMovementInput.Y) + (RightDirection * CachedMovementInput.X);
|
||||
PHYCharacter->SetMovementIntent(WorldIntent);
|
||||
|
||||
if (!CachedMovementInput.IsNearlyZero())
|
||||
{
|
||||
PHYCharacter->AddMovementInput(ForwardDirection, CachedMovementInput.Y);
|
||||
PHYCharacter->AddMovementInput(RightDirection, CachedMovementInput.X);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool APHYPlayerController::HandleLookInput(const FInputActionInstance& ActionData, const ETriggerEvent TriggerEvent)
|
||||
{
|
||||
CachedLookInput = IsInputReleased(TriggerEvent) ? FVector2D::ZeroVector : ExtractAxis2D(ActionData.GetValue());
|
||||
CachedRotationInput = FRotator(CachedLookInput.Y, CachedLookInput.X, 0.0f);
|
||||
|
||||
if (!CachedLookInput.IsNearlyZero())
|
||||
{
|
||||
AddYawInput(CachedLookInput.X);
|
||||
AddPitchInput(CachedLookInput.Y);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
22
Source/PHY/Private/Player/PHYPlayerState.cpp
Normal file
22
Source/PHY/Private/Player/PHYPlayerState.cpp
Normal file
@@ -0,0 +1,22 @@
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#include "Player/PHYPlayerState.h"
|
||||
|
||||
#include UE_INLINE_GENERATED_CPP_BY_NAME(PHYPlayerState)
|
||||
|
||||
#include "GGA_AbilitySystemComponent.h"
|
||||
|
||||
APHYPlayerState::APHYPlayerState(const FObjectInitializer& ObjectInitializer)
|
||||
: Super(ObjectInitializer)
|
||||
{
|
||||
SetNetUpdateFrequency(100.0f);
|
||||
|
||||
AbilitySystemComponent = CreateDefaultSubobject<UGGA_AbilitySystemComponent>(TEXT("AbilitySystemComponent"));
|
||||
AbilitySystemComponent->SetIsReplicated(true);
|
||||
AbilitySystemComponent->SetReplicationMode(EGameplayEffectReplicationMode::Mixed);
|
||||
}
|
||||
|
||||
UAbilitySystemComponent* APHYPlayerState::GetAbilitySystemComponent() const
|
||||
{
|
||||
return AbilitySystemComponent;
|
||||
}
|
||||
38
Source/PHY/Public/AI/PHYAIController.h
Normal file
38
Source/PHY/Public/AI/PHYAIController.h
Normal file
@@ -0,0 +1,38 @@
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "AIController.h"
|
||||
#include "GameplayTagContainer.h"
|
||||
#include "PHYAIController.generated.h"
|
||||
|
||||
class APHYAICharacter;
|
||||
|
||||
/**
|
||||
* @brief PHY AI 控制器。
|
||||
*
|
||||
* AI 通过角色请求接口触发移动、目标、交互和 Ability,不模拟玩家输入。
|
||||
*/
|
||||
UCLASS(BlueprintType, Blueprintable)
|
||||
class PHY_API APHYAIController : public AAIController
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
/** @brief 获取当前控制的 PHY AI 角色。 */
|
||||
UFUNCTION(BlueprintCallable, BlueprintPure, Category="PHY|AI")
|
||||
APHYAICharacter* GetPHYAICharacter() const;
|
||||
|
||||
/** @brief 请求 AI 角色开始交互。 */
|
||||
UFUNCTION(BlueprintCallable, Category="PHY|AI")
|
||||
bool RequestInteraction(int32 OptionIndex = 0);
|
||||
|
||||
/** @brief 设置 AI 角色的战斗目标。 */
|
||||
UFUNCTION(BlueprintCallable, Category="PHY|AI")
|
||||
void SetCombatTarget(AActor* TargetActor);
|
||||
|
||||
/** @brief 通过 Ability Tag 激活 AI 角色能力。 */
|
||||
UFUNCTION(BlueprintCallable, Category="PHY|AI")
|
||||
bool ActivateAbilityByTag(FGameplayTag AbilityTag);
|
||||
};
|
||||
18
Source/PHY/Public/Camera/PHYUGCSpringArmComponent.h
Normal file
18
Source/PHY/Public/Camera/PHYUGCSpringArmComponent.h
Normal file
@@ -0,0 +1,18 @@
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Camera/Components/UGC_SpringArmComponentBase.h"
|
||||
#include "PHYUGCSpringArmComponent.generated.h"
|
||||
|
||||
/**
|
||||
* @brief PHY 对 UGC SpringArm 的项目级可实例化包装。
|
||||
*
|
||||
* UGC 基类是抽象组件,项目通过该薄包装在 C++ 构造玩家相机臂。
|
||||
*/
|
||||
UCLASS(BlueprintType, Blueprintable, meta=(BlueprintSpawnableComponent))
|
||||
class PHY_API UPHYUGCSpringArmComponent : public UUGC_SpringArmComponentBase
|
||||
{
|
||||
GENERATED_BODY()
|
||||
};
|
||||
42
Source/PHY/Public/Characters/PHYAICharacter.h
Normal file
42
Source/PHY/Public/Characters/PHYAICharacter.h
Normal file
@@ -0,0 +1,42 @@
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Characters/PHYCharacterBase.h"
|
||||
#include "PHYAICharacter.generated.h"
|
||||
|
||||
class UGGA_AbilitySystemComponent;
|
||||
|
||||
/**
|
||||
* @brief PHY AI 角色。
|
||||
*
|
||||
* AI ASC 创建在 AI Character 自身,不创建玩家相机,也不绑定玩家输入。
|
||||
*/
|
||||
UCLASS(BlueprintType, Blueprintable)
|
||||
class PHY_API APHYAICharacter : public APHYCharacterBase
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
/** @brief 构造 AI 角色自有 ASC。 */
|
||||
APHYAICharacter(const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get());
|
||||
|
||||
/** @brief 开始游戏时初始化 AI 自身 ASC。 */
|
||||
virtual void BeginPlay() override;
|
||||
|
||||
/** @brief AI 被控制器接管时初始化自身 ASC。 */
|
||||
virtual void PossessedBy(AController* NewController) override;
|
||||
|
||||
/** @brief 获取 AI 自有 GGA ASC。 */
|
||||
UFUNCTION(BlueprintCallable, BlueprintPure, Category="PHY|AI")
|
||||
UGGA_AbilitySystemComponent* GetAIAbilitySystemComponent() const { return AbilitySystemComponent; }
|
||||
|
||||
protected:
|
||||
/** @brief 初始化 AI 自身作为 Owner 和 Avatar 的 ASC。 */
|
||||
virtual void InitializeAIAbilitySystem();
|
||||
|
||||
/** @brief AI 自身 ASC。 */
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="PHY|AI")
|
||||
TObjectPtr<UGGA_AbilitySystemComponent> AbilitySystemComponent;
|
||||
};
|
||||
244
Source/PHY/Public/Characters/PHYCharacterBase.h
Normal file
244
Source/PHY/Public/Characters/PHYCharacterBase.h
Normal file
@@ -0,0 +1,244 @@
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "AbilitySystemInterface.h"
|
||||
#include "GCS_CombatEntityInterface.h"
|
||||
#include "GameplayTagAssetInterface.h"
|
||||
#include "GameFramework/Character.h"
|
||||
#include "InputTriggers.h"
|
||||
#include "PHYCharacterBase.generated.h"
|
||||
|
||||
class UAbilitySystemComponent;
|
||||
class UGCS_CombatSystemComponent;
|
||||
class UGCS_CombatTeamAgentComponent;
|
||||
class UGCS_TargetingSystemComponent;
|
||||
class UGES_ContextEffectComponent;
|
||||
class UGGS_InteractionSystemComponent;
|
||||
class UGGS_RagdollComponent;
|
||||
class UPHYCharacterStateComponent;
|
||||
|
||||
/**
|
||||
* @brief PHY 玩家和 AI 共用角色基类。
|
||||
*
|
||||
* 基类直接继承 ACharacter,并通过项目级组件和接口适配 GAS、GCS、GGS、UGC 与后续运动系统。
|
||||
*/
|
||||
UCLASS(Abstract, BlueprintType, Blueprintable)
|
||||
class PHY_API APHYCharacterBase : public ACharacter, public IAbilitySystemInterface, public IGameplayTagAssetInterface, public IGCS_CombatEntityInterface
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
/** @brief 构造基础角色组件。 */
|
||||
APHYCharacterBase(const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get());
|
||||
|
||||
/** @brief 注册 ModularGameplay 组件接收者。 */
|
||||
virtual void PreInitializeComponents() override;
|
||||
|
||||
/** @brief 初始化角色运行时组件。 */
|
||||
virtual void BeginPlay() override;
|
||||
|
||||
/** @brief 移除 ModularGameplay 组件接收者。 */
|
||||
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
|
||||
|
||||
/** @brief 控制器接管时刷新项目状态。 */
|
||||
virtual void PossessedBy(AController* NewController) override;
|
||||
|
||||
/** @brief 控制器复制到客户端后刷新项目状态。 */
|
||||
virtual void OnRep_Controller() override;
|
||||
|
||||
/** @brief 获取当前角色使用的 AbilitySystemComponent。 */
|
||||
virtual UAbilitySystemComponent* GetAbilitySystemComponent() const override;
|
||||
|
||||
/** @brief 收集 ASC 与角色状态组件提供的 GameplayTag。 */
|
||||
virtual void GetOwnedGameplayTags(FGameplayTagContainer& TagContainer) const override;
|
||||
|
||||
/** @brief 初始化当前 Avatar 对应的 ASC。 */
|
||||
UFUNCTION(BlueprintCallable, Category="PHY|Character|Ability")
|
||||
virtual void InitializeAbilitySystem(UAbilitySystemComponent* NewAbilitySystemComponent, AActor* OwnerActor);
|
||||
|
||||
/** @brief 清理角色缓存的 ASC 引用。 */
|
||||
UFUNCTION(BlueprintCallable, Category="PHY|Character|Ability")
|
||||
virtual void ClearAbilitySystem();
|
||||
|
||||
/** @brief 查询 ASC 是否已经完成项目级初始化。 */
|
||||
UFUNCTION(BlueprintCallable, BlueprintPure, Category="PHY|Character|Ability")
|
||||
bool IsAbilitySystemReady() const { return bAbilitySystemReady; }
|
||||
|
||||
/** @brief 接收输入 Tag 并路由到移动、交互或 GAS Ability。 */
|
||||
UFUNCTION(BlueprintCallable, Category="PHY|Character|Input")
|
||||
virtual bool HandleInputTag(FGameplayTag InputTag, ETriggerEvent TriggerEvent);
|
||||
|
||||
/** @brief 设置移动意图,并在客户端请求服务端同步。 */
|
||||
UFUNCTION(BlueprintCallable, Category="PHY|Character|Movement")
|
||||
virtual void SetMovementIntent(FVector NewMovementIntent);
|
||||
|
||||
/** @brief 设置项目级战斗目标。 */
|
||||
UFUNCTION(BlueprintCallable, Category="PHY|Character|Combat")
|
||||
virtual void SetCombatTargetActor(AActor* NewCombatTargetActor);
|
||||
|
||||
/** @brief 请求开始交互。 */
|
||||
UFUNCTION(BlueprintCallable, Category="PHY|Character|Interaction")
|
||||
virtual bool RequestInteraction(int32 OptionIndex = 0);
|
||||
|
||||
/** @brief 请求一次性即时交互。 */
|
||||
UFUNCTION(BlueprintCallable, Category="PHY|Character|Interaction")
|
||||
virtual bool RequestInstantInteraction(int32 OptionIndex = 0);
|
||||
|
||||
/** @brief 请求结束当前交互。 */
|
||||
UFUNCTION(BlueprintCallable, Category="PHY|Character|Interaction")
|
||||
virtual void EndInteraction();
|
||||
|
||||
/** @brief 请求切换当前可交互对象。 */
|
||||
UFUNCTION(BlueprintCallable, Category="PHY|Character|Interaction")
|
||||
virtual void CycleInteractionTarget(bool bNext);
|
||||
|
||||
/** @brief 获取项目角色状态组件。 */
|
||||
UFUNCTION(BlueprintCallable, BlueprintPure, Category="PHY|Character")
|
||||
UPHYCharacterStateComponent* GetCharacterStateComponent() const { return CharacterStateComponent; }
|
||||
|
||||
/** @brief 获取 GCS 战斗组件。 */
|
||||
UFUNCTION(BlueprintCallable, BlueprintPure, Category="PHY|Character")
|
||||
UGCS_CombatSystemComponent* GetCombatSystemComponent() const { return CombatSystemComponent; }
|
||||
|
||||
/** @brief 获取 GCS 目标组件。 */
|
||||
UFUNCTION(BlueprintCallable, BlueprintPure, Category="PHY|Character")
|
||||
UGCS_TargetingSystemComponent* GetTargetingSystemComponent() const { return TargetingSystemComponent; }
|
||||
|
||||
/** @brief 获取 GGS 交互组件。 */
|
||||
UFUNCTION(BlueprintCallable, BlueprintPure, Category="PHY|Character")
|
||||
UGGS_InteractionSystemComponent* GetInteractionSystemComponent() const { return InteractionSystemComponent; }
|
||||
|
||||
/** @brief 获取 GGS 布娃娃组件。 */
|
||||
UFUNCTION(BlueprintCallable, BlueprintPure, Category="PHY|Character")
|
||||
UGGS_RagdollComponent* GetRagdollComponent() const { return RagdollComponent; }
|
||||
|
||||
/** @brief 获取上下文效果组件。 */
|
||||
UFUNCTION(BlueprintCallable, BlueprintPure, Category="PHY|Character")
|
||||
UGES_ContextEffectComponent* GetContextEffectComponent() const { return ContextEffectComponent; }
|
||||
|
||||
/** @brief 获取当前战斗目标 Actor。 */
|
||||
virtual AActor* GetCombatTargetActor_Implementation() const override;
|
||||
|
||||
/** @brief 获取连击定义表,首期骨架默认不绑定表。 */
|
||||
virtual const UDataTable* GetComboDefinitionTable_Implementation() const override;
|
||||
|
||||
/** @brief 获取当前战斗目标场景对象。 */
|
||||
virtual USceneComponent* GetCombatTargetObject_Implementation() const override;
|
||||
|
||||
/** @brief 查询能力动作,首期骨架默认返回空。 */
|
||||
virtual bool QueryAbilityActions_Implementation(FGameplayTagContainer AbilityTags, FGameplayTagContainer SourceTags, FGameplayTagContainer TargetTags, TArray<FGCS_AbilityAction>& AbilityActions) override;
|
||||
|
||||
/** @brief 按上下文查询能力动作,首期骨架默认返回空。 */
|
||||
virtual bool QueryAbilityActionsByContext_Implementation(UObject* Context, FGameplayTagContainer AbilityTags, FGameplayTagContainer SourceTags, FGameplayTagContainer TargetTags, TArray<FGCS_AbilityAction>& AbilityActions) override;
|
||||
|
||||
/** @brief 按 Tag 查询当前武器。 */
|
||||
virtual UObject* QueryWeapon_Implementation(const FGameplayTagQuery& Query) const override;
|
||||
|
||||
/** @brief 设置旋转模式。 */
|
||||
virtual void SetRotationMode_Implementation(FGameplayTag NewRotationMode) override;
|
||||
|
||||
/** @brief 获取旋转模式。 */
|
||||
virtual FGameplayTag GetRotationMode_Implementation() const override;
|
||||
|
||||
/** @brief 设置移动集合。 */
|
||||
virtual void SetMovementSet_Implementation(FGameplayTag NewMovementSet) override;
|
||||
|
||||
/** @brief 获取移动集合。 */
|
||||
virtual FGameplayTag GetMovementSet_Implementation() const override;
|
||||
|
||||
/** @brief 设置移动状态。 */
|
||||
virtual void SetMovementState_Implementation(FGameplayTag NewMovementState) override;
|
||||
|
||||
/** @brief 获取移动状态。 */
|
||||
virtual FGameplayTag GetMovementState_Implementation() const override;
|
||||
|
||||
/** @brief 开始死亡流程。 */
|
||||
virtual void StartDeath_Implementation() override;
|
||||
|
||||
/** @brief 完成死亡流程。 */
|
||||
virtual void FinishDeath_Implementation() override;
|
||||
|
||||
/** @brief 查询角色是否死亡。 */
|
||||
virtual bool IsDead_Implementation() const override;
|
||||
|
||||
/** @brief 获取移动意图。 */
|
||||
virtual FVector GetMovementIntent_Implementation() const override;
|
||||
|
||||
/** @brief 获取当前武器。 */
|
||||
virtual UObject* GetCurrentWeapon_Implementation(UObject* Context = nullptr) const override;
|
||||
|
||||
/** @brief 设置当前武器。 */
|
||||
virtual void SetCurrentWeapon_Implementation(UObject* Weapon) override;
|
||||
|
||||
/** @brief 获取指定 Socket 的相对变换。 */
|
||||
virtual bool GetRelativeTransformToSocket_Implementation(const USkeletalMeshComponent* InSkeletalMeshComponent, const UStaticMesh* StaticMesh, const USkeletalMesh* SkeletalMesh, FName SocketName, FTransform& OutTransform) const override;
|
||||
|
||||
protected:
|
||||
/** @brief 将输入 Tag 映射为 Ability Tag。 */
|
||||
virtual FGameplayTag GetAbilityTagForInputTag(FGameplayTag InputTag) const;
|
||||
|
||||
/** @brief 应用 Character 配置默认值。 */
|
||||
virtual void ApplyCharacterSettings();
|
||||
|
||||
/** @brief 服务端同步移动意图。 */
|
||||
UFUNCTION(Server, Unreliable)
|
||||
void ServerSetMovementIntent(FVector NewMovementIntent);
|
||||
|
||||
/** @brief 服务端设置战斗目标。 */
|
||||
UFUNCTION(Server, Reliable)
|
||||
void ServerSetCombatTargetActor(AActor* NewCombatTargetActor);
|
||||
|
||||
/** @brief 服务端执行开始交互。 */
|
||||
UFUNCTION(Server, Reliable)
|
||||
void ServerRequestInteraction(int32 OptionIndex);
|
||||
|
||||
/** @brief 服务端执行即时交互。 */
|
||||
UFUNCTION(Server, Reliable)
|
||||
void ServerRequestInstantInteraction(int32 OptionIndex);
|
||||
|
||||
/** @brief 服务端结束交互。 */
|
||||
UFUNCTION(Server, Reliable)
|
||||
void ServerEndInteraction();
|
||||
|
||||
/** @brief 服务端切换交互目标。 */
|
||||
UFUNCTION(Server, Reliable)
|
||||
void ServerCycleInteractionTarget(bool bNext);
|
||||
|
||||
/** @brief 角色共享状态组件。 */
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="PHY|Character")
|
||||
TObjectPtr<UPHYCharacterStateComponent> CharacterStateComponent;
|
||||
|
||||
/** @brief GCS 战斗系统组件。 */
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="PHY|Character")
|
||||
TObjectPtr<UGCS_CombatSystemComponent> CombatSystemComponent;
|
||||
|
||||
/** @brief GCS 目标系统组件。 */
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="PHY|Character")
|
||||
TObjectPtr<UGCS_TargetingSystemComponent> TargetingSystemComponent;
|
||||
|
||||
/** @brief GCS 战斗队伍代理组件。 */
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="PHY|Character")
|
||||
TObjectPtr<UGCS_CombatTeamAgentComponent> CombatTeamAgentComponent;
|
||||
|
||||
/** @brief GGS 交互系统组件。 */
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="PHY|Character")
|
||||
TObjectPtr<UGGS_InteractionSystemComponent> InteractionSystemComponent;
|
||||
|
||||
/** @brief GGS 布娃娃组件。 */
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="PHY|Character")
|
||||
TObjectPtr<UGGS_RagdollComponent> RagdollComponent;
|
||||
|
||||
/** @brief GES 上下文效果组件。 */
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="PHY|Character")
|
||||
TObjectPtr<UGES_ContextEffectComponent> ContextEffectComponent;
|
||||
|
||||
/** @brief 当前 Avatar 缓存的 ASC,玩家来自 PlayerState,AI 来自自身。 */
|
||||
UPROPERTY(Transient)
|
||||
TObjectPtr<UAbilitySystemComponent> CachedAbilitySystemComponent;
|
||||
|
||||
/** @brief ASC 是否已经初始化为当前 Avatar。 */
|
||||
UPROPERTY(Transient)
|
||||
bool bAbilitySystemReady = false;
|
||||
};
|
||||
75
Source/PHY/Public/Characters/PHYCharacterSettings.h
Normal file
75
Source/PHY/Public/Characters/PHYCharacterSettings.h
Normal file
@@ -0,0 +1,75 @@
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "UObject/Object.h"
|
||||
#include "UObject/SoftObjectPtr.h"
|
||||
#include "PHYCharacterSettings.generated.h"
|
||||
|
||||
class APHYAICharacter;
|
||||
class APHYAIController;
|
||||
class APHYPlayerCameraManager;
|
||||
class APHYPlayerCharacter;
|
||||
class APHYPlayerController;
|
||||
class UUGC_CameraDataAssetBase;
|
||||
|
||||
/**
|
||||
* @brief PHY 角色系统配置。
|
||||
*
|
||||
* 角色默认参数独立放在 PHYCharacter 配置域,避免把玩法参数混入 Engine 或 Input 标准配置。
|
||||
*/
|
||||
UCLASS(Config=PHYCharacter, DefaultConfig)
|
||||
class PHY_API UPHYCharacterSettings : public UObject
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
/** @brief 是否启用 GenericGameSystem 交互组件路径。 */
|
||||
UPROPERTY(Config, EditDefaultsOnly, Category="PHY|Character")
|
||||
bool bEnableGenericGameInteraction = true;
|
||||
|
||||
/** @brief 是否启用 GenericEffectsSystem 上下文效果组件。 */
|
||||
UPROPERTY(Config, EditDefaultsOnly, Category="PHY|Character")
|
||||
bool bEnableContextEffects = true;
|
||||
|
||||
/** @brief 默认最大行走速度。 */
|
||||
UPROPERTY(Config, EditDefaultsOnly, Category="PHY|Character")
|
||||
float DefaultMaxWalkSpeed = 500.0f;
|
||||
|
||||
/** @brief 默认冲刺速度。 */
|
||||
UPROPERTY(Config, EditDefaultsOnly, Category="PHY|Character")
|
||||
float DefaultSprintSpeed = 650.0f;
|
||||
|
||||
/** @brief 默认最大加速度。 */
|
||||
UPROPERTY(Config, EditDefaultsOnly, Category="PHY|Character")
|
||||
float DefaultMaxAcceleration = 2048.0f;
|
||||
|
||||
/** @brief 默认交互选项索引。 */
|
||||
UPROPERTY(Config, EditDefaultsOnly, Category="PHY|Character")
|
||||
int32 DefaultInteractionOption = 0;
|
||||
|
||||
/** @brief 玩家角色默认软类引用。 */
|
||||
UPROPERTY(Config, EditDefaultsOnly, Category="PHY|Character")
|
||||
TSoftClassPtr<APHYPlayerCharacter> DefaultPlayerCharacterClass;
|
||||
|
||||
/** @brief AI 角色默认软类引用。 */
|
||||
UPROPERTY(Config, EditDefaultsOnly, Category="PHY|Character")
|
||||
TSoftClassPtr<APHYAICharacter> DefaultAICharacterClass;
|
||||
|
||||
/** @brief 玩家控制器默认软类引用。 */
|
||||
UPROPERTY(Config, EditDefaultsOnly, Category="PHY|Character")
|
||||
TSoftClassPtr<APHYPlayerController> DefaultPlayerControllerClass;
|
||||
|
||||
/** @brief AI 控制器默认软类引用。 */
|
||||
UPROPERTY(Config, EditDefaultsOnly, Category="PHY|Character")
|
||||
TSoftClassPtr<APHYAIController> DefaultAIControllerClass;
|
||||
|
||||
/** @brief 玩家相机管理器默认软类引用。 */
|
||||
UPROPERTY(Config, EditDefaultsOnly, Category="PHY|Character")
|
||||
TSoftClassPtr<APHYPlayerCameraManager> DefaultPlayerCameraManagerClass;
|
||||
|
||||
/** @brief UGC 默认 CameraData 软引用,首期不强制制作资产。 */
|
||||
UPROPERTY(Config, EditDefaultsOnly, Category="PHY|Character")
|
||||
TSoftObjectPtr<UUGC_CameraDataAssetBase> DefaultUGCCameraDataAsset;
|
||||
};
|
||||
114
Source/PHY/Public/Characters/PHYCharacterStateComponent.h
Normal file
114
Source/PHY/Public/Characters/PHYCharacterStateComponent.h
Normal file
@@ -0,0 +1,114 @@
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Components/ActorComponent.h"
|
||||
#include "GameplayTagContainer.h"
|
||||
#include "PHYCharacterStateComponent.generated.h"
|
||||
|
||||
/**
|
||||
* @brief PHY 角色复制状态组件。
|
||||
*
|
||||
* 该组件集中保存 GCS、相机、输入和运动层共享的轻量状态,避免玩法层直接散落插件状态字段。
|
||||
*/
|
||||
UCLASS(BlueprintType, Blueprintable, meta=(BlueprintSpawnableComponent))
|
||||
class PHY_API UPHYCharacterStateComponent : public UActorComponent
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
/** @brief 构造默认复制状态。 */
|
||||
UPHYCharacterStateComponent(const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get());
|
||||
|
||||
/** @brief 注册需要网络复制的角色状态字段。 */
|
||||
virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;
|
||||
|
||||
/** @brief 设置死亡状态。 */
|
||||
UFUNCTION(BlueprintCallable, Category="PHY|Character|State")
|
||||
void SetDead(bool bNewDead);
|
||||
|
||||
/** @brief 查询角色是否已经死亡。 */
|
||||
UFUNCTION(BlueprintCallable, BlueprintPure, Category="PHY|Character|State")
|
||||
bool IsDead() const { return bDead; }
|
||||
|
||||
/** @brief 设置当前战斗目标 Actor。 */
|
||||
UFUNCTION(BlueprintCallable, Category="PHY|Character|State")
|
||||
void SetCombatTargetActor(AActor* NewCombatTargetActor);
|
||||
|
||||
/** @brief 获取当前战斗目标 Actor。 */
|
||||
UFUNCTION(BlueprintCallable, BlueprintPure, Category="PHY|Character|State")
|
||||
AActor* GetCombatTargetActor() const { return CombatTargetActor; }
|
||||
|
||||
/** @brief 设置当前武器对象。 */
|
||||
UFUNCTION(BlueprintCallable, Category="PHY|Character|State")
|
||||
void SetCurrentWeapon(UObject* NewCurrentWeapon);
|
||||
|
||||
/** @brief 获取当前武器对象。 */
|
||||
UFUNCTION(BlueprintCallable, BlueprintPure, Category="PHY|Character|State")
|
||||
UObject* GetCurrentWeapon() const { return CurrentWeapon; }
|
||||
|
||||
/** @brief 设置移动输入意图,通常由玩家控制器或 AI 控制器写入。 */
|
||||
UFUNCTION(BlueprintCallable, Category="PHY|Character|State")
|
||||
void SetMovementIntent(FVector NewMovementIntent);
|
||||
|
||||
/** @brief 获取当前移动输入意图。 */
|
||||
UFUNCTION(BlueprintCallable, BlueprintPure, Category="PHY|Character|State")
|
||||
FVector GetMovementIntent() const { return MovementIntent; }
|
||||
|
||||
/** @brief 设置当前移动状态 Tag。 */
|
||||
UFUNCTION(BlueprintCallable, Category="PHY|Character|State")
|
||||
void SetMovementState(FGameplayTag NewMovementState);
|
||||
|
||||
/** @brief 获取当前移动状态 Tag。 */
|
||||
UFUNCTION(BlueprintCallable, BlueprintPure, Category="PHY|Character|State")
|
||||
FGameplayTag GetMovementState() const { return MovementState; }
|
||||
|
||||
/** @brief 设置当前移动集合 Tag。 */
|
||||
UFUNCTION(BlueprintCallable, Category="PHY|Character|State")
|
||||
void SetMovementSet(FGameplayTag NewMovementSet);
|
||||
|
||||
/** @brief 获取当前移动集合 Tag。 */
|
||||
UFUNCTION(BlueprintCallable, BlueprintPure, Category="PHY|Character|State")
|
||||
FGameplayTag GetMovementSet() const { return MovementSet; }
|
||||
|
||||
/** @brief 设置当前旋转模式 Tag。 */
|
||||
UFUNCTION(BlueprintCallable, Category="PHY|Character|State")
|
||||
void SetRotationMode(FGameplayTag NewRotationMode);
|
||||
|
||||
/** @brief 获取当前旋转模式 Tag。 */
|
||||
UFUNCTION(BlueprintCallable, BlueprintPure, Category="PHY|Character|State")
|
||||
FGameplayTag GetRotationMode() const { return RotationMode; }
|
||||
|
||||
/** @brief 将状态组件拥有的 GameplayTag 写入输出容器。 */
|
||||
void GetOwnedStateTags(FGameplayTagContainer& OutTags) const;
|
||||
|
||||
protected:
|
||||
/** @brief 死亡状态,由服务端驱动复制。 */
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Replicated, Category="PHY|Character|State")
|
||||
bool bDead = false;
|
||||
|
||||
/** @brief 当前战斗目标 Actor。 */
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Replicated, Category="PHY|Character|State")
|
||||
TObjectPtr<AActor> CombatTargetActor;
|
||||
|
||||
/** @brief 当前武器对象。 */
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Replicated, Category="PHY|Character|State")
|
||||
TObjectPtr<UObject> CurrentWeapon;
|
||||
|
||||
/** @brief 移动输入意图。 */
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Replicated, Category="PHY|Character|State")
|
||||
FVector MovementIntent = FVector::ZeroVector;
|
||||
|
||||
/** @brief 当前移动状态。 */
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Replicated, Category="PHY|Character|State")
|
||||
FGameplayTag MovementState;
|
||||
|
||||
/** @brief 当前移动集合。 */
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Replicated, Category="PHY|Character|State")
|
||||
FGameplayTag MovementSet;
|
||||
|
||||
/** @brief 当前旋转模式。 */
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Replicated, Category="PHY|Character|State")
|
||||
FGameplayTag RotationMode;
|
||||
};
|
||||
51
Source/PHY/Public/Characters/PHYPlayerCharacter.h
Normal file
51
Source/PHY/Public/Characters/PHYPlayerCharacter.h
Normal file
@@ -0,0 +1,51 @@
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Characters/PHYCharacterBase.h"
|
||||
#include "PHYPlayerCharacter.generated.h"
|
||||
|
||||
class UCameraComponent;
|
||||
class UPHYUGCSpringArmComponent;
|
||||
|
||||
/**
|
||||
* @brief PHY 玩家角色。
|
||||
*
|
||||
* 玩家角色从 PlayerState 获取 ASC,并只持有相机组件,不直接持有输入组件。
|
||||
*/
|
||||
UCLASS(BlueprintType, Blueprintable)
|
||||
class PHY_API APHYPlayerCharacter : public APHYCharacterBase
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
/** @brief 构造玩家角色相机组件。 */
|
||||
APHYPlayerCharacter(const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get());
|
||||
|
||||
/** @brief 服务端 Possess 后从 PlayerState 初始化 ASC。 */
|
||||
virtual void PossessedBy(AController* NewController) override;
|
||||
|
||||
/** @brief 客户端 PlayerState 复制后初始化 ASC。 */
|
||||
virtual void OnRep_PlayerState() override;
|
||||
|
||||
/** @brief 获取 UGC 相机臂。 */
|
||||
UFUNCTION(BlueprintCallable, BlueprintPure, Category="PHY|Camera")
|
||||
UPHYUGCSpringArmComponent* GetCameraBoom() const { return CameraBoom; }
|
||||
|
||||
/** @brief 获取跟随相机。 */
|
||||
UFUNCTION(BlueprintCallable, BlueprintPure, Category="PHY|Camera")
|
||||
UCameraComponent* GetFollowCamera() const { return FollowCamera; }
|
||||
|
||||
protected:
|
||||
/** @brief 根据当前 PlayerState 初始化 ASC。 */
|
||||
virtual void InitializeAbilitySystemFromPlayerState();
|
||||
|
||||
/** @brief UGC 项目相机臂。 */
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="PHY|Camera")
|
||||
TObjectPtr<UPHYUGCSpringArmComponent> CameraBoom;
|
||||
|
||||
/** @brief 玩家跟随相机。 */
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="PHY|Camera")
|
||||
TObjectPtr<UCameraComponent> FollowCamera;
|
||||
};
|
||||
@@ -23,4 +23,31 @@ namespace PHYGameplayTags
|
||||
|
||||
/** @brief UI 占用主要输入。 */
|
||||
UE_DECLARE_GAMEPLAY_TAG_EXTERN(State_UI_Open);
|
||||
|
||||
/** @brief 角色已经进入死亡流程。 */
|
||||
UE_DECLARE_GAMEPLAY_TAG_EXTERN(State_Dead);
|
||||
|
||||
/** @brief 角色处于行走移动状态。 */
|
||||
UE_DECLARE_GAMEPLAY_TAG_EXTERN(State_Movement_Walk);
|
||||
|
||||
/** @brief 角色处于常规跑动移动状态。 */
|
||||
UE_DECLARE_GAMEPLAY_TAG_EXTERN(State_Movement_Run);
|
||||
|
||||
/** @brief 角色处于冲刺移动状态。 */
|
||||
UE_DECLARE_GAMEPLAY_TAG_EXTERN(State_Movement_Sprint);
|
||||
|
||||
/** @brief 角色处于下落移动状态。 */
|
||||
UE_DECLARE_GAMEPLAY_TAG_EXTERN(State_Movement_Falling);
|
||||
|
||||
/** @brief 角色使用默认移动集合。 */
|
||||
UE_DECLARE_GAMEPLAY_TAG_EXTERN(State_MovementSet_Default);
|
||||
|
||||
/** @brief 角色使用瞄准移动集合。 */
|
||||
UE_DECLARE_GAMEPLAY_TAG_EXTERN(State_MovementSet_Aiming);
|
||||
|
||||
/** @brief 角色旋转朝向移动方向。 */
|
||||
UE_DECLARE_GAMEPLAY_TAG_EXTERN(State_Rotation_OrientToMovement);
|
||||
|
||||
/** @brief 角色旋转使用战斗横移模式。 */
|
||||
UE_DECLARE_GAMEPLAY_TAG_EXTERN(State_Rotation_Strafe);
|
||||
}
|
||||
|
||||
25
Source/PHY/Public/Player/PHYPlayerCameraManager.h
Normal file
25
Source/PHY/Public/Player/PHYPlayerCameraManager.h
Normal file
@@ -0,0 +1,25 @@
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Camera/UGC_PlayerCameraManager.h"
|
||||
#include "PHYPlayerCameraManager.generated.h"
|
||||
|
||||
/**
|
||||
* @brief PHY 玩家相机管理器。
|
||||
*
|
||||
* 该类型从 PlayerController 的 C++ 缓存读取输入,不把 UGC 蓝图 Pawn Interface 作为主路径。
|
||||
*/
|
||||
UCLASS(BlueprintType, Blueprintable)
|
||||
class PHY_API APHYPlayerCameraManager : public AUGC_PlayerCameraManager
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
protected:
|
||||
/** @brief 返回玩家视角输入。 */
|
||||
virtual FRotator GetRotationInput_Implementation() const override;
|
||||
|
||||
/** @brief 返回玩家移动控制输入。 */
|
||||
virtual FVector GetMovementControlInput_Implementation() const override;
|
||||
};
|
||||
78
Source/PHY/Public/Player/PHYPlayerController.h
Normal file
78
Source/PHY/Public/Player/PHYPlayerController.h
Normal file
@@ -0,0 +1,78 @@
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "GameFramework/PlayerController.h"
|
||||
#include "GIPS_InputTypes.h"
|
||||
#include "PHYPlayerController.generated.h"
|
||||
|
||||
class APHYPlayerCharacter;
|
||||
class UGIPS_InputSystemComponent;
|
||||
|
||||
/**
|
||||
* @brief PHY 玩家控制器。
|
||||
*
|
||||
* 控制器持有 GenericInputSystem 组件,并将 Input GameplayTag 路由到当前玩家角色、ASC、移动和相机输入缓存。
|
||||
*/
|
||||
UCLASS(BlueprintType, Blueprintable)
|
||||
class PHY_API APHYPlayerController : public APlayerController
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
/** @brief 构造输入组件并设置 UGC 相机管理器。 */
|
||||
APHYPlayerController(const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get());
|
||||
|
||||
/** @brief 初始化输入委托。 */
|
||||
virtual void BeginPlay() override;
|
||||
|
||||
/** @brief 接管 Pawn 时刷新输入委托。 */
|
||||
virtual void OnPossess(APawn* InPawn) override;
|
||||
|
||||
/** @brief 获取 GenericInputSystem 组件。 */
|
||||
UFUNCTION(BlueprintCallable, BlueprintPure, Category="PHY|Input")
|
||||
UGIPS_InputSystemComponent* GetInputSystemComponent() const { return InputSystemComponent; }
|
||||
|
||||
/** @brief 获取当前 PHY 玩家角色。 */
|
||||
UFUNCTION(BlueprintCallable, BlueprintPure, Category="PHY|Input")
|
||||
APHYPlayerCharacter* GetPHYPlayerCharacter() const;
|
||||
|
||||
/** @brief 获取相机使用的旋转输入缓存。 */
|
||||
UFUNCTION(BlueprintCallable, BlueprintPure, Category="PHY|Input")
|
||||
FRotator GetCachedRotationInput() const { return CachedRotationInput; }
|
||||
|
||||
/** @brief 获取相机使用的移动控制输入缓存。 */
|
||||
UFUNCTION(BlueprintCallable, BlueprintPure, Category="PHY|Input")
|
||||
FVector GetCachedMovementControlInput() const { return FVector(CachedMovementInput.X, CachedMovementInput.Y, 0.0f); }
|
||||
|
||||
protected:
|
||||
/** @brief 绑定 GenericInputSystem 输入委托。 */
|
||||
virtual void BindInputEvents();
|
||||
|
||||
/** @brief 处理 GenericInputSystem 发出的输入事件。 */
|
||||
UFUNCTION()
|
||||
void OnReceivedInput(const FInputActionInstance& ActionData, const FGameplayTag& InputTag, ETriggerEvent TriggerEvent);
|
||||
|
||||
/** @brief 处理移动输入。 */
|
||||
virtual bool HandleMoveInput(const FInputActionInstance& ActionData, ETriggerEvent TriggerEvent);
|
||||
|
||||
/** @brief 处理视角输入。 */
|
||||
virtual bool HandleLookInput(const FInputActionInstance& ActionData, ETriggerEvent TriggerEvent);
|
||||
|
||||
/** @brief GenericInputSystem 路由组件。 */
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="PHY|Input")
|
||||
TObjectPtr<UGIPS_InputSystemComponent> InputSystemComponent;
|
||||
|
||||
/** @brief 本地移动输入缓存。 */
|
||||
UPROPERTY(Transient)
|
||||
FVector2D CachedMovementInput = FVector2D::ZeroVector;
|
||||
|
||||
/** @brief 本地视角输入缓存。 */
|
||||
UPROPERTY(Transient)
|
||||
FVector2D CachedLookInput = FVector2D::ZeroVector;
|
||||
|
||||
/** @brief UGC 相机管理器读取的旋转输入缓存。 */
|
||||
UPROPERTY(Transient)
|
||||
FRotator CachedRotationInput = FRotator::ZeroRotator;
|
||||
};
|
||||
37
Source/PHY/Public/Player/PHYPlayerState.h
Normal file
37
Source/PHY/Public/Player/PHYPlayerState.h
Normal file
@@ -0,0 +1,37 @@
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "AbilitySystemInterface.h"
|
||||
#include "GameFramework/PlayerState.h"
|
||||
#include "PHYPlayerState.generated.h"
|
||||
|
||||
class UGGA_AbilitySystemComponent;
|
||||
|
||||
/**
|
||||
* @brief PHY 玩家状态。
|
||||
*
|
||||
* 玩家 ASC 挂在 PlayerState 上,以支持重生、换 Pawn 和持久属性复制。
|
||||
*/
|
||||
UCLASS(BlueprintType, Blueprintable)
|
||||
class PHY_API APHYPlayerState : public APlayerState, public IAbilitySystemInterface
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
/** @brief 构造玩家状态与 ASC。 */
|
||||
APHYPlayerState(const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get());
|
||||
|
||||
/** @brief 获取玩家持久 AbilitySystemComponent。 */
|
||||
virtual UAbilitySystemComponent* GetAbilitySystemComponent() const override;
|
||||
|
||||
/** @brief 获取 GGA ASC 的强类型指针。 */
|
||||
UFUNCTION(BlueprintCallable, BlueprintPure, Category="PHY|PlayerState")
|
||||
UGGA_AbilitySystemComponent* GetGGAAbilitySystemComponent() const { return AbilitySystemComponent; }
|
||||
|
||||
protected:
|
||||
/** @brief 玩家持久 ASC。 */
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="PHY|PlayerState")
|
||||
TObjectPtr<UGGA_AbilitySystemComponent> AbilitySystemComponent;
|
||||
};
|
||||
Reference in New Issue
Block a user