diff --git a/Source/ChildHood/Interaction/DoorActor.cpp b/Source/ChildHood/Interaction/DoorActor.cpp index a8fce73..06b77da 100644 --- a/Source/ChildHood/Interaction/DoorActor.cpp +++ b/Source/ChildHood/Interaction/DoorActor.cpp @@ -24,11 +24,11 @@ ADoorActor::ADoorActor() void ADoorActor::OnInteractStarted_Implementation(UInteractableComponent* Comp) { - // 只响应门组件的交互 - if (UDoorInteractableComponent* DoorComp = Cast(Comp)) - { - DoorComp->ToggleDoor(); - } + (void)Comp; // 参数保留以匹配基类签名(OnInteractStarted 当前无调用方) + + // v1.1 架构:门的开关业务逻辑由 EffectManager::ExecuteToggleDoor 统一驱动, + // 视觉旋转由 UDoorInteractableComponent::ToggleDoor 内部回调 UpdateDoorVisual 完成。 + // 此处保留空实现,避免与 Effect 路径重复 ToggleDoor 导致状态抵消。 } // ============================================================================ diff --git a/Source/ChildHood/Interaction/DoorActor.h b/Source/ChildHood/Interaction/DoorActor.h index 084eb1f..8ea0fbe 100644 --- a/Source/ChildHood/Interaction/DoorActor.h +++ b/Source/ChildHood/Interaction/DoorActor.h @@ -16,7 +16,7 @@ class UDoorInteractableComponent; * * 门类型的交互物 Actor。在基类基础上: * - 使用 UDoorInteractableComponent 替代 UInteractableComponent - * - OnInteractStarted 中调用 ToggleDoor 并更新 Mesh 旋转 + * - v1.1:门开关业务由 EffectManager::ExecuteToggleDoor 驱动,OnInteractStarted 为空实现 * - UpdateDoorVisual 执行实际的 Mesh Yaw 旋转(开门+90, 关门0) * * v0.1 阶段旋转为瞬时 SetRelativeRotation,不使用动画插值。 @@ -39,9 +39,9 @@ public: // === 交互回调 === /** - * 交互开始时调用。 - * Cast 到 UDoorInteractableComponent 后调用 ToggleDoor, - * 由 Component 负责状态切换和持久化,Actor 只负责视觉。 + * 交互开始回调(v1.1 为空实现)。 + * 门开关业务逻辑由 EffectManager::ExecuteToggleDoor 统一驱动, + * 视觉旋转由 UDoorInteractableComponent::ToggleDoor 内部回调,Actor 不在此重复处理。 */ virtual void OnInteractStarted_Implementation(UInteractableComponent* Comp) override; diff --git a/Source/ChildHood/Interaction/EffectManager.cpp b/Source/ChildHood/Interaction/EffectManager.cpp index 79e060a..68a8ed2 100644 --- a/Source/ChildHood/Interaction/EffectManager.cpp +++ b/Source/ChildHood/Interaction/EffectManager.cpp @@ -149,6 +149,8 @@ void FEffectManager::ExecuteAction(const FInteractAction& Action) break; // v0.1 用日志占位的 Action case EInteractActionType::AddToBackpack: + // TODO: 后续集成收集系统(Issue #33 P-013 收集系统程序实现)。 + // 届时由 ASystemDriver 回调链通知 FCollectionManager,EffectManager 不直接处理业务逻辑。 UE_LOG(LogTemp, Log, TEXT("EffectManager: AddToBackpack - Item: %s"), CurrentContext.TargetComp.IsValid() ? *CurrentContext.TargetComp->GetInteractableData().DisplayName @@ -328,7 +330,17 @@ void FEffectManager::ExecuteCameraReturn(const FInteractAction& Action) PC->SetViewTargetWithBlend(CurrentContext.Instigator.Get(), Action.ReturnDuration); - // 延迟销毁 PushCamera(在 PerformCleanup 中统一清理) + // 相机已回到角色,立即销毁推镜摄像机并清空缓存, + // 避免 PerformCleanup 检测到有效缓存后冗余回位 + 重复销毁。 + if (APushCameraActor* PushCam = CachedPushCamera.Get()) + { + CachedPushCamera = nullptr; + if (PushCam->GetWorld()) + { + PushCam->Destroy(); + } + } + UE_LOG(LogTemp, Verbose, TEXT("EffectManager: CameraReturn (Dur=%.2fs)"), Action.ReturnDuration); } diff --git a/Source/ChildHood/Interaction/InteractionManager.cpp b/Source/ChildHood/Interaction/InteractionManager.cpp index 08cd0e5..fd3fd61 100644 --- a/Source/ChildHood/Interaction/InteractionManager.cpp +++ b/Source/ChildHood/Interaction/InteractionManager.cpp @@ -121,20 +121,8 @@ UInteractableComponent* FInteractionManager::BeginInteract() State = EInteractionState::Executing; CurrentInteractable = Target; - // 通知 Character 进入交互状态(屏蔽移动) - // FInteractionManager 只持有 ACharacter 基类指针,不直接依赖 AChildHoodCharacter。 - // 通过 UE 反射调用 SetInteracting(UFUNCTION(BlueprintCallable))。 - if (ACharacter* Char = PlayerCharacter.Get()) - { - UFunction* Fn = Char->FindFunction(FName(TEXT("SetInteracting"))); - if (Fn) - { - struct FSetInteractingParams { bool bValue; }; - FSetInteractingParams Params; - Params.bValue = true; - Char->ProcessEvent(Fn, &Params); - } - } + // SetInteracting(true) 由 Character 侧 OnInteract 直接调用(见 ChildHoodCharacter::OnInteract)。 + // FInteractionManager 作为纯逻辑层不操作 Character 表现状态,避免 SetInteracting(true) 双调用。 UE_LOG(LogChildHood, Log, TEXT("InteractionManager::BeginInteract: 开始交互 '%s'"), *Target->GetInteractableData().DisplayName); @@ -193,19 +181,8 @@ void FInteractionManager::OnInteractionFinished() // 清理当前交互物引用 CurrentInteractable.Reset(); - // 通知 Character 解除交互状态 - // 通过 UE 反射调用 SetInteracting(false) - if (ACharacter* Char = PlayerCharacter.Get()) - { - UFunction* Fn = Char->FindFunction(FName(TEXT("SetInteracting"))); - if (Fn) - { - struct FSetInteractingParams { bool bValue; }; - FSetInteractingParams Params; - Params.bValue = false; - Char->ProcessEvent(Fn, &Params); - } - } + // SetInteracting(false) 由 ASystemDriver::OnEffectComplete 协调调用, + // FInteractionManager 作为纯逻辑层不操作 Character 表现状态。 // 重新排序和刷新缓存(消耗可能改变了列表) UpdateSelection(); diff --git a/Source/ChildHood/Interaction/InteractionManager.h b/Source/ChildHood/Interaction/InteractionManager.h index d006921..8316fd2 100644 --- a/Source/ChildHood/Interaction/InteractionManager.h +++ b/Source/ChildHood/Interaction/InteractionManager.h @@ -113,7 +113,7 @@ private: /** 当前正在交互的交互物(Executing 状态下锁定) */ TWeakObjectPtr CurrentInteractable; - /** 玩家角色弱引用(用于排序距离计算和 SetInteracting 调用) */ + /** 玩家角色弱引用(用于按水平距离排序的选中计算) */ TWeakObjectPtr PlayerCharacter; /** Presentation 层缓存数据 — 选中交互物的摘要信息 */ diff --git a/Source/ChildHood/SystemDriver.cpp b/Source/ChildHood/SystemDriver.cpp index c84d892..8b706a2 100644 --- a/Source/ChildHood/SystemDriver.cpp +++ b/Source/ChildHood/SystemDriver.cpp @@ -10,6 +10,7 @@ #include "Kismet/GameplayStatics.h" #include "GameFramework/PlayerController.h" #include "GameFramework/Character.h" +#include "ChildHoodCharacter.h" // ============================================================================ // 构造函数 @@ -108,4 +109,18 @@ void ASystemDriver::OnEffectComplete() { // Effect 完成后通知 InteractionManager 恢复 Free 状态 InteractionManager.OnInteractionFinished(); + + // 通知 Character 复位交互状态(解除移动屏蔽)。 + // FInteractionManager 作为纯逻辑层不操作 Character 表现状态, + // 由 ASystemDriver 作为 World 级协调者统一驱动。 + if (UWorld* World = GetWorld()) + { + if (APlayerController* PC = World->GetFirstPlayerController()) + { + if (AChildHoodCharacter* Char = Cast(PC->GetCharacter())) + { + Char->SetInteracting(false); + } + } + } }