using UnityEngine; using UnityEngine.Events; using Cinemachine; using AibisDream; using AibisDream.FixSystem; using AibisDream.Framework; using System.Collections; using System.Collections.Generic; using DG.Tweening; using AibisDream.MiniGame.HuoShan; namespace AibisDream.MiniGame.Language { /// /// 销售模块深入阶段(滑片进度 0~1 均分三段) /// /// /// 销售系统管理器 /// 负责视图开关、相机注册、销售模块深入阶段状态管理 /// public class SalesManager : MonoBehaviour { [Header("UI配置")] [Tooltip("销售系统主视图对象(会自动查找名为'SaleView'或'SellView'的子对象)")] [SerializeField] private GameObject saleView; [HideInInspector] public BubbleSlotGroup bubbleSlotGroup; [Header("相机配置")] [Tooltip("主销售相机")] [SerializeField] private CameraEnum mainCamera = CameraEnum.SaleCamera; [Tooltip("深度销售相机(可选)")] [SerializeField] private CameraEnum deepCamera = CameraEnum.SaleDeepCamera; [Header("销售模块深入 - Crank 与 Slider 协调")] [Tooltip("发条控制器(不填则从 saleView 下查找)")] [SerializeField] private CrankController crankController; [Tooltip("滑片控制器(不填则从 saleView 下查找)")] [SerializeField] private SliderController sliderController; [Tooltip("总共转动几次(发条上满+滑片到位 为一轮)")] [SerializeField] private int totalTurns = 4; [Tooltip("每次转动的时间(秒),发条回位与滑片滑动均用此刻度")] [SerializeField] private float timePerTurn = 3f; [Tooltip("每轮转动完成后调用的 Yarn 节点名,可通过 $salesTurnIndex 分支不同内容")] [SerializeField] private string crankCompleteNode = "销售模块转动完成"; [Tooltip("滑片开始转动时调用的 Yarn 节点名,配合 ChipModule 解释正在做的步骤,可通过 $salesTurnIndex 分支")] [SerializeField] private string crankSlideStartNode = "销售转动_开始"; // [Header("销售模块深入 - 阶段事件(滑片进度阈值)")] // [Tooltip("语义组织阶段时调用的 Yarn 节点名(滑片进度 ≥ 1/3)")] // [SerializeField] private string phaseSemanticNode = "语义组织达到"; // [Tooltip("审查阶段时调用的 Yarn 节点名(滑片进度 ≥ 2/3)")] // [SerializeField] private string phaseReviewNode = "审查达到"; // [Tooltip("风格阶段时调用的 Yarn 节点名(滑片进度 ≥ 1)")] // [SerializeField] private string phaseStyleNode = "风格达到"; [Header("处理器深入模式")] [Tooltip("盖子 SpriteRenderer(深入模式下淡出)")] [SerializeField] private SpriteRenderer processorCover; [Tooltip("旋钮控制器(不填则从 saleView 下查找)")] [SerializeField] private KnobController knobController; [Tooltip("辉光管粒子效果(不填则从 saleView 下查找)")] [SerializeField] private GlowTubeEffect glowTubeEffect; [Header("SaleView 进入动画")] [Tooltip("进入动画控制器(不填则从 saleView 下查找 SaleViewEnterAnimation)")] [SerializeField] private SaleViewEnterAnimation saleViewEnterAnimation; [Tooltip("深入模式缩放倍数")] [SerializeField] private float deepModeScale = 1.2f; [Tooltip("深入模式 X 偏移(负方向)")] [SerializeField] private float deepModeOffsetX = -5f; [Tooltip("深入模式动画时长")] [SerializeField] private float deepModeTransitionDuration = 0.6f; [Tooltip("盖子淡出时长")] [SerializeField] private float coverFadeDuration = 0.5f; private readonly List registeredCameras = new(); private bool _isProcessorDeepMode; private Vector3 _saleViewOriginalPos; private Vector3 _saleViewOriginalScale; private Sequence _deepModeSequence; private int _currentTurnIndex; // 当前已完成第几轮(1-based) /// /// 当前销售模块深入阶段 /// /// /// 当前转动到第几轮(1-based,滑片到位时更新) /// public int CurrentTurnIndex => _currentTurnIndex; /// 发条控制器(供 Yarn 命令等通过 SalesManager 获取) public CrankController CrankController => crankController; /// 滑片控制器(供 Yarn 命令等通过 SalesManager 获取) public SliderController SliderController => sliderController; /// 旋钮控制器 public KnobController KnobController => knobController; /// 辉光管效果 public GlowTubeEffect GlowTubeEffect => glowTubeEffect; /// 是否处于处理器深入模式 public bool IsProcessorDeepMode => _isProcessorDeepMode; /// 播放 SaleView 进入动画(轨道伸张、滑片伸出等) public void PlaySaleViewEnterAnimation() => saleViewEnterAnimation?.PlayEnterAnimation(); /// /// 播放进入动画,并在完成后释放控制权(禁用 Animator), /// 以便 SliderController 等代码控制滑片等物件。 /// 完成后激活 SliderController,使其接受滑片控制并显示等离子体。 /// public IEnumerator PlaySaleViewEnterAnimationAndReleaseWhenDone() { // if (saleViewEnterAnimation != null) // yield return saleViewEnterAnimation.PlayEnterAnimationAndReleaseWhenDone(); // // 进入动画完成,激活滑片控制(等离子体与 Slider 才接受控制) yield return TimelineCenter.Instance.PlayTimelineAsync("步进模式/进入步进模式"); sliderController?.SetControlActive(true); } private void Awake() { // 对话气泡槽组(SaleSystem 下名为 "Bubble Slots" 的 GameObject) var bubbleSlots = transform.Find("Bubble Slots"); if (bubbleSlots != null) { bubbleSlotGroup = bubbleSlots.GetComponent(); if (bubbleSlotGroup == null) Debug.LogWarning("[SalesManager] 找到 'Bubble Slots' 但无 BubbleSlotGroup 组件", this); } else { Debug.LogWarning("[SalesManager] 未找到名为 'Bubble Slots' 的子对象,对话气泡将无法显示", this); } } private void Start() { RegisterToSystem(); RegisterCameras(); FindSaleView(); FindSaleViewEnterAnimation(); FindCrankController(); FindSliderController(); FindKnobController(); FindGlowTubeEffect(); FindProcessorCover(); } private void OnDestroy() { _deepModeSequence?.Kill(); UnregisterCameras(); UnsubscribeFromCrankSlider(); } /// /// 查找销售视图(按名字"SaleView",递归查找子孙节点) /// private void FindSaleView() { if (saleView == null) { // 递归查找,支持 SaleView/SellView 不在直接子级的情况 foreach (Transform t in transform.GetComponentsInChildren(true)) { if (t.name == "SaleView" || t.name == "SellView") { saleView = t.gameObject; Debug.Log($"[SalesManager] 找到视图: {t.name}"); break; } } if (saleView == null) Debug.LogWarning("[SalesManager] 未找到名为 'SaleView' 或 'SellView' 的子对象", this); } // 初始时隐藏视图 if (saleView != null) { saleView.SetActive(false); } } /// /// 查找 SaleView 进入动画(从 saleView 下查找) /// private void FindSaleViewEnterAnimation() { if (saleViewEnterAnimation != null) return; var root = saleView != null ? saleView.transform : transform; saleViewEnterAnimation = root.GetComponentInChildren(true); if (saleViewEnterAnimation != null) Debug.Log("[SalesManager] 找到 SaleViewEnterAnimation"); } /// /// 查找发条控制器(从 saleView 或自身下查找) /// private void FindCrankController() { if (crankController != null) return; var root = saleView != null ? saleView.transform : transform; crankController = root.GetComponentInChildren(true); if (crankController != null) Debug.Log("[SalesManager] 找到 CrankController"); else Debug.LogWarning("[SalesManager] 未找到 CrankController,请在 SaleView 下添加或手动指定", this); } /// /// 查找滑片控制器(从 saleView 或自身下查找) /// private void FindSliderController() { if (sliderController != null) return; var root = saleView != null ? saleView.transform : transform; sliderController = root.GetComponentInChildren(true); if (sliderController != null) Debug.Log("[SalesManager] 找到 SliderController"); else Debug.LogWarning("[SalesManager] 未找到 SliderController,请在 SaleView 下添加或手动指定", this); } /// /// 建立 Crank 与 Slider 的协调:回位时长、段数、事件订阅 /// 事件统一监听滑片转到位置(阶段事件)和滑片到位完成(每轮完成) /// 每次 OpenView 时调用,确保 prefab 初始 inactive 时也能正确连接 /// private void EnsureCrankSliderSync() { UnsubscribeFromCrankSlider(); // 避免重复订阅 if (crankController == null) { Debug.LogWarning("[SalesManager] CrankController 未找到,发条转动无法驱动滑片!", this); } else { crankController.SetReturnDuration(timePerTurn); crankController.onCrankComplete.AddListener(OnCrankComplete); } if (sliderController == null) { Debug.LogWarning("[SalesManager] SliderController 未找到,事件无法触发!", this); } else { sliderController.SetSegmentCount(totalTurns); // 滑片到位完成 → 每轮转动完成事件 sliderController.onSlideComplete.AddListener(OnSlideComplete); // 阶段事件:监听滑片转到 1/3、2/3、1 位置 // sliderController.onPhaseSemanticReached.AddListener(OnPhaseSemanticReached); // sliderController.onPhaseReviewReached.AddListener(OnPhaseReviewReached); // sliderController.onPhaseStyleReached.AddListener(OnPhaseStyleReached); } } private void UnsubscribeFromCrankSlider() { if (crankController != null) crankController.onCrankComplete.RemoveListener(OnCrankComplete); if (sliderController != null) { // sliderController.onSlideComplete.RemoveListener(OnSlideComplete); // sliderController.onPhaseSemanticReached.RemoveListener(OnPhaseSemanticReached); // sliderController.onPhaseReviewReached.RemoveListener(OnPhaseReviewReached); // sliderController.onPhaseStyleReached.RemoveListener(OnPhaseStyleReached); } } // private void OnPhaseSemanticReached() => TryStartPhaseNode(phaseSemanticNode); // private void OnPhaseReviewReached() => TryStartPhaseNode(phaseReviewNode); // private void OnPhaseStyleReached() => TryStartPhaseNode(phaseStyleNode); private void OnCrankComplete() { Debug.Log($"[SalesManager] OnCrankComplete 被调用!当前轮次: {_currentTurnIndex + 1}, sliderController: {sliderController != null}", this); _currentTurnIndex++; #if UNITY_EDITOR Debug.Log($"[SalesManager] 发条完成,当前第 {_currentTurnIndex}/{totalTurns} 轮", this); #endif if (_currentTurnIndex > totalTurns) return; // 滑片开始转动前,先触发 ChipModule 解释当前步骤(Stage3 等配合) StorageSystem.Instance?.SetValue("$salesTurnIndex", (float)_currentTurnIndex); if (!string.IsNullOrEmpty(crankSlideStartNode)) DialogController.Instance?.StartDialogNode(crankSlideStartNode); if (sliderController != null) { // 滑片移动至当前轮对应的段,时长与发条回位一致 Debug.Log($"[SalesManager] 开始滑动滑片到段 {_currentTurnIndex}", this); sliderController.SlideToSegment(_currentTurnIndex, timePerTurn); } else { Debug.LogError($"[SalesManager] SliderController 为 null,无法滑动滑片!", this); } } private void OnSlideComplete() { if (string.IsNullOrEmpty(crankCompleteNode)) return; StorageSystem.Instance?.SetValue("$salesTurnIndex", (float)_currentTurnIndex); DialogController.Instance?.StartDialogNode(crankCompleteNode); } private void TryStartPhaseNode(string nodeName) { if (string.IsNullOrEmpty(nodeName)) return; DialogController.Instance?.StartDialogNode(nodeName); } /// /// 注册到系统字典 /// private void RegisterToSystem() { FixSystemCenter.SystemDic.Register(this); } /// /// 注册所有相机到CameraKit /// private void RegisterCameras() { if (CameraKit.Instance == null) { Debug.LogError("[SalesManager] CameraKit.Instance 为 null,无法注册相机!"); return; } // 获取所有相机 var virtualCams = GetComponentsInChildren(); if (virtualCams.Length == 0) { Debug.LogWarning("[SalesManager] 未找到任何 ICinemachineCamera 组件!"); return; } // 注册主相机 if (virtualCams.Length > 0) { CameraKit.Instance.RegisterCamera(mainCamera, virtualCams[0]); registeredCameras.Add(mainCamera); Debug.Log($"[SalesManager] 成功注册主相机: {mainCamera}"); } // 注册深度相机(如果有) if (virtualCams.Length > 1) { CameraKit.Instance.RegisterCamera(deepCamera, virtualCams[1]); registeredCameras.Add(deepCamera); Debug.Log($"[SalesManager] 成功注册深度相机: {deepCamera}"); } } /// /// 从CameraKit注销所有相机 /// private void UnregisterCameras() { if (CameraKit.Instance == null) return; foreach (var cameraType in registeredCameras) { CameraKit.Instance.UnRegisterCamera(cameraType); Debug.Log($"[SalesManager] 已注销相机: {cameraType}"); } registeredCameras.Clear(); } /// /// 打开销售系统界面 /// public void OpenView() { gameObject.SetActive(true); // 延迟一帧确保子物体已激活,再建立连接(避免 prefab 初始 inactive 导致 Start 未跑) StartCoroutine(OpenViewDelayed()); } private System.Collections.IEnumerator OpenViewDelayed() { yield return null; // 等待本帧结束,子物体 Awake/OnEnable 完成 Debug.Log($"[SalesManager] OpenViewDelayed 开始,子物体已激活。crankController: {crankController != null}, sliderController: {sliderController != null}", this); EnsureCrankSliderSync(); // 每次打开时建立/重建连接 ResetCrankCycle(); if (saleView != null) { saleView.SetActive(true); sliderController?.SetPlasmaActive(true); // OpenView 时等离子体激活,360° 满弧 Debug.Log("[SalesManager] 销售系统已打开"); } else { Debug.LogError("[SalesManager] SaleView 未找到,无法打开销售界面", this); } } /// /// 关闭销售系统界面 /// public void CloseView() { UnsubscribeFromCrankSlider(); sliderController?.SetControlActive(false); sliderController?.SetPlasmaActive(false); saleViewEnterAnimation?.ResetToIdle(); if (saleView != null) { saleView.SetActive(false); } gameObject.SetActive(false); Debug.Log("[SalesManager] 销售系统已关闭"); } /// /// 初始化销售系统 /// public void Initialize() { Debug.Log("[SalesManager] 初始化销售系统"); // 这里添加初始化逻辑 } /// /// 重置销售模块深入阶段(滑片重置时通常需调用) /// public void ResetPhase() { if (sliderController != null) sliderController.ResetPhaseFlags(); } /// /// 重置发条-滑片循环(进入销售深入时调用) /// public void ResetCrankCycle() { _currentTurnIndex = 0; crankController?.ResetCrank(); sliderController?.ResetPosition(); ResetPhase(); } #region 处理器深入模式 private void FindKnobController() { if (knobController != null) return; var root = saleView != null ? saleView.transform : transform; knobController = root.GetComponentInChildren(true); if (knobController == null) knobController = GetComponentInChildren(true); if (knobController != null) Debug.Log("[SalesManager] Found KnobController"); } private void FindGlowTubeEffect() { if (glowTubeEffect != null) return; var root = saleView != null ? saleView.transform : transform; glowTubeEffect = root.GetComponentInChildren(true); if (glowTubeEffect == null) glowTubeEffect = GetComponentInChildren(true); if (glowTubeEffect != null) Debug.Log("[SalesManager] Found GlowTubeEffect"); } private void FindProcessorCover() { if (processorCover != null) return; var root = saleView != null ? saleView.transform : transform; foreach (var t in root.GetComponentsInChildren(true)) { if (t.name == "\u76d6\u5b50") { processorCover = t.GetComponent(); if (processorCover != null) Debug.Log("[SalesManager] Found processor cover"); break; } } } /// /// 进入处理器深入模式:面板放大右移 → 盖子淡出 → 启动旋钮和辉光管 /// public void EnterProcessorDeepMode() { if (_isProcessorDeepMode) return; if (saleView == null) { Debug.LogError("[SalesManager] SaleView is null, cannot enter processor deep mode", this); return; } _isProcessorDeepMode = true; StartCoroutine(EnterProcessorDeepModeRoutine()); } private IEnumerator EnterProcessorDeepModeRoutine() { _deepModeSequence?.Kill(); var viewTransform = saleView.transform; _saleViewOriginalPos = viewTransform.localPosition; _saleViewOriginalScale = viewTransform.localScale; // Activate cover so we can fade it out if (processorCover != null) { processorCover.gameObject.SetActive(true); var c = processorCover.color; processorCover.color = new Color(c.r, c.g, c.b, 1f); } // Build animation sequence _deepModeSequence = DOTween.Sequence(); // Step 1: Scale up + shift X Vector3 targetPos = _saleViewOriginalPos + new Vector3(deepModeOffsetX, 0f, 0f); Vector3 targetScale = _saleViewOriginalScale * deepModeScale; _deepModeSequence.Append( viewTransform.DOLocalMove(targetPos, deepModeTransitionDuration).SetEase(Ease.OutCubic) ); _deepModeSequence.Join( viewTransform.DOScale(targetScale, deepModeTransitionDuration).SetEase(Ease.OutCubic) ); // Step 2: Fade out cover if (processorCover != null) { _deepModeSequence.Append( processorCover.DOFade(0f, coverFadeDuration).SetEase(Ease.InQuad) ); _deepModeSequence.AppendCallback(() => { processorCover.gameObject.SetActive(false); }); } // Step 3: Enable knob + glow tube _deepModeSequence.AppendCallback(() => { if (glowTubeEffect != null) glowTubeEffect.gameObject.SetActive(true); if (knobController != null) { knobController.gameObject.SetActive(true); knobController.Reset(); } Debug.Log("[SalesManager] Processor deep mode entered"); }); yield return _deepModeSequence.WaitForCompletion(); } /// /// 退出处理器深入模式:恢复面板位置/缩放、恢复盖子 /// public void ExitProcessorDeepMode() { if (!_isProcessorDeepMode) return; _isProcessorDeepMode = false; StartCoroutine(ExitProcessorDeepModeRoutine()); } private IEnumerator ExitProcessorDeepModeRoutine() { _deepModeSequence?.Kill(); if (knobController != null) knobController.gameObject.SetActive(false); if (glowTubeEffect != null) glowTubeEffect.gameObject.SetActive(false); _deepModeSequence = DOTween.Sequence(); // Restore cover if (processorCover != null) { processorCover.gameObject.SetActive(true); var c = processorCover.color; processorCover.color = new Color(c.r, c.g, c.b, 0f); _deepModeSequence.Append( processorCover.DOFade(1f, coverFadeDuration).SetEase(Ease.OutQuad) ); } // Restore position and scale var viewTransform = saleView.transform; _deepModeSequence.Append( viewTransform.DOLocalMove(_saleViewOriginalPos, deepModeTransitionDuration).SetEase(Ease.InOutCubic) ); _deepModeSequence.Join( viewTransform.DOScale(_saleViewOriginalScale, deepModeTransitionDuration).SetEase(Ease.InOutCubic) ); _deepModeSequence.AppendCallback(() => { Debug.Log("[SalesManager] Processor deep mode exited"); }); yield return _deepModeSequence.WaitForCompletion(); } #endregion } }