4fc4a39aa6
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
271 lines
8.6 KiB
C++
271 lines
8.6 KiB
C++
// ChildHood Project - 玩家角色 实现(v1.1 Effect/Action 架构适配)
|
||
// 变更:通过 ASystemDriver 访问 FInteractionManager + FEffectManager
|
||
// 新增 BeginPlay 初始化 PromptComponent
|
||
// 删除对旧 UInteractionManager 的依赖
|
||
|
||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||
|
||
#include "ChildHoodCharacter.h"
|
||
#include "Engine/LocalPlayer.h"
|
||
#include "Camera/CameraComponent.h"
|
||
#include "Components/CapsuleComponent.h"
|
||
#include "GameFramework/CharacterMovementComponent.h"
|
||
#include "GameFramework/SpringArmComponent.h"
|
||
#include "GameFramework/Controller.h"
|
||
#include "EnhancedInputComponent.h"
|
||
#include "EnhancedInputSubsystems.h"
|
||
#include "InputActionValue.h"
|
||
#include "ChildHood.h"
|
||
#include "Interaction/InteractionPromptComponent.h"
|
||
#include "Collection/CollectionHUDComponent.h"
|
||
#include "SystemDriver.h"
|
||
#include "Interaction/InteractionManager.h"
|
||
#include "Interaction/EffectManager.h"
|
||
#include "Interaction/InteractableComponent.h"
|
||
#include "Interaction/InteractionTypes.h"
|
||
|
||
AChildHoodCharacter::AChildHoodCharacter()
|
||
{
|
||
// Set size for collision capsule
|
||
GetCapsuleComponent()->InitCapsuleSize(42.f, 96.0f);
|
||
|
||
// Don't rotate when the controller rotates. Let that just affect the camera.
|
||
bUseControllerRotationPitch = false;
|
||
bUseControllerRotationYaw = false;
|
||
bUseControllerRotationRoll = false;
|
||
|
||
// Configure character movement — v0.1 player controller tech design parameters
|
||
auto* CMC = GetCharacterMovement();
|
||
CMC->bOrientRotationToMovement = true; // 角色朝移动方向旋转
|
||
CMC->RotationRate = FRotator(0.0f, 720.0f, 0.0f); // 转向速度 720°/s(远快于鼠标 150°/s)
|
||
CMC->MaxWalkSpeed = 450.0f; // 跑步速度 4.5 m/s
|
||
CMC->MaxAcceleration = 2250.0f; // 起步加速 0.2s (450/0.2)
|
||
CMC->BrakingDecelerationWalking = 1500.0f; // 停止减速 0.3s (450/0.3)
|
||
CMC->BrakingDecelerationFalling = 1500.0f;
|
||
CMC->MinAnalogWalkSpeed = 20.f;
|
||
|
||
// Create a camera boom (pulls in towards the player if there is a collision)
|
||
CameraBoom = CreateDefaultSubobject<USpringArmComponent>(TEXT("CameraBoom"));
|
||
CameraBoom->SetupAttachment(RootComponent);
|
||
CameraBoom->TargetArmLength = 350.0f; // 摄像机距离 3.5m
|
||
CameraBoom->SocketOffset = FVector(0.f, 0.f, 80.f); // 摄像机高度 0.8m(头部上方)
|
||
CameraBoom->bUsePawnControlRotation = true;
|
||
|
||
// 摄像机软跟随
|
||
CameraBoom->bEnableCameraLag = true;
|
||
CameraBoom->CameraLagSpeed = 6.0f;
|
||
CameraBoom->bEnableCameraRotationLag = false;
|
||
|
||
// 摄像机碰撞处理
|
||
CameraBoom->bDoCollisionTest = true;
|
||
CameraBoom->ProbeSize = 12.0f;
|
||
CameraBoom->ProbeChannel = ECC_Camera;
|
||
|
||
// Create a follow camera
|
||
FollowCamera = CreateDefaultSubobject<UCameraComponent>(TEXT("FollowCamera"));
|
||
FollowCamera->SetupAttachment(CameraBoom, USpringArmComponent::SocketName);
|
||
FollowCamera->bUsePawnControlRotation = false;
|
||
|
||
// 创建交互提示组件(替代旧 InteractionManager)
|
||
PromptComponent = CreateDefaultSubobject<UInteractionPromptComponent>(TEXT("PromptComponent"));
|
||
|
||
// 创建收集系统 HUD 组件(表现层,挂在角色上;Tick 兜底查找 Driver)
|
||
CollectionHUDComponent = CreateDefaultSubobject<UCollectionHUDComponent>(TEXT("CollectionHUDComponent"));
|
||
}
|
||
|
||
void AChildHoodCharacter::BeginPlay()
|
||
{
|
||
Super::BeginPlay();
|
||
|
||
// 初始化 PromptComponent — 将其与 ASystemDriver 关联
|
||
if (PromptComponent)
|
||
{
|
||
if (ASystemDriver* Driver = ASystemDriver::Get(this))
|
||
{
|
||
PromptComponent->Initialize(Driver);
|
||
}
|
||
}
|
||
|
||
// 初始化收集系统 HUD 组件(Driver 弱引用;Tick 会兜底查找,规避 BeginPlay 时序竞争)
|
||
if (CollectionHUDComponent)
|
||
{
|
||
if (ASystemDriver* Driver = ASystemDriver::Get(this))
|
||
{
|
||
CollectionHUDComponent->Initialize(Driver);
|
||
}
|
||
}
|
||
}
|
||
|
||
void AChildHoodCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
|
||
{
|
||
// Set up action bindings
|
||
if (UEnhancedInputComponent* EnhancedInputComponent = Cast<UEnhancedInputComponent>(PlayerInputComponent)) {
|
||
|
||
// Moving
|
||
EnhancedInputComponent->BindAction(MoveAction, ETriggerEvent::Triggered, this, &AChildHoodCharacter::Move);
|
||
|
||
// Looking (gamepad + mouse)
|
||
EnhancedInputComponent->BindAction(LookAction, ETriggerEvent::Triggered, this, &AChildHoodCharacter::Look);
|
||
EnhancedInputComponent->BindAction(MouseLookAction, ETriggerEvent::Triggered, this, &AChildHoodCharacter::Look);
|
||
|
||
// Interaction — delegates to ASystemDriver
|
||
if (InteractAction)
|
||
{
|
||
EnhancedInputComponent->BindAction(InteractAction, ETriggerEvent::Started, this, &AChildHoodCharacter::OnInteract);
|
||
}
|
||
if (CancelAction)
|
||
{
|
||
EnhancedInputComponent->BindAction(CancelAction, ETriggerEvent::Started, this, &AChildHoodCharacter::OnCancel);
|
||
}
|
||
if (SwitchInteractAction)
|
||
{
|
||
EnhancedInputComponent->BindAction(SwitchInteractAction, ETriggerEvent::Started, this, &AChildHoodCharacter::OnSwitchInteract);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
UE_LOG(LogChildHood, Error, TEXT("'%s' Failed to find an Enhanced Input component! This template is built to use the Enhanced Input system. If you intend to use the legacy system, then you will need to update this C++ file."), *GetNameSafe(this));
|
||
}
|
||
}
|
||
|
||
void AChildHoodCharacter::Move(const FInputActionValue& Value)
|
||
{
|
||
// input is a Vector2D
|
||
FVector2D MovementVector = Value.Get<FVector2D>();
|
||
|
||
// route the input
|
||
DoMove(MovementVector.X, MovementVector.Y);
|
||
}
|
||
|
||
void AChildHoodCharacter::Look(const FInputActionValue& Value)
|
||
{
|
||
// input is a Vector2D
|
||
FVector2D LookAxisVector = Value.Get<FVector2D>();
|
||
|
||
// route the input
|
||
DoLook(LookAxisVector.X, LookAxisVector.Y);
|
||
}
|
||
|
||
void AChildHoodCharacter::OnInteract(const FInputActionValue& Value)
|
||
{
|
||
ASystemDriver* Driver = ASystemDriver::Get(this);
|
||
if (!Driver) return;
|
||
|
||
auto& Mgr = Driver->GetInteractionManager();
|
||
auto& EFM = Driver->GetEffectManager();
|
||
|
||
// E 键三重功能:
|
||
// 1. Free 状态:发起交互
|
||
// 2. WaitForInput 暂停态:恢复 Effect(观察/对话类按 E 继续)
|
||
// 3. 可取消 Effect 执行中:取消 Effect
|
||
|
||
if (Mgr.GetState() == EInteractionState::Free)
|
||
{
|
||
// 发起交互
|
||
auto* Selected = Mgr.BeginInteract();
|
||
if (!Selected) return;
|
||
|
||
SetInteracting(true);
|
||
|
||
FEffectContext Ctx;
|
||
Ctx.Instigator = this;
|
||
Ctx.TargetComp = Selected;
|
||
Ctx.TargetActor = Selected->GetOwner();
|
||
EFM.PlayEffect(Selected->GetInteractableData().InteractEffect, Ctx);
|
||
}
|
||
else
|
||
{
|
||
// Executing 状态 → 尝试取消/恢复
|
||
EFM.CancelEffect();
|
||
}
|
||
}
|
||
|
||
void AChildHoodCharacter::OnCancel(const FInputActionValue& Value)
|
||
{
|
||
ASystemDriver* Driver = ASystemDriver::Get(this);
|
||
if (!Driver) return;
|
||
|
||
auto& EFM = Driver->GetEffectManager();
|
||
EFM.CancelEffect();
|
||
}
|
||
|
||
void AChildHoodCharacter::OnSwitchInteract(const FInputActionValue& Value)
|
||
{
|
||
ASystemDriver* Driver = ASystemDriver::Get(this);
|
||
if (!Driver) return;
|
||
|
||
auto& Mgr = Driver->GetInteractionManager();
|
||
// 交互中不可切换
|
||
if (Mgr.GetState() != EInteractionState::Free) return;
|
||
|
||
float DirectionValue = Value.Get<float>();
|
||
int32 Direction = (DirectionValue >= 0.f) ? 1 : -1;
|
||
Mgr.SwitchTarget(Direction);
|
||
}
|
||
|
||
void AChildHoodCharacter::DoMove(float Right, float Forward)
|
||
{
|
||
// 交互中屏蔽移动
|
||
if (bIsInteracting)
|
||
{
|
||
return;
|
||
}
|
||
|
||
if (GetController() != nullptr)
|
||
{
|
||
// find out which way is forward
|
||
const FRotator Rotation = GetController()->GetControlRotation();
|
||
const FRotator YawRotation(0, Rotation.Yaw, 0);
|
||
|
||
// get forward vector
|
||
const FVector ForwardDirection = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::X);
|
||
|
||
// get right vector
|
||
const FVector RightDirection = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::Y);
|
||
|
||
// add movement
|
||
AddMovementInput(ForwardDirection, Forward);
|
||
AddMovementInput(RightDirection, Right);
|
||
}
|
||
}
|
||
|
||
void AChildHoodCharacter::DoLook(float Yaw, float Pitch)
|
||
{
|
||
if (GetController() != nullptr)
|
||
{
|
||
// add yaw and pitch input to controller
|
||
AddControllerYawInput(Yaw);
|
||
AddControllerPitchInput(Pitch);
|
||
}
|
||
}
|
||
|
||
// ============================================================================
|
||
// 交互系统方法
|
||
// ============================================================================
|
||
|
||
UInteractionPromptComponent* AChildHoodCharacter::GetPromptComponent() const
|
||
{
|
||
return PromptComponent;
|
||
}
|
||
|
||
UCollectionHUDComponent* AChildHoodCharacter::GetCollectionHUDComponent() const
|
||
{
|
||
return CollectionHUDComponent;
|
||
}
|
||
|
||
void AChildHoodCharacter::SetInteracting(bool bValue)
|
||
{
|
||
bIsInteracting = bValue;
|
||
}
|
||
|
||
bool AChildHoodCharacter::IsInteracting() const
|
||
{
|
||
return bIsInteracting;
|
||
}
|
||
|
||
bool AChildHoodCharacter::IsRunning() const
|
||
{
|
||
return GetVelocity().SizeSquared() > 100.f // 速度 > 10 cm/s 阈值
|
||
&& GetCharacterMovement()->IsMovingOnGround();
|
||
}
|