Files
ChildHood/Source/ChildHood/Interaction/InteractionManager.h
T
starmen1265 c14c63f30d refactor(interaction): 适配v1.1架构的角色/管理器/交互物改动
- Character: 替换UInteractionManager为UInteractionPromptComponent
- GameInstance: 空壳化,持久数据迁移至PersistenceSubsystem
- InteractionManager: 重写为普通C++ FInteractionManager
- InteractableComponent: 碰撞回调接入ASystemDriver注册

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-11 23:21:46 +08:00

136 lines
4.6 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// ChildHood Project - 交互管理器(v1.1 Effect/Action 架构重写)
// 对应技术方案: docs/technical/交互系统-技术方案.md 第3节(类设计)+ 第6节(行为规则实现)
// 职责:检测列表维护、选中管理、顶层状态(Free/Executing)
// 架构:普通 C++ 类(非 UObject、非 UActorComponent),由 ASystemDriver 值持有
// 特点:纯事件驱动无 Tick,所有变化由外部调用触发
#pragma once
#include "CoreMinimal.h"
#include "InteractionTypes.h"
class UInteractableComponent;
class ACharacter;
/**
* FInteractionManager
*
* 普通C++类,负责交互检测列表维护和顶层状态管理。
* 由 ASystemDriver 值持有,不参与 UE 反射系统。
*
* 数据流:
* InteractableComponent 碰撞回调 → ASystemDriver → RegisterInteractable/UnregisterInteractable
* Character 输入回调 → ASystemDriver → BeginInteract/CancelInteract/SwitchTarget
* EffectManager 完成回调 → ASystemDriver → OnInteractionFinished
*/
class FInteractionManager
{
public:
/** 初始化管理器,绑定玩家角色引用 */
void Initialize(ACharacter* PlayerCharacter);
// === 交互物注册(由 InteractableComponent 碰撞回调通过 ASystemDriver 调用)===
/**
* 注册交互物到检测列表。
* 添加后按水平距离排序,重置选中索引为0,刷新缓存。
*/
void RegisterInteractable(UInteractableComponent* Interactable);
/**
* 从检测列表注销交互物。
* Executing 状态下如果移除的是 CurrentInteractable,仅从列表移除,
* CurrentInteractable 延迟清理(因为 Effect 可能仍在执行)。
*/
void UnregisterInteractable(UInteractableComponent* Interactable);
// === 交互触发(Character 输入回调中调用)===
/**
* 发起交互(E键触发)。
* 前置检查:State==Free、SelectedIndex有效、!IsConsumed()。
* 成功后 State=Executing,返回选中的 Component。
* 拒绝则返回 nullptr。
*/
UInteractableComponent* BeginInteract();
/**
* 取消交互(ESC/E键在Executing阶段触发)。
* v0.1 简化:仅设置状态标记,实际取消由 ASystemDriver 协调 EffectManager。
*/
void CancelInteract();
/**
* 切换选中目标(Tab/滚轮)。
* Direction: +1下一个 / -1上一个,循环。
* 仅在 Free 状态下响应。
*/
void SwitchTarget(int32 Direction);
// === 状态查询 ===
/** 获取当前顶层状态 */
EInteractionState GetState() const { return State; }
/** 当前是否有有效的选中交互物 */
bool HasSelection() const { return CachedSelected.bHasSelection; }
/** 获取选中交互物的提示文本(从缓存读取,不访问 Component) */
FString GetSelectedPromptText() const { return CachedSelected.PromptText; }
/** 获取选中交互物的世界坐标(从缓存读取) */
FVector GetSelectedWorldPosition() const { return CachedSelected.WorldPosition; }
/** 获取完整的选中信息缓存 */
const FSelectedInfo& GetCachedSelectedInfo() const { return CachedSelected; }
// === Effect 完成回调(由 EffectManager 通过 ASystemDriver 调用)===
/**
* Effect 执行完毕回调。
* State 回到 Free,清理 CurrentInteractable,通知 Character 解除交互,
* 重新排序和刷新缓存(因为消耗可能改变了列表)。
*/
void OnInteractionFinished();
// === 当前交互物访问(EffectManager 需要访问)===
/** 获取当前正在交互的交互物(Executing 状态下有效) */
UInteractableComponent* GetCurrentInteractable() const;
private:
/** 交互系统顶层状态 */
EInteractionState State = EInteractionState::Free;
/** 当前附近的交互物列表,按水平距离排序 */
TArray<TWeakObjectPtr<UInteractableComponent>> NearbyInteractables;
/** 当前选中的交互物索引(NearbyInteractables 中的下标) */
int32 SelectedIndex = 0;
/** 当前正在交互的交互物(Executing 状态下锁定) */
TWeakObjectPtr<UInteractableComponent> CurrentInteractable;
/** 玩家角色弱引用(用于排序距离计算和 SetInteracting 调用) */
TWeakObjectPtr<ACharacter> PlayerCharacter;
/** Presentation 层缓存数据 — 选中交互物的摘要信息 */
FSelectedInfo CachedSelected;
// === 内部方法 ===
/**
* 更新选中交互物:按与玩家的水平距离排序,重置 SelectedIndex=0。
* 同时清理已失效的弱引用。
*/
void UpdateSelection();
/**
* 从 Component 读取选中项信息并写入 CachedSelected。
* Presentation 层每帧只读 CachedSelected,不直接访问 Component。
*/
void RefreshCachedSelection();
};