Files
aibis-dream/Assets/Scripts/MiniGame/HuoShan/SalesSystem/SalesManager.cs
T

393 lines
14 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.
using UnityEngine;
using UnityEngine.Events;
using Cinemachine;
using AibisDream;
using AibisDream.FixSystem;
using AibisDream.Framework;
using System.Collections.Generic;
using AibisDream.MiniGame.HuoShan;
namespace AibisDream.MiniGame.Language
{
/// <summary>
/// 销售模块深入阶段(滑片进度 0~1 均分三段)
/// </summary>
/// <summary>
/// 销售系统管理器
/// 负责视图开关、相机注册、销售模块深入阶段状态管理
/// </summary>
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 = "销售模块转动完成";
// [Header("销售模块深入 - 阶段事件(滑片进度阈值)")]
// [Tooltip("语义组织阶段时调用的 Yarn 节点名(滑片进度 ≥ 1/3")]
// [SerializeField] private string phaseSemanticNode = "语义组织达到";
// [Tooltip("审查阶段时调用的 Yarn 节点名(滑片进度 ≥ 2/3")]
// [SerializeField] private string phaseReviewNode = "审查达到";
// [Tooltip("风格阶段时调用的 Yarn 节点名(滑片进度 ≥ 1)")]
// [SerializeField] private string phaseStyleNode = "风格达到";
private readonly List<CameraEnum> registeredCameras = new();
private int _currentTurnIndex; // 当前已完成第几轮(1-based)
/// <summary>
/// 当前销售模块深入阶段
/// </summary>
/// <summary>
/// 当前转动到第几轮(1-based,滑片到位时更新)
/// </summary>
public int CurrentTurnIndex => _currentTurnIndex;
/// <summary>发条控制器(供 Yarn 命令等通过 SalesManager 获取)</summary>
public CrankController CrankController => crankController;
/// <summary>滑片控制器(供 Yarn 命令等通过 SalesManager 获取)</summary>
public SliderController SliderController => sliderController;
private void Awake()
{
// 对话气泡槽组(SaleSystem 下名为 "Bubble Slots" 的 GameObject
var bubbleSlots = transform.Find("Bubble Slots");
if (bubbleSlots != null)
{
bubbleSlotGroup = bubbleSlots.GetComponent<BubbleSlotGroup>();
if (bubbleSlotGroup == null)
Debug.LogWarning("[SalesManager] 找到 'Bubble Slots' 但无 BubbleSlotGroup 组件", this);
}
else
{
Debug.LogWarning("[SalesManager] 未找到名为 'Bubble Slots' 的子对象,对话气泡将无法显示", this);
}
}
private void Start()
{
RegisterToSystem();
RegisterCameras();
FindSaleView();
FindCrankController();
FindSliderController();
}
private void OnDestroy()
{
UnregisterCameras();
UnsubscribeFromCrankSlider();
}
/// <summary>
/// 查找销售视图(按名字"SaleView",递归查找子孙节点)
/// </summary>
private void FindSaleView()
{
if (saleView == null)
{
// 递归查找,支持 SaleView/SellView 不在直接子级的情况
foreach (Transform t in transform.GetComponentsInChildren<Transform>(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);
}
}
/// <summary>
/// 查找发条控制器(从 saleView 或自身下查找)
/// </summary>
private void FindCrankController()
{
if (crankController != null) return;
var root = saleView != null ? saleView.transform : transform;
crankController = root.GetComponentInChildren<CrankController>(true);
if (crankController != null)
Debug.Log("[SalesManager] 找到 CrankController");
else
Debug.LogWarning("[SalesManager] 未找到 CrankController,请在 SaleView 下添加或手动指定", this);
}
/// <summary>
/// 查找滑片控制器(从 saleView 或自身下查找)
/// </summary>
private void FindSliderController()
{
if (sliderController != null) return;
var root = saleView != null ? saleView.transform : transform;
sliderController = root.GetComponentInChildren<SliderController>(true);
if (sliderController != null)
Debug.Log("[SalesManager] 找到 SliderController");
else
Debug.LogWarning("[SalesManager] 未找到 SliderController,请在 SaleView 下添加或手动指定", this);
}
/// <summary>
/// 建立 Crank 与 Slider 的协调:回位时长、段数、事件订阅
/// 事件统一监听滑片转到位置(阶段事件)和滑片到位完成(每轮完成)
/// 每次 OpenView 时调用,确保 prefab 初始 inactive 时也能正确连接
/// </summary>
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;
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);
}
/// <summary>
/// 注册到系统字典
/// </summary>
private void RegisterToSystem()
{
FixSystemCenter.SystemDic.Register(this);
}
/// <summary>
/// 注册所有相机到CameraKit
/// </summary>
private void RegisterCameras()
{
if (CameraKit.Instance == null)
{
Debug.LogError("[SalesManager] CameraKit.Instance 为 null,无法注册相机!");
return;
}
// 获取所有相机
var virtualCams = GetComponentsInChildren<ICinemachineCamera>();
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}");
}
}
/// <summary>
/// 从CameraKit注销所有相机
/// </summary>
private void UnregisterCameras()
{
if (CameraKit.Instance == null) return;
foreach (var cameraType in registeredCameras)
{
CameraKit.Instance.UnRegisterCamera(cameraType);
Debug.Log($"[SalesManager] 已注销相机: {cameraType}");
}
registeredCameras.Clear();
}
/// <summary>
/// 打开销售系统界面
/// </summary>
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);
Debug.Log("[SalesManager] 销售系统已打开");
}
else
{
Debug.LogError("[SalesManager] SaleView 未找到,无法打开销售界面", this);
}
}
/// <summary>
/// 关闭销售系统界面
/// </summary>
public void CloseView()
{
UnsubscribeFromCrankSlider();
if (saleView != null)
{
saleView.SetActive(false);
}
gameObject.SetActive(false);
Debug.Log("[SalesManager] 销售系统已关闭");
}
/// <summary>
/// 初始化销售系统
/// </summary>
public void Initialize()
{
Debug.Log("[SalesManager] 初始化销售系统");
// 这里添加初始化逻辑
}
/// <summary>
/// 重置销售模块深入阶段(滑片重置时通常需调用)
/// </summary>
public void ResetPhase()
{
if (sliderController != null)
sliderController.ResetPhaseFlags();
}
/// <summary>
/// 重置发条-滑片循环(进入销售深入时调用)
/// </summary>
public void ResetCrankCycle()
{
_currentTurnIndex = 0;
crankController?.ResetCrank();
sliderController?.ResetPosition();
ResetPhase();
}
}
}