feat(interaction): Character和PlayerController集成交互系统

This commit is contained in:
2026-06-11 11:25:30 +08:00
parent 00ca7044c7
commit 5df451011c
4 changed files with 159 additions and 11 deletions
+32 -6
View File
@@ -11,12 +11,13 @@
#include "EnhancedInputSubsystems.h" #include "EnhancedInputSubsystems.h"
#include "InputActionValue.h" #include "InputActionValue.h"
#include "ChildHood.h" #include "ChildHood.h"
#include "Interaction/InteractionManager.h"
AChildHoodCharacter::AChildHoodCharacter() AChildHoodCharacter::AChildHoodCharacter()
{ {
// Set size for collision capsule // Set size for collision capsule
GetCapsuleComponent()->InitCapsuleSize(42.f, 96.0f); GetCapsuleComponent()->InitCapsuleSize(42.f, 96.0f);
// Don't rotate when the controller rotates. Let that just affect the camera. // Don't rotate when the controller rotates. Let that just affect the camera.
bUseControllerRotationPitch = false; bUseControllerRotationPitch = false;
bUseControllerRotationYaw = false; bUseControllerRotationYaw = false;
@@ -46,15 +47,15 @@ AChildHoodCharacter::AChildHoodCharacter()
FollowCamera->SetupAttachment(CameraBoom, USpringArmComponent::SocketName); FollowCamera->SetupAttachment(CameraBoom, USpringArmComponent::SocketName);
FollowCamera->bUsePawnControlRotation = false; FollowCamera->bUsePawnControlRotation = false;
// Note: The skeletal mesh and anim blueprint references on the Mesh component (inherited from Character) // 创建交互管理器组件
// are set in the derived blueprint asset named ThirdPersonCharacter (to avoid direct content references in C++) InteractionManager = CreateDefaultSubobject<UInteractionManager>(TEXT("InteractionManager"));
} }
void AChildHoodCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent) void AChildHoodCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{ {
// Set up action bindings // Set up action bindings
if (UEnhancedInputComponent* EnhancedInputComponent = Cast<UEnhancedInputComponent>(PlayerInputComponent)) { if (UEnhancedInputComponent* EnhancedInputComponent = Cast<UEnhancedInputComponent>(PlayerInputComponent)) {
// Jumping // Jumping
EnhancedInputComponent->BindAction(JumpAction, ETriggerEvent::Started, this, &ACharacter::Jump); EnhancedInputComponent->BindAction(JumpAction, ETriggerEvent::Started, this, &ACharacter::Jump);
EnhancedInputComponent->BindAction(JumpAction, ETriggerEvent::Completed, this, &ACharacter::StopJumping); EnhancedInputComponent->BindAction(JumpAction, ETriggerEvent::Completed, this, &ACharacter::StopJumping);
@@ -92,6 +93,12 @@ void AChildHoodCharacter::Look(const FInputActionValue& Value)
void AChildHoodCharacter::DoMove(float Right, float Forward) void AChildHoodCharacter::DoMove(float Right, float Forward)
{ {
// 交互中屏蔽移动
if (bIsInteracting)
{
return;
}
if (GetController() != nullptr) if (GetController() != nullptr)
{ {
// find out which way is forward // find out which way is forward
@@ -101,10 +108,10 @@ void AChildHoodCharacter::DoMove(float Right, float Forward)
// get forward vector // get forward vector
const FVector ForwardDirection = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::X); const FVector ForwardDirection = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::X);
// get right vector // get right vector
const FVector RightDirection = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::Y); const FVector RightDirection = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::Y);
// add movement // add movement
AddMovementInput(ForwardDirection, Forward); AddMovementInput(ForwardDirection, Forward);
AddMovementInput(RightDirection, Right); AddMovementInput(RightDirection, Right);
} }
@@ -131,3 +138,22 @@ void AChildHoodCharacter::DoJumpEnd()
// signal the character to stop jumping // signal the character to stop jumping
StopJumping(); StopJumping();
} }
// ============================================================================
// 交互系统方法
// ============================================================================
UInteractionManager* AChildHoodCharacter::GetInteractionManager() const
{
return InteractionManager;
}
void AChildHoodCharacter::SetInteracting(bool bValue)
{
bIsInteracting = bValue;
}
bool AChildHoodCharacter::IsInteracting() const
{
return bIsInteracting;
}
+22 -3
View File
@@ -10,6 +10,7 @@
class USpringArmComponent; class USpringArmComponent;
class UCameraComponent; class UCameraComponent;
class UInputAction; class UInputAction;
class UInteractionManager;
struct FInputActionValue; struct FInputActionValue;
DECLARE_LOG_CATEGORY_EXTERN(LogTemplateCharacter, Log, All); DECLARE_LOG_CATEGORY_EXTERN(LogTemplateCharacter, Log, All);
@@ -30,7 +31,7 @@ class AChildHoodCharacter : public ACharacter
/** Follow camera */ /** Follow camera */
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Components", meta = (AllowPrivateAccess = "true")) UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Components", meta = (AllowPrivateAccess = "true"))
UCameraComponent* FollowCamera; UCameraComponent* FollowCamera;
protected: protected:
/** Jump Input Action */ /** Jump Input Action */
@@ -49,10 +50,29 @@ protected:
UPROPERTY(EditAnywhere, Category="Input") UPROPERTY(EditAnywhere, Category="Input")
UInputAction* MouseLookAction; UInputAction* MouseLookAction;
/** 交互管理器组件 */
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Interaction", meta = (AllowPrivateAccess = "true"))
UInteractionManager* InteractionManager;
/** 是否处于交互状态(交互期间屏蔽移动) */
bool bIsInteracting = false;
public: public:
/** Constructor */ /** Constructor */
AChildHoodCharacter(); AChildHoodCharacter();
/** 获取交互管理器组件 */
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Interaction")
UInteractionManager* GetInteractionManager() const;
/** 设置交互状态(InteractionManager 调用,控制移动屏蔽) */
UFUNCTION(BlueprintCallable, Category = "Interaction")
void SetInteracting(bool bValue);
/** 查询当前是否在交互中 */
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Interaction")
bool IsInteracting() const;
protected: protected:
@@ -93,4 +113,3 @@ public:
/** Returns FollowCamera subobject **/ /** Returns FollowCamera subobject **/
FORCEINLINE class UCameraComponent* GetFollowCamera() const { return FollowCamera; } FORCEINLINE class UCameraComponent* GetFollowCamera() const { return FollowCamera; }
}; };
+78 -1
View File
@@ -1,7 +1,9 @@
// Copyright Epic Games, Inc. All Rights Reserved. // Copyright Epic Games, Inc. All Rights Reserved.
#include "ChildHoodPlayerController.h" #include "ChildHoodPlayerController.h"
#include "ChildHoodCharacter.h"
#include "Interaction/InteractionManager.h"
#include "EnhancedInputComponent.h"
#include "EnhancedInputSubsystems.h" #include "EnhancedInputSubsystems.h"
#include "Engine/LocalPlayer.h" #include "Engine/LocalPlayer.h"
#include "InputMappingContext.h" #include "InputMappingContext.h"
@@ -57,6 +59,28 @@ 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);
}
}
} }
} }
@@ -65,3 +89,56 @@ bool AChildHoodPlayerController::ShouldUseTouchControls() const
// are we on a mobile platform? Should we force touch? // are we on a mobile platform? Should we force touch?
return SVirtualJoystick::ShouldDisplayTouchInterface() || bForceTouchControls; 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);
}
}
}
}
+27 -1
View File
@@ -7,7 +7,9 @@
#include "ChildHoodPlayerController.generated.h" #include "ChildHoodPlayerController.generated.h"
class UInputMappingContext; class UInputMappingContext;
class UInputAction;
class UUserWidget; class UUserWidget;
struct FInputActionValue;
/** /**
* Basic PlayerController class for a third person game * Basic PlayerController class for a third person game
@@ -17,7 +19,7 @@ UCLASS(abstract)
class AChildHoodPlayerController : public APlayerController class AChildHoodPlayerController : public APlayerController
{ {
GENERATED_BODY() GENERATED_BODY()
protected: protected:
/** Input Mapping Contexts */ /** Input Mapping Contexts */
@@ -40,6 +42,20 @@ protected:
UPROPERTY(EditAnywhere, Config, Category = "Input|Touch Controls") UPROPERTY(EditAnywhere, Config, Category = "Input|Touch Controls")
bool bForceTouchControls = false; 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 */ /** Gameplay initialization */
virtual void BeginPlay() override; virtual void BeginPlay() override;
@@ -49,4 +65,14 @@ protected:
/** Returns true if the player should use UMG touch controls */ /** Returns true if the player should use UMG touch controls */
bool ShouldUseTouchControls() const; bool ShouldUseTouchControls() const;
private:
/** E 键按下回调:发起交互 */
void OnInteractPressed();
/** ESC 键按下回调:取消/结束交互 */
void OnCancelPressed();
/** Tab/滚轮回调:切换交互目标 */
void OnSwitchInteract(const FInputActionValue& Value);
}; };