4bf678b937
新增: - 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>
161 lines
4.2 KiB
C++
161 lines
4.2 KiB
C++
// 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;
|
||
}
|
||
}
|