207 lines
6.2 KiB
C++
207 lines
6.2 KiB
C++
// ChildHood Project - 交互管理器核心组件
|
||
// 对应技术方案: docs/technical/交互系统-技术方案.md 第3节(类设计)+ 第6节(行为规则实现)
|
||
// 职责:交互全流程状态机、检测选择、类型分发、摄像机/转向/UI 控制
|
||
|
||
#pragma once
|
||
|
||
#include "CoreMinimal.h"
|
||
#include "Components/ActorComponent.h"
|
||
#include "InteractionTypes.h"
|
||
#include "InteractionManager.generated.h"
|
||
|
||
class UInteractableComponent;
|
||
class APushCameraActor;
|
||
class AChildHoodCharacter;
|
||
|
||
/**
|
||
* UInteractionManager
|
||
*
|
||
* 挂载在 AChildHoodCharacter 上的组件,负责交互全流程管理:
|
||
* - 层级状态机驱动(Free / Interacting + 子阶段)
|
||
* - 附近交互物检测列表排序与选中管理
|
||
* - 四种交互类型分发(观察/拾取/操作/对话)
|
||
* - 角色自动转向插值
|
||
* - 摄像机推镜/回位控制
|
||
* - UI 提示与文本显示控制(v0.1 先用日志)
|
||
*/
|
||
UCLASS(ClassGroup=(Interaction), meta=(BlueprintSpawnableComponent))
|
||
class UInteractionManager : public UActorComponent
|
||
{
|
||
GENERATED_BODY()
|
||
|
||
public:
|
||
|
||
UInteractionManager();
|
||
|
||
// === 公开方法 ===
|
||
|
||
/** 发起交互(E键触发),前置检查通过后进入 Enter 阶段 */
|
||
UFUNCTION(BlueprintCallable, Category = "Interaction")
|
||
void BeginInteract();
|
||
|
||
/** 取消/结束交互(ESC/E键在Active阶段触发),AnimLock期间不可取消 */
|
||
UFUNCTION(BlueprintCallable, Category = "Interaction")
|
||
void CancelInteract();
|
||
|
||
/** 切换选中交互物(Tab/滚轮),Direction: +1下一个 / -1上一个 */
|
||
UFUNCTION(BlueprintCallable, Category = "Interaction")
|
||
void SwitchTarget(int32 Direction);
|
||
|
||
/** 注册交互物到检测列表(由 InteractableComponent 的碰撞回调触发) */
|
||
UFUNCTION(BlueprintCallable, Category = "Interaction")
|
||
void RegisterInteractable(UInteractableComponent* Interactable);
|
||
|
||
/** 从检测列表注销交互物(离开范围或消耗时触发) */
|
||
UFUNCTION(BlueprintCallable, Category = "Interaction")
|
||
void UnregisterInteractable(UInteractableComponent* Interactable);
|
||
|
||
// === 委托 ===
|
||
|
||
/** 物品拾取事件 — 通知物品系统(Pickup 类型 ExecuteAnimEvent 中广播) */
|
||
UPROPERTY(BlueprintAssignable, Category = "Interaction|Events")
|
||
FMLocalItemEvent OnItemPickedUp;
|
||
|
||
/** 物品获得事件 — 通知收集系统(Search 类型 OnAnimLockComplete 中广播) */
|
||
UPROPERTY(BlueprintAssignable, Category = "Interaction|Events")
|
||
FMLocalItemEvent OnItemFound;
|
||
|
||
// === 可调参数 ===
|
||
|
||
/** 角色转向时长(秒) */
|
||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Interaction|Tuning")
|
||
float TurnDuration = 0.2f;
|
||
|
||
/** 提示 UI 淡入时长(秒) */
|
||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Interaction|Tuning")
|
||
float PromptFadeInDuration = 0.2f;
|
||
|
||
/** 提示 UI 淡出时长(秒) */
|
||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Interaction|Tuning")
|
||
float PromptFadeOutDuration = 0.2f;
|
||
|
||
protected:
|
||
|
||
virtual void BeginPlay() override;
|
||
virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
|
||
|
||
private:
|
||
|
||
// === 状态机 ===
|
||
|
||
/** 交互系统顶层状态 */
|
||
EInteractionState State = EInteractionState::Free;
|
||
|
||
/** Interacting 子阶段 */
|
||
EInteractPhase Phase = EInteractPhase::None;
|
||
|
||
// === 检测与选择 ===
|
||
|
||
/** 当前附近的交互物列表,按水平距离排序 */
|
||
UPROPERTY()
|
||
TArray<UInteractableComponent*> NearbyInteractables;
|
||
|
||
/** 当前选中的交互物索引 */
|
||
int32 SelectedIndex = 0;
|
||
|
||
/** 当前正在交互的交互物(交互过程中锁定) */
|
||
UPROPERTY()
|
||
UInteractableComponent* CurrentInteractable = nullptr;
|
||
|
||
// === 摄像机控制 ===
|
||
|
||
/** 推镜用临时摄像机 Actor(BeginPlay 中 Spawn) */
|
||
UPROPERTY()
|
||
TObjectPtr<APushCameraActor> PushCameraActor;
|
||
|
||
/** 推镜是否已发起(Enter阶段一次性标志) */
|
||
bool bPushStarted = false;
|
||
|
||
// === 计时器 ===
|
||
|
||
/** 转向已用时间 */
|
||
float TurnElapsed = 0.0f;
|
||
|
||
/** 推镜后等待已用时间 */
|
||
float WaitElapsed = 0.0f;
|
||
|
||
/** 动画事件计时器(如60%时物品消失) */
|
||
FTimerHandle AnimEventTimerHandle;
|
||
|
||
/** 动画结束计时器 */
|
||
FTimerHandle AnimEndTimerHandle;
|
||
|
||
/** 退出阶段回位计时器 */
|
||
FTimerHandle ExitTimerHandle;
|
||
|
||
/** 动画事件是否已触发 */
|
||
bool bAnimEventFired = false;
|
||
|
||
// === UI 引用(v0.1 后续任务创建) ===
|
||
|
||
/** 交互提示 Widget(v0.1 用日志替代) */
|
||
UPROPERTY()
|
||
TObjectPtr<UUserWidget> PromptWidget;
|
||
|
||
/** 文本底框 Widget(v0.1 用日志替代) */
|
||
UPROPERTY()
|
||
TObjectPtr<UUserWidget> NarrativeWidget;
|
||
|
||
// === 文本选择 ===
|
||
|
||
/** 上次显示的叙事文本(用于不重复选取) */
|
||
FString LastNarrativeText;
|
||
|
||
// === 内部方法 ===
|
||
|
||
/** 更新选中交互物(排序后 SelectedIndex = 0) */
|
||
void UpdateSelection();
|
||
|
||
/** 更新提示 UI(v0.1 用日志输出) */
|
||
void UpdatePromptUI();
|
||
|
||
/** 隐藏提示 UI(v0.1 用日志输出) */
|
||
void HidePrompt();
|
||
|
||
/** Enter 阶段 Tick:转向插值 + 推镜 + 等待 */
|
||
void TickEnterPhase(float DeltaTime);
|
||
|
||
/** AnimLock 阶段 Tick(v0.1 由计时器驱动,此处可为空) */
|
||
void TickAnimLockPhase(float DeltaTime);
|
||
|
||
/** Exit 阶段 Tick(v0.1 由定时器驱动回 Free) */
|
||
void TickExitPhase(float DeltaTime);
|
||
|
||
/** Enter 阶段完成后,根据交互类型分发到下一阶段 */
|
||
void TransitionFromEnter();
|
||
|
||
/** 进入 AnimLock 阶段:播放蒙太奇或启动计时器 */
|
||
void EnterAnimLockPhase();
|
||
|
||
/** 动画事件触发点回调(如拾取物消失、门状态切换) */
|
||
void ExecuteAnimEvent();
|
||
|
||
/** 动画结束回调 */
|
||
void OnAnimLockComplete();
|
||
|
||
/** 显示叙事文本(v0.1 用日志输出) */
|
||
void ShowNarrativeText(const FString& Text);
|
||
|
||
/** 隐藏叙事文本(v0.1 用日志输出) */
|
||
void HideNarrativeText();
|
||
|
||
/** 推镜:移动 PushCameraActor 并切换 ViewTarget */
|
||
void PushCamera(FVector Target, float Duration);
|
||
|
||
/** 相机回位:切换回 Character 的 FollowCamera */
|
||
void ReturnCamera(float Duration);
|
||
|
||
/** 计算推镜目标位置 */
|
||
FVector CalculatePushPosition(UInteractableComponent* Interactable);
|
||
|
||
/** 随机选取叙事文本,排除上次 */
|
||
FString PickRandomNarrative(const TArray<FString>& Texts);
|
||
|
||
/** Exit 阶段定时器回调:回到 Free 状态 */
|
||
void OnExitTimerComplete();
|
||
};
|