merge: 合并main分支,解决冲突并统一交互输入架构

This commit is contained in:
2026-06-11 14:26:44 +08:00
26 changed files with 4304 additions and 272 deletions
+71 -31
View File
@@ -23,25 +23,33 @@ AChildHoodCharacter::AChildHoodCharacter()
bUseControllerRotationYaw = false;
bUseControllerRotationRoll = false;
// Configure character movement
GetCharacterMovement()->bOrientRotationToMovement = true;
GetCharacterMovement()->RotationRate = FRotator(0.0f, 500.0f, 0.0f);
// Note: For faster iteration times these variables, and many more, can be tweaked in the Character Blueprint
// instead of recompiling to adjust them
GetCharacterMovement()->JumpZVelocity = 500.f;
GetCharacterMovement()->AirControl = 0.35f;
GetCharacterMovement()->MaxWalkSpeed = 500.f;
GetCharacterMovement()->MinAnalogWalkSpeed = 20.f;
GetCharacterMovement()->BrakingDecelerationWalking = 2000.f;
GetCharacterMovement()->BrakingDecelerationFalling = 1500.0f;
// 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 = 400.0f;
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);
@@ -56,16 +64,26 @@ void AChildHoodCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInput
// Set up action bindings
if (UEnhancedInputComponent* EnhancedInputComponent = Cast<UEnhancedInputComponent>(PlayerInputComponent)) {
// Jumping
EnhancedInputComponent->BindAction(JumpAction, ETriggerEvent::Started, this, &ACharacter::Jump);
EnhancedInputComponent->BindAction(JumpAction, ETriggerEvent::Completed, this, &ACharacter::StopJumping);
// 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);
// Looking
EnhancedInputComponent->BindAction(LookAction, 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
{
@@ -91,6 +109,34 @@ void AChildHoodCharacter::Look(const FInputActionValue& Value)
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)
{
// 交互中屏蔽移动
@@ -127,18 +173,6 @@ void AChildHoodCharacter::DoLook(float Yaw, float Pitch)
}
}
void AChildHoodCharacter::DoJumpStart()
{
// signal the character to jump
Jump();
}
void AChildHoodCharacter::DoJumpEnd()
{
// signal the character to stop jumping
StopJumping();
}
// ============================================================================
// 交互系统方法
// ============================================================================
@@ -157,3 +191,9 @@ bool AChildHoodCharacter::IsInteracting() const
{
return bIsInteracting;
}
bool AChildHoodCharacter::IsRunning() const
{
return GetVelocity().SizeSquared() > 100.f // 速度 > 10 cm/s 阈值
&& GetCharacterMovement()->IsMovingOnGround();
}
+29 -16
View File
@@ -34,10 +34,6 @@ class AChildHoodCharacter : public ACharacter
protected:
/** Jump Input Action */
UPROPERTY(EditAnywhere, Category="Input")
UInputAction* JumpAction;
/** Move Input Action */
UPROPERTY(EditAnywhere, Category="Input")
UInputAction* MoveAction;
@@ -50,11 +46,23 @@ protected:
UPROPERTY(EditAnywhere, Category="Input")
UInputAction* MouseLookAction;
/** Interact Input Action (E key) — delegates to interaction system */
UPROPERTY(EditAnywhere, Category="Input")
UInputAction* InteractAction;
/** Cancel Input Action (ESC key) — delegates to interaction system */
UPROPERTY(EditAnywhere, Category="Input")
UInputAction* CancelAction;
/** Switch Interact Target Input Action (Tab / Mouse Wheel) — delegates to interaction system */
UPROPERTY(EditAnywhere, Category="Input")
UInputAction* SwitchInteractAction;
/** 交互管理器组件 */
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Interaction", meta = (AllowPrivateAccess = "true"))
UInteractionManager* InteractionManager;
/** 是否处于交互状态(交互期间屏蔽移动) */
/** Whether the character is currently in an interaction */
bool bIsInteracting = false;
public:
@@ -66,14 +74,18 @@ public:
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Interaction")
UInteractionManager* GetInteractionManager() const;
/** 设置交互状态(InteractionManager 调用,控制移动屏蔽) */
/** Set interaction state — called by interaction system */
UFUNCTION(BlueprintCallable, Category = "Interaction")
void SetInteracting(bool bValue);
/** 查询当前是否在交互中 */
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Interaction")
/** Query: is the character currently interacting? */
UFUNCTION(BlueprintCallable, BlueprintPure, Category="Interaction")
bool IsInteracting() const;
/** Query: is the character currently running (moving on ground)? */
UFUNCTION(BlueprintCallable, BlueprintPure, Category="Interaction")
bool IsRunning() const;
protected:
/** Initialize input action bindings */
@@ -87,6 +99,15 @@ protected:
/** Called for looking input */
void Look(const FInputActionValue& Value);
/** Called for interact input (E) — delegates to InteractionManager */
void OnInteract(const FInputActionValue& Value);
/** Called for cancel input (ESC) — delegates to InteractionManager */
void OnCancel(const FInputActionValue& Value);
/** Called for switch interact target input (Tab/Wheel) — delegates to InteractionManager */
void OnSwitchInteract(const FInputActionValue& Value);
public:
/** Handles move inputs from either controls or UI interfaces */
@@ -97,14 +118,6 @@ public:
UFUNCTION(BlueprintCallable, Category="Input")
virtual void DoLook(float Yaw, float Pitch);
/** Handles jump pressed inputs from either controls or UI interfaces */
UFUNCTION(BlueprintCallable, Category="Input")
virtual void DoJumpStart();
/** Handles jump pressed inputs from either controls or UI interfaces */
UFUNCTION(BlueprintCallable, Category="Input")
virtual void DoJumpEnd();
public:
/** Returns CameraBoom subobject **/
+14 -78
View File
@@ -1,9 +1,7 @@
// Copyright Epic Games, Inc. All Rights Reserved.
#include "ChildHoodPlayerController.h"
#include "ChildHoodCharacter.h"
#include "Interaction/InteractionManager.h"
#include "EnhancedInputComponent.h"
#include "EnhancedInputSubsystems.h"
#include "Engine/LocalPlayer.h"
#include "InputMappingContext.h"
@@ -15,6 +13,19 @@ void AChildHoodPlayerController::BeginPlay()
{
Super::BeginPlay();
// C3: 设置摄像机俯仰角限制(垂直旋转 +45°/-30°)
if (PlayerCameraManager)
{
PlayerCameraManager->ViewPitchMin = -30.0f; // 向下看最多 30°
PlayerCameraManager->ViewPitchMax = 45.0f; // 向上看最多 45°
}
// C1: 初始俯角 -15°(摄像机默认略向下看向角色)
if (GetControlRotation().Pitch == 0.f)
{
SetControlRotation(FRotator(-15.0f, GetControlRotation().Yaw, GetControlRotation().Roll));
}
// only spawn touch controls on local player controllers
if (ShouldUseTouchControls() && IsLocalPlayerController())
{
@@ -59,28 +70,6 @@ void AChildHoodPlayerController::SetupInputComponent()
}
}
}
// 绑定交互输入(Enhanced Input Action)
if (UEnhancedInputComponent* EnhancedInputComponent = Cast<UEnhancedInputComponent>(InputComponent))
{
// 交互(E 键)
if (InteractAction)
{
EnhancedInputComponent->BindAction(InteractAction, ETriggerEvent::Started, this, &AChildHoodPlayerController::OnInteractPressed);
}
// 取消(ESC 键)
if (CancelAction)
{
EnhancedInputComponent->BindAction(CancelAction, ETriggerEvent::Started, this, &AChildHoodPlayerController::OnCancelPressed);
}
// 切换交互目标(Tab/滚轮)
if (SwitchInteractAction)
{
EnhancedInputComponent->BindAction(SwitchInteractAction, ETriggerEvent::Triggered, this, &AChildHoodPlayerController::OnSwitchInteract);
}
}
}
}
@@ -89,56 +78,3 @@ bool AChildHoodPlayerController::ShouldUseTouchControls() const
// are we on a mobile platform? Should we force touch?
return SVirtualJoystick::ShouldDisplayTouchInterface() || bForceTouchControls;
}
// ============================================================================
// 交互输入回调
// ============================================================================
void AChildHoodPlayerController::OnInteractPressed()
{
if (APawn* MyPawn = GetPawn())
{
if (AChildHoodCharacter* Char = Cast<AChildHoodCharacter>(MyPawn))
{
if (UInteractionManager* IM = Char->GetInteractionManager())
{
// E 键双重功能:Free 状态发起交互,Active 阶段结束交互
// BeginInteract 在非 Free 状态会被拒绝(内部 return)
// CancelInteract 在非 Interacting 状态或 AnimLock 阶段会被拒绝
IM->BeginInteract();
IM->CancelInteract();
}
}
}
}
void AChildHoodPlayerController::OnCancelPressed()
{
if (APawn* MyPawn = GetPawn())
{
if (AChildHoodCharacter* Char = Cast<AChildHoodCharacter>(MyPawn))
{
if (UInteractionManager* IM = Char->GetInteractionManager())
{
IM->CancelInteract();
}
}
}
}
void AChildHoodPlayerController::OnSwitchInteract(const FInputActionValue& Value)
{
if (APawn* MyPawn = GetPawn())
{
if (AChildHoodCharacter* Char = Cast<AChildHoodCharacter>(MyPawn))
{
if (UInteractionManager* IM = Char->GetInteractionManager())
{
// 读取 float 值作为方向:正值=下一个,负值=上一个
float DirectionValue = Value.Get<float>();
int32 Direction = (DirectionValue >= 0.f) ? 1 : -1;
IM->SwitchTarget(Direction);
}
}
}
}
+1 -27
View File
@@ -7,9 +7,7 @@
#include "ChildHoodPlayerController.generated.h"
class UInputMappingContext;
class UInputAction;
class UUserWidget;
struct FInputActionValue;
/**
* Basic PlayerController class for a third person game
@@ -19,7 +17,7 @@ UCLASS(abstract)
class AChildHoodPlayerController : public APlayerController
{
GENERATED_BODY()
protected:
/** Input Mapping Contexts */
@@ -42,20 +40,6 @@ protected:
UPROPERTY(EditAnywhere, Config, Category = "Input|Touch Controls")
bool bForceTouchControls = false;
// === 交互输入 ===
/** 交互输入动作(E 键) */
UPROPERTY(EditAnywhere, Category = "Input|Interaction")
UInputAction* InteractAction;
/** 取消输入动作(ESC 键) */
UPROPERTY(EditAnywhere, Category = "Input|Interaction")
UInputAction* CancelAction;
/** 切换交互目标输入动作(Tab/滚轮) */
UPROPERTY(EditAnywhere, Category = "Input|Interaction")
UInputAction* SwitchInteractAction;
/** Gameplay initialization */
virtual void BeginPlay() override;
@@ -65,14 +49,4 @@ protected:
/** Returns true if the player should use UMG touch controls */
bool ShouldUseTouchControls() const;
private:
/** E 键按下回调:发起交互 */
void OnInteractPressed();
/** ESC 键按下回调:取消/结束交互 */
void OnCancelPressed();
/** Tab/滚轮回调:切换交互目标 */
void OnSwitchInteract(const FInputActionValue& Value);
};