From 237885e3b8687b3d880ff0f74a33ed6d454efb34 Mon Sep 17 00:00:00 2001 From: starmen1265 Date: Fri, 12 Jun 2026 00:51:00 +0800 Subject: [PATCH] =?UTF-8?q?fix(interaction):=20=E4=BF=AE=E5=A4=8D=E7=BC=96?= =?UTF-8?q?=E8=AF=91=E9=94=99=E8=AF=AF=E5=92=8C=E4=BA=A4=E4=BA=92=E7=B3=BB?= =?UTF-8?q?=E7=BB=9F=E9=9B=86=E6=88=90=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - SystemDriver: EffectManager改为值持有,去掉TUniquePtr和条件编译 - SystemDriver: 补充EngineUtils.h include修复TActorIterator编译错误 - GameMode: BeginPlay自动Spawn ASystemDriver - InteractableActor: 改为abstract基类,子类自行创建交互组件 - DoorActor: 创建DoorInteractableComp替代基类组件 - EffectManager: 实现ExecuteToggleDoor调用实际门开关逻辑 - InteractableComponent/DoorComponent: 修复GetGameInstance路径和调用方式 - EffectManager: Broadcast改为Execute(单播委托) --- Content/BP/Interactable/BP_Door.uasset | 3 ++ Content/BP/UI/WBP_InteractionPrompt.uasset | 3 ++ Content/BP/UI/WBP_NarrativeText.uasset | 3 ++ Source/ChildHood/ChildHoodGameMode.cpp | 18 ++++++++ Source/ChildHood/ChildHoodGameMode.h | 7 ++- Source/ChildHood/Interaction/DoorActor.cpp | 5 +-- .../Interaction/DoorInteractableComponent.cpp | 2 +- .../ChildHood/Interaction/EffectManager.cpp | 13 ++++-- .../Interaction/InteractableActor.cpp | 3 +- .../ChildHood/Interaction/InteractableActor.h | 20 ++++----- .../Interaction/InteractableComponent.cpp | 9 ++-- Source/ChildHood/SystemDriver.cpp | 43 ++----------------- Source/ChildHood/SystemDriver.h | 22 +++------- 13 files changed, 69 insertions(+), 82 deletions(-) create mode 100644 Content/BP/Interactable/BP_Door.uasset create mode 100644 Content/BP/UI/WBP_InteractionPrompt.uasset create mode 100644 Content/BP/UI/WBP_NarrativeText.uasset diff --git a/Content/BP/Interactable/BP_Door.uasset b/Content/BP/Interactable/BP_Door.uasset new file mode 100644 index 0000000..6ba14d9 --- /dev/null +++ b/Content/BP/Interactable/BP_Door.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1d2a5b8c399f6cb50a3835742988a5bee8e9e0cf77825b499781d16ea1ab5d63 +size 37339 diff --git a/Content/BP/UI/WBP_InteractionPrompt.uasset b/Content/BP/UI/WBP_InteractionPrompt.uasset new file mode 100644 index 0000000..d4d45ef --- /dev/null +++ b/Content/BP/UI/WBP_InteractionPrompt.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:323cd1c694882eb9e19883808abd30e73afc8488f997b8b6d9380b56501a71fa +size 19883 diff --git a/Content/BP/UI/WBP_NarrativeText.uasset b/Content/BP/UI/WBP_NarrativeText.uasset new file mode 100644 index 0000000..67896be --- /dev/null +++ b/Content/BP/UI/WBP_NarrativeText.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7aa4804d28c28d6c0bb5f61cd4f1cee824f179e77fd8a3ed093305a6f6f8d6e0 +size 19803 diff --git a/Source/ChildHood/ChildHoodGameMode.cpp b/Source/ChildHood/ChildHoodGameMode.cpp index 6b295cd..f42c812 100644 --- a/Source/ChildHood/ChildHoodGameMode.cpp +++ b/Source/ChildHood/ChildHoodGameMode.cpp @@ -1,8 +1,26 @@ // Copyright Epic Games, Inc. All Rights Reserved. #include "ChildHoodGameMode.h" +#include "SystemDriver.h" AChildHoodGameMode::AChildHoodGameMode() { // stub } + +void AChildHoodGameMode::BeginPlay() +{ + Super::BeginPlay(); + + // 自动 Spawn ASystemDriver(全局交互系统驱动器) + // 如果关卡中已手动放置则跳过,避免重复 + if (UWorld* World = GetWorld()) + { + if (!ASystemDriver::Get(this)) + { + FActorSpawnParameters SpawnParams; + SpawnParams.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn; + World->SpawnActor(ASystemDriver::StaticClass(), FTransform::Identity, SpawnParams); + } + } +} diff --git a/Source/ChildHood/ChildHoodGameMode.h b/Source/ChildHood/ChildHoodGameMode.h index 07bcbdf..01628af 100644 --- a/Source/ChildHood/ChildHoodGameMode.h +++ b/Source/ChildHood/ChildHoodGameMode.h @@ -15,10 +15,9 @@ class AChildHoodGameMode : public AGameModeBase GENERATED_BODY() public: - + /** Constructor */ AChildHoodGameMode(); + + virtual void BeginPlay() override; }; - - - diff --git a/Source/ChildHood/Interaction/DoorActor.cpp b/Source/ChildHood/Interaction/DoorActor.cpp index 4c7be9f..a8fce73 100644 --- a/Source/ChildHood/Interaction/DoorActor.cpp +++ b/Source/ChildHood/Interaction/DoorActor.cpp @@ -13,10 +13,9 @@ ADoorActor::ADoorActor() { PrimaryActorTick.bCanEverTick = false; - // 基类构造函数已创建 MeshComp(根组件)和 InteractableComp - - // 创建门专用交互组件,替代基类的通用 InteractableComp + // 创建门专用交互组件,赋值给基类指针 DoorInteractableComp = CreateDefaultSubobject(TEXT("DoorInteractableComp")); + InteractableComp = DoorInteractableComp; } // ============================================================================ diff --git a/Source/ChildHood/Interaction/DoorInteractableComponent.cpp b/Source/ChildHood/Interaction/DoorInteractableComponent.cpp index 5b1ac99..f6aba06 100644 --- a/Source/ChildHood/Interaction/DoorInteractableComponent.cpp +++ b/Source/ChildHood/Interaction/DoorInteractableComponent.cpp @@ -6,7 +6,7 @@ #include "ChildHood.h" #include "Engine/World.h" -#include "GameFramework/GameInstance.h" +#include "Engine/GameInstance.h" // ============================================================================ // 构造函数 diff --git a/Source/ChildHood/Interaction/EffectManager.cpp b/Source/ChildHood/Interaction/EffectManager.cpp index 5a29d38..79e060a 100644 --- a/Source/ChildHood/Interaction/EffectManager.cpp +++ b/Source/ChildHood/Interaction/EffectManager.cpp @@ -9,6 +9,8 @@ #include "Interaction/PersistenceSubsystem.h" #include "Interaction/PushCameraActor.h" #include "Components/SphereComponent.h" +#include "Interaction/DoorInteractableComponent.h" +#include "Interaction/DoorActor.h" #include "Kismet/GameplayStatics.h" #include "Animation/AnimInstance.h" @@ -176,7 +178,7 @@ void FEffectManager::FinishEffect() // 广播完成回调 if (OnEffectComplete.IsBound()) { - OnEffectComplete.Broadcast(); + OnEffectComplete.Execute(); } } @@ -395,8 +397,13 @@ void FEffectManager::ExecuteShowPickupNotification() void FEffectManager::ExecuteToggleDoor() { - // v0.1: 日志占位(门逻辑由 UDoorInteractableComponent 派生类实现,Phase 2) - UE_LOG(LogTemp, Log, TEXT("EffectManager: ToggleDoor (placeholder)")); + if (!CurrentContext.TargetComp.IsValid()) return; + + if (UDoorInteractableComponent* DoorComp = Cast(CurrentContext.TargetComp.Get())) + { + DoorComp->ToggleDoor(); + UE_LOG(LogTemp, Log, TEXT("EffectManager: ToggleDoor executed")); + } } // ============================================================================ diff --git a/Source/ChildHood/Interaction/InteractableActor.cpp b/Source/ChildHood/Interaction/InteractableActor.cpp index dc337c0..f457e4f 100644 --- a/Source/ChildHood/Interaction/InteractableActor.cpp +++ b/Source/ChildHood/Interaction/InteractableActor.cpp @@ -18,8 +18,7 @@ AInteractableActor::AInteractableActor() RootComponent = MeshComp; MeshComp->SetCollisionProfileName(TEXT("BlockAll")); - // 创建交互组件(UActorComponent 不需要 SetupAttachment,数据驱动型组件) - InteractableComp = CreateDefaultSubobject(TEXT("InteractableComp")); + // InteractableComp 由子类创建(本类为 abstract) } // ============================================================================ diff --git a/Source/ChildHood/Interaction/InteractableActor.h b/Source/ChildHood/Interaction/InteractableActor.h index 42f80c7..9bd5781 100644 --- a/Source/ChildHood/Interaction/InteractableActor.h +++ b/Source/ChildHood/Interaction/InteractableActor.h @@ -1,7 +1,7 @@ // ChildHood Project - 通用交互物 Actor 基类(v1.1 Effect/Action 架构) // 对应技术方案: docs/technical/交互系统-技术方案.md 第3节(类设计) -// 职责:持有 Mesh + InteractableComponent,提供可被子类覆盖的交互回调 -// 核心变更(v0.1 → v1.1):去除门旋转逻辑,只保留干净的基类 +// 职责:持有 Mesh,提供可被子类覆盖的交互回调 +// 注意:本类为 abstract,子类必须自行创建并赋值 InteractableComp #pragma once @@ -15,17 +15,14 @@ class UStaticMeshComponent; /** * AInteractableActor * - * 通用交互物 Actor 基类。场景中的每个交互物(冰箱、门、NPC 等) - * 均为该类的实例或其子类的实例。 + * 交互物 Actor 抽象基类。提供 Mesh 和交互回调框架。 + * 子类必须在构造函数中创建合适的 InteractableComponent 并赋值给 InteractableComp。 * * 组成: * - UStaticMeshComponent* MeshComp(根组件,承载可视模型) - * - UInteractableComponent* InteractableComp(交互逻辑与数据) - * - * 子类可覆盖 OnInteractStarted / OnInteractEnded 以实现类型特定行为, - * 如门开关时的 Mesh 旋转(ADoorActor)、拾取物的消失效果等。 + * - UInteractableComponent* InteractableComp(由子类创建) */ -UCLASS() +UCLASS(abstract) class AInteractableActor : public AActor { GENERATED_BODY() @@ -70,7 +67,10 @@ protected: UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Components", meta = (AllowPrivateAccess = "true")) TObjectPtr MeshComp; - /** 交互物的交互组件(数据 + 检测 + 状态) */ + /** + * 交互物的交互组件(数据 + 检测 + 状态)。 + * 由子类在构造函数中创建并赋值。 + */ UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Components", meta = (AllowPrivateAccess = "true")) TObjectPtr InteractableComp; }; diff --git a/Source/ChildHood/Interaction/InteractableComponent.cpp b/Source/ChildHood/Interaction/InteractableComponent.cpp index 7984f73..e423276 100644 --- a/Source/ChildHood/Interaction/InteractableComponent.cpp +++ b/Source/ChildHood/Interaction/InteractableComponent.cpp @@ -9,7 +9,7 @@ #include "Components/SphereComponent.h" #include "Engine/World.h" -#include "GameFramework/GameInstance.h" +#include "Engine/GameInstance.h" #include "GameFramework/Character.h" // ============================================================================ @@ -59,7 +59,8 @@ void UInteractableComponent::BeginPlay() } // --- 恢复跨场景持久状态 --- - if (UPersistenceSubsystem* Persistence = GetGameInstance()->GetSubsystem()) + UGameInstance* GI = Owner->GetGameInstance(); + if (UPersistenceSubsystem* Persistence = GI ? GI->GetSubsystem() : nullptr) { RestorePersistentState(Persistence); } @@ -94,9 +95,9 @@ void UInteractableComponent::Consume_Implementation() } // 写入持久层 - if (UWorld* World = GetWorld()) + if (UGameInstance* GI = GetOwner() ? GetOwner()->GetGameInstance() : nullptr) { - if (UPersistenceSubsystem* Persistence = World->GetGameInstance()->GetSubsystem()) + if (UPersistenceSubsystem* Persistence = GI->GetSubsystem()) { Persistence->MarkItemCollected(Data.ItemId); } diff --git a/Source/ChildHood/SystemDriver.cpp b/Source/ChildHood/SystemDriver.cpp index 68470f9..c84d892 100644 --- a/Source/ChildHood/SystemDriver.cpp +++ b/Source/ChildHood/SystemDriver.cpp @@ -5,17 +5,8 @@ #include "SystemDriver.h" #include "ChildHood.h" -// FEffectManager 尚未创建时,此 include 会失败。 -// 临时处理:条件编译,EffectManager.h 存在时才包含。 -// 当 EffectManager 子代理完成后,去掉 __has_include 判断直接包含。 -#if __has_include("Interaction/EffectManager.h") -#include "Interaction/EffectManager.h" -#define HAS_EFFECT_MANAGER 1 -#else -#define HAS_EFFECT_MANAGER 0 -#endif - #include "Engine/World.h" +#include "EngineUtils.h" #include "Kismet/GameplayStatics.h" #include "GameFramework/PlayerController.h" #include "GameFramework/Character.h" @@ -29,11 +20,6 @@ ASystemDriver::ASystemDriver() // AInfo 默认不需要 Tick,我们在构造函数中开启 PrimaryActorTick.bCanEverTick = true; PrimaryActorTick.bStartWithTickEnabled = true; - - // 如果 FEffectManager 可用,在构造时创建实例 -#if HAS_EFFECT_MANAGER - EffectManagerPtr = MakeUnique(); -#endif } // ============================================================================ @@ -66,19 +52,13 @@ void ASystemDriver::BeginPlay() } // --- 初始化 EffectManager --- -#if HAS_EFFECT_MANAGER - if (EffectManagerPtr.IsValid()) { - // 绑定 Effect 完成回调 FOnEffectComplete Callback; Callback.BindLambda([this]() { this->OnEffectComplete(); }); - EffectManagerPtr->SetOnEffectComplete(MoveTemp(Callback)); + EffectManager.SetOnEffectComplete(MoveTemp(Callback)); UE_LOG(LogChildHood, Log, TEXT("SystemDriver: EffectManager 初始化完成")); } -#else - UE_LOG(LogChildHood, Log, TEXT("SystemDriver: EffectManager 尚未创建(EffectManager.h 不存在)")); -#endif } void ASystemDriver::Tick(float DeltaTime) @@ -87,12 +67,7 @@ void ASystemDriver::Tick(float DeltaTime) // --- Tick EffectManager --- // InteractionManager 无 Tick(纯事件驱动) -#if HAS_EFFECT_MANAGER - if (EffectManagerPtr.IsValid()) - { - EffectManagerPtr->Update(DeltaTime); - } -#endif + EffectManager.Update(DeltaTime); } // ============================================================================ @@ -125,18 +100,6 @@ ASystemDriver* ASystemDriver::Get(const UObject* WorldContextObject) return nullptr; } -// ============================================================================ -// Manager 访问 -// ============================================================================ - -FEffectManager& ASystemDriver::GetEffectManager() -{ - checkf(EffectManagerPtr.IsValid(), - TEXT("ASystemDriver::GetEffectManager: EffectManager 未初始化。") - TEXT("请确保 EffectManager.h 已创建且 HAS_EFFECT_MANAGER == 1")); - return *EffectManagerPtr; -} - // ============================================================================ // Effect 完成回调 // ============================================================================ diff --git a/Source/ChildHood/SystemDriver.h b/Source/ChildHood/SystemDriver.h index 8748cfa..b9da23e 100644 --- a/Source/ChildHood/SystemDriver.h +++ b/Source/ChildHood/SystemDriver.h @@ -9,11 +9,9 @@ #include "CoreMinimal.h" #include "GameFramework/Info.h" #include "Interaction/InteractionManager.h" +#include "Interaction/EffectManager.h" #include "SystemDriver.generated.h" -// FEffectManager 由另一个子代理并行创建,此处只前向声明 -class FEffectManager; - /** * ASystemDriver * @@ -56,23 +54,17 @@ public: FInteractionManager& GetInteractionManager() { return InteractionManager; } const FInteractionManager& GetInteractionManager() const { return InteractionManager; } - /** - * 获取效果管理器(值引用)。 - * FEffectManager 尚未创建时调用会触发链接错误,仅在 EffectManager.h 存在时使用。 - */ - FEffectManager& GetEffectManager(); + /** 获取效果管理器(值引用) */ + FEffectManager& GetEffectManager() { return EffectManager; } + const FEffectManager& GetEffectManager() const { return EffectManager; } private: - /** 交互管理器 — 普通 C++ 值持有 */ + /** 交互管理器 */ FInteractionManager InteractionManager; - /** - * 效果管理器 — 普通 C++ 值持有。 - * FEffectManager 定义在 Interaction/EffectManager.h 中(由另一个子代理创建)。 - * 使用 unique_ptr 延迟构造,避免头文件中需要完整定义。 - */ - TUniquePtr EffectManagerPtr; + /** 效果管理器 */ + FEffectManager EffectManager; // === Effect 完成回调连线 ===