实现销售系统核心交互组件: - CrankController: 曲柄/旋钮控制 - KnobController: 旋钮交互逻辑 - ProcessorLightController: 处理器灯光控制 - SalesYarnCommand: Yarn 命令集成 - SliderController: 滑片控制器 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
297 lines
8.8 KiB
C#
297 lines
8.8 KiB
C#
using UnityEngine;
|
|
using UnityEngine.Events;
|
|
using DG.Tweening;
|
|
using System.Collections;
|
|
|
|
namespace AibisDream.MiniGame.HuoShan
|
|
{
|
|
/// <summary>
|
|
/// 发条控制器 - 实现发条的拖拽旋转交互
|
|
/// 功能:拖拽旋转,最大260°,缓慢回位,触发事件
|
|
/// </summary>
|
|
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<float> 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;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 手动旋转到指定角度(用于动画或程序化控制)
|
|
/// </summary>
|
|
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);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取当前旋转角度(0-1标准化)
|
|
/// </summary>
|
|
public float GetNormalizedRotation()
|
|
{
|
|
return _currentRotation / maxRotationAngle;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取当前旋转角度(度)
|
|
/// </summary>
|
|
public float GetCurrentAngle()
|
|
{
|
|
return _currentRotation;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 是否正在拖拽中
|
|
/// </summary>
|
|
public bool IsDragging => _isDragging;
|
|
|
|
/// <summary>
|
|
/// 是否已达到触发角度
|
|
/// </summary>
|
|
public bool HasTriggered => _hasTriggered;
|
|
|
|
#endregion
|
|
}
|
|
}
|