200 lines
6.5 KiB
C++
200 lines
6.5 KiB
C++
// 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/InteractionManager.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 = CreateDefaultSubobject<UInteractionManager>(TEXT("InteractionManager"));
|
||
}
|
||
|
||
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 InteractionManager
|
||
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)
|
||
{
|
||
if (UInteractionManager* IM = GetInteractionManager())
|
||
{
|
||
// E 键双重功能:Free 发起交互,Active 结束交互
|
||
IM->BeginInteract();
|
||
IM->CancelInteract();
|
||
}
|
||
}
|
||
|
||
void AChildHoodCharacter::OnCancel(const FInputActionValue& Value)
|
||
{
|
||
if (UInteractionManager* IM = GetInteractionManager())
|
||
{
|
||
IM->CancelInteract();
|
||
}
|
||
}
|
||
|
||
void AChildHoodCharacter::OnSwitchInteract(const FInputActionValue& Value)
|
||
{
|
||
if (UInteractionManager* IM = GetInteractionManager())
|
||
{
|
||
float DirectionValue = Value.Get<float>();
|
||
int32 Direction = (DirectionValue >= 0.f) ? 1 : -1;
|
||
IM->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);
|
||
}
|
||
}
|
||
|
||
// ============================================================================
|
||
// 交互系统方法
|
||
// ============================================================================
|
||
|
||
UInteractionManager* AChildHoodCharacter::GetInteractionManager() const
|
||
{
|
||
return InteractionManager;
|
||
}
|
||
|
||
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();
|
||
}
|