Files
ChildHood/Source/ChildHood/Interaction/InteractionPromptComponent.cpp
T
starmen1265 4bf678b937 feat(interaction): 交互系统v1.1 Effect/Action架构实现
新增:
- EffectManager: Effect Timeline调度 + Action执行分发
- SystemDriver: AInfo全局驱动器, 持有FInteractionManager/FEffectManager
- InteractionPromptComponent: 独立Prompt UI组件(只读Manager缓存)
- DoorActor/DoorInteractableComponent: 门派生类

修改:
- InteractionManager: 从UActorComponent重写为普通C++ FInteractionManager
- Character: 替换旧InteractionManager为PromptComponent, 通过Driver访问Manager
- GameInstance: 空壳化, 持久数据迁移至PersistenceSubsystem
- InteractableComponent: 碰撞回调接入ASystemDriver注册路径

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

161 lines
4.2 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 - 交互提示追踪组件 实现
// 对应技术方案: docs/technical/交互系统-技术方案.md 第6节(提示UI显示/隐藏)
// 职责:Free 状态下追踪 Manager 缓存,更新 Prompt Widget 位置和文本
#include "Interaction/InteractionPromptComponent.h"
#include "Interaction/InteractionPromptWidget.h"
#include "SystemDriver.h"
#include "Interaction/InteractionManager.h"
#include "ChildHood.h"
#include "Engine/World.h"
#include "Blueprint/WidgetLayoutLibrary.h"
#include "Kismet/GameplayStatics.h"
#include "GameFramework/PlayerController.h"
// ============================================================================
// 构造函数
// ============================================================================
UInteractionPromptComponent::UInteractionPromptComponent()
{
// 启用 Tick,每帧更新 Prompt 位置
PrimaryComponentTick.bCanEverTick = true;
PrimaryComponentTick.bStartWithTickEnabled = true;
}
// ============================================================================
// 初始化
// ============================================================================
void UInteractionPromptComponent::Initialize(ASystemDriver* InDriver)
{
Driver = InDriver;
UE_LOG(LogChildHood, Log, TEXT("InteractionPromptComponent: 初始化完成, Driver=%s"),
InDriver ? *InDriver->GetName() : TEXT("nullptr"));
}
// ============================================================================
// 生命周期
// ============================================================================
void UInteractionPromptComponent::BeginPlay()
{
Super::BeginPlay();
// 根据 PromptWidgetClass 创建 Prompt Widget
if (PromptWidgetClass)
{
if (APlayerController* PC = GetWorld()
? GetWorld()->GetFirstPlayerController()
: nullptr)
{
PromptWidget = CreateWidget<UInteractionPromptWidget>(PC, PromptWidgetClass);
if (PromptWidget)
{
PromptWidget->AddToViewport();
PromptWidget->SetVisibility(ESlateVisibility::Hidden);
UE_LOG(LogChildHood, Log, TEXT("InteractionPromptComponent: Prompt Widget 创建完成"));
}
}
else
{
UE_LOG(LogChildHood, Warning, TEXT("InteractionPromptComponent: 无法获取 PlayerController,Prompt Widget 未创建"));
}
}
else
{
UE_LOG(LogChildHood, Warning, TEXT("InteractionPromptComponent: PromptWidgetClass 未设置,Prompt Widget 未创建"));
}
}
void UInteractionPromptComponent::TickComponent(float DeltaTime, ELevelTick TickType,
FActorComponentTickFunction* ThisTickFunction)
{
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
// 没有 Widget 则跳过
if (!PromptWidget)
{
return;
}
// 获取 Driver(弱引用检查)
ASystemDriver* DriverPtr = Driver.Get();
if (!DriverPtr)
{
HidePrompt();
return;
}
// 获取 InteractionManager 引用
FInteractionManager& Manager = DriverPtr->GetInteractionManager();
// 检查 State == Free 且 HasSelection()
if (Manager.GetState() == EInteractionState::Free && Manager.HasSelection())
{
UpdatePrompt();
}
else
{
HidePrompt();
}
}
// ============================================================================
// Prompt 显示/隐藏
// ============================================================================
void UInteractionPromptComponent::UpdatePrompt()
{
ASystemDriver* DriverPtr = Driver.Get();
if (!DriverPtr || !PromptWidget)
{
return;
}
FInteractionManager& Manager = DriverPtr->GetInteractionManager();
// 从 Manager 缓存读取数据
FString PromptText = Manager.GetSelectedPromptText();
FVector WorldPos = Manager.GetSelectedWorldPosition();
// 应用高度偏移
FVector AdjustedPos = WorldPos + FVector(0.f, 0.f, PromptHeightOffset);
// ProjectWorldToScreen
APlayerController* PC = GetWorld()
? GetWorld()->GetFirstPlayerController()
: nullptr;
if (!PC)
{
return;
}
FVector2D ScreenPos;
bool bOnScreen = PC->ProjectWorldLocationToScreen(AdjustedPos, ScreenPos, true);
if (!bOnScreen)
{
HidePrompt();
return;
}
// 更新 Widget 位置和文本
PromptWidget->SetPromptText(PromptText);
PromptWidget->SetScreenPosition(ScreenPos);
PromptWidget->Show();
bWasShowingPrompt = true;
}
void UInteractionPromptComponent::HidePrompt()
{
if (PromptWidget && bWasShowingPrompt)
{
PromptWidget->Hide();
bWasShowingPrompt = false;
}
}