using UnityEngine; using UnityEngine.Events; using DG.Tweening; using System.Collections; namespace AibisDream.MiniGame.HuoShan { /// /// 发条控制器 - 实现发条的拖拽旋转交互 /// 功能:拖拽旋转,最大260°,缓慢回位,触发事件 /// public class CrankController : MonoBehaviour { [Header("发条配置")] [Tooltip("最大旋转角度(度)")] [SerializeField] private float maxRotationAngle = 260f; [Tooltip("回位速度(度/秒)")] [SerializeField] private float returnSpeed = 45f; [Tooltip("触发事件的最小角度(度)")] [SerializeField] private float triggerAngle = 240f; [Tooltip("拖拽阻力,值越大越难拖动")] [SerializeField] private float dragResistance = 0.1f; [Tooltip("是否自动返回初始位置")] [SerializeField] private bool autoReturn = true; [Header("事件" )] [Tooltip("发条达到最大角度并释放时触发")] public UnityEvent onCrankComplete; [Tooltip("发条旋转时触发(参数:当前角度0-1)")] public UnityEvent onCrankRotate; [Tooltip("发条开始拖拽时触发")] public UnityEvent onCrankStartDrag; [Header("视觉反馈")] [Tooltip("发条旋转的中心Transform")] [SerializeField] private Transform crankTransform; [Tooltip("拖拽时的缩放效果")] [SerializeField] private float dragScale = 1.05f; [Tooltip("缩放动画时长")] [SerializeField] private float scaleDuration = 0.1f; private Vector3 _dragStartPosition; private float _currentRotation = 0f; private bool _isDragging = false; private bool _hasTriggered = false; private Camera _mainCamera; private Vector3 _initialScale; private Tweener _scaleTween; private Tweener _returnTween; #region 生命周期 private void Awake() { _mainCamera = Camera.main; if (crankTransform != null) { _initialScale = crankTransform.localScale; } else { _initialScale = transform.localScale; crankTransform = transform; } } private void OnEnable() { ResetCrank(); } private void Update() { HandleMouseInput(); HandleReturn(); } #endregion #region 输入处理 private void HandleMouseInput() { if (Input.GetMouseButtonDown(0)) { Ray ray = _mainCamera.ScreenPointToRay(Input.mousePosition); RaycastHit2D hit = Physics2D.Raycast(ray.origin, ray.direction); if (hit.collider != null && hit.collider.gameObject == gameObject) { StartDrag(); } } if (_isDragging) { if (Input.GetMouseButton(0)) { ContinueDrag(); } else if (Input.GetMouseButtonUp(0)) { EndDrag(); } } } #endregion #region 拖拽逻辑 private void StartDrag() { _isDragging = true; _dragStartPosition = Input.mousePosition; _hasTriggered = false; if (_returnTween != null) { _returnTween.Kill(); _returnTween = null; } // 拖拽缩放效果 if (_scaleTween != null) _scaleTween.Kill(); _scaleTween = crankTransform.DOScale(_initialScale * dragScale, scaleDuration) .SetEase(Ease.OutQuad); onCrankStartDrag?.Invoke(); } private void ContinueDrag() { // 获取鼠标相对于中心的角度 Vector3 screenCenter = _mainCamera.WorldToScreenPoint(crankTransform.position); Vector3 currentMousePos = Input.mousePosition; // 计算角度 float angle = Mathf.Atan2(currentMousePos.y - screenCenter.y, currentMousePos.x - screenCenter.x) * Mathf.Rad2Deg; // 将角度转换为0-360范围 if (angle < 0) angle += 360f; // 限制最大旋转角度 angle = Mathf.Clamp(angle, 0f, maxRotationAngle); // 应用阻力效果 float targetRotation = angle * (1f - dragResistance); _currentRotation = Mathf.Lerp(_currentRotation, targetRotation, Time.deltaTime * 10f); // 更新旋转 crankTransform.localRotation = Quaternion.Euler(0f, 0f, -_currentRotation); // 触发旋转事件 float normalizedRotation = _currentRotation / maxRotationAngle; onCrankRotate?.Invoke(normalizedRotation); // 检查是否达到触发角度 if (_currentRotation >= triggerAngle && !_hasTriggered) { _hasTriggered = true; // 触发完成事件将在释放时调用 } } private void EndDrag() { _isDragging = false; // 恢复缩放 if (_scaleTween != null) _scaleTween.Kill(); _scaleTween = crankTransform.DOScale(_initialScale, scaleDuration) .SetEase(Ease.OutQuad); // 触发完成事件 if (_hasTriggered && _currentRotation >= triggerAngle) { onCrankComplete?.Invoke(); } } #endregion #region 回位逻辑 private void HandleReturn() { if (!_isDragging && autoReturn && _currentRotation > 0f) { if (_returnTween == null) { float returnDuration = _currentRotation / returnSpeed; _returnTween = DOTween.To( () => _currentRotation, value => { _currentRotation = value; crankTransform.localRotation = Quaternion.Euler(0f, 0f, -_currentRotation); float normalizedRotation = _currentRotation / maxRotationAngle; onCrankRotate?.Invoke(normalizedRotation); }, 0f, returnDuration ).SetEase(Ease.OutCubic).OnComplete(() => { _currentRotation = 0f; _returnTween = null; }); } } } #endregion #region 公共方法 public void ResetCrank() { if (_returnTween != null) { _returnTween.Kill(); _returnTween = null; } _isDragging = false; _hasTriggered = false; _currentRotation = 0f; if (crankTransform != null) { crankTransform.localRotation = Quaternion.identity; crankTransform.localScale = _initialScale; } } /// /// 手动旋转到指定角度(用于动画或程序化控制) /// public void RotateTo(float angle, float duration = 0.5f) { angle = Mathf.Clamp(angle, 0f, maxRotationAngle); if (_returnTween != null) { _returnTween.Kill(); _returnTween = null; } DOTween.To( () => _currentRotation, value => { _currentRotation = value; crankTransform.localRotation = Quaternion.Euler(0f, 0f, -_currentRotation); float normalizedRotation = _currentRotation / maxRotationAngle; onCrankRotate?.Invoke(normalizedRotation); }, angle, duration ).SetEase(Ease.OutCubic); } /// /// 获取当前旋转角度(0-1标准化) /// public float GetNormalizedRotation() { return _currentRotation / maxRotationAngle; } /// /// 获取当前旋转角度(度) /// public float GetCurrentAngle() { return _currentRotation; } /// /// 是否正在拖拽中 /// public bool IsDragging => _isDragging; /// /// 是否已达到触发角度 /// public bool HasTriggered => _hasTriggered; #endregion } }