using System.Collections;
using UnityEngine;
using UnityEngine.Events;
using DG.Tweening;
using Yarn.Unity;
namespace AibisDream.MiniGame.HuoShan
{
///
/// 处理器旋钮控制器 - 实现旋钮的拖拽调节和失败逻辑
/// 功能:
/// - 旋钮拖拽旋转(0-360度)
/// - 角度映射到功率值(0-100%)
/// - 降功率失败判定
/// - 信息面板显示失败结果
///
public class KnobController : MonoBehaviour
{
[System.Serializable]
public class PowerLevel
{
public float angle; // 旋钮角度
public float power; // 对应的功率百分比
public Color indicatorColor; // 指示器颜色
}
[Header("旋钮配置")]
[Tooltip("旋钮旋转的Transform")]
[SerializeField] private Transform knobTransform;
[Tooltip("功率指示器Transform(红色指示器)")]
[SerializeField] private Transform powerIndicator;
[Tooltip("旋钮刻度区间")]
[SerializeField] private PowerLevel[] powerLevels = new PowerLevel[]
{
new PowerLevel { angle = 0f, power = 100f, indicatorColor = Color.red },
new PowerLevel { angle = 90f, power = 75f, indicatorColor = new Color(1f, 0.5f, 0f) },
new PowerLevel { angle = 180f, power = 50f, indicatorColor = Color.yellow },
new PowerLevel { angle = 270f, power = 25f, indicatorColor = Color.green },
new PowerLevel { angle = 360f, power = 0f, indicatorColor = Color.gray }
};
[Tooltip("初始功率(%)")]
[SerializeField] private float initialPower = 100f;
[Tooltip("最小可接受功率(%)")]
[SerializeField] private float minAcceptablePower = 70f;
[Tooltip("拖拽阻力")]
[SerializeField] private float dragResistance = 0.1f;
[Tooltip("旋钮旋转动画时长")]
[SerializeField] private float rotationDuration = 0.2f;
[Header("氖光灯配置")]
[Tooltip("氖光灯Transform")]
[SerializeField] private Transform neonLight;
[Tooltip("氖光灯材质属性名")]
[SerializeField] private string neonProperty = "_EmissionColor";
[Tooltip("氖光灯最大闪烁强度")]
[SerializeField] private float maxNeonFlicker = 2f;
[Tooltip("氖光灯闪烁速度")]
[SerializeField] private float neonFlickerSpeed = 5f;
[Header("信息面板")]
[Tooltip("信息面板GameObject")]
[SerializeField] private GameObject infoPanel;
[Tooltip("信息面板文本组件")]
[SerializeField] private UnityEngine.UI.Text infoText;
[Tooltip("失败信息")]
[SerializeField] private string failMessage = "表达模块拒绝了未被处理的波形";
[Tooltip("面板显示动画时长")]
[SerializeField] private float panelShowDuration = 0.3f;
[Tooltip("面板隐藏动画时长")]
[SerializeField] private float panelHideDuration = 0.2f;
[Header("事件")]
[Tooltip("功率调节开始时触发")]
public UnityEvent onPowerAdjustmentStart;
[Tooltip("功率改变时触发(参数:当前功率%)")]
public UnityEvent onPowerChanged;
[Tooltip("功率调节失败时触发")]
public UnityEvent onPowerAdjustmentFail;
[Tooltip("功率调节成功时触发")]
public UnityEvent onPowerAdjustmentSuccess;
private bool _isDragging = false;
private float _currentPower = 100f;
private float _currentAngle = 0f;
private float _targetAngle = 0f;
private Camera _mainCamera;
private Vector3 _dragStartPosition;
private float _dragStartAngle;
private Material _neonMaterial;
private float _neonIntensity;
private Tweener _knobTween;
private Tweener _neonTween;
private bool _hasFailed = false;
private bool _hasSucceeded = false;
#region 生命周期
private void Awake()
{
_mainCamera = Camera.main;
if (knobTransform == null)
{
knobTransform = transform;
}
// 获取氖光灯材质
if (neonLight != null)
{
Renderer renderer = neonLight.GetComponent();
if (renderer != null)
{
_neonMaterial = renderer.material;
}
}
// 初始状态隐藏信息面板
if (infoPanel != null)
{
infoPanel.SetActive(false);
}
}
private void Start()
{
// 初始化到最大功率
SetPower(initialPower, false);
}
private void Update()
{
HandleMouseInput();
UpdateKnobRotation();
UpdateNeonLight();
}
#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()
{
if (_hasFailed || _hasSucceeded) return;
_isDragging = true;
_dragStartPosition = Input.mousePosition;
_dragStartAngle = GetMouseAngle();
if (_knobTween != null)
{
_knobTween.Kill();
_knobTween = null;
}
onPowerAdjustmentStart?.Invoke();
}
private void ContinueDrag()
{
if (_hasFailed || _hasSucceeded) return;
// 获取鼠标相对于中心的角度
float mouseAngle = GetMouseAngle();
float deltaAngle = mouseAngle - _dragStartAngle;
// 将角度转换为旋钮角度(0-360)
_targetAngle = Mathf.Clamp(deltaAngle, 0f, 360f);
// 计算当前功率
float power = AngleToPower(_targetAngle);
SetPower(power);
}
private void EndDrag()
{
_isDragging = false;
}
private float GetMouseAngle()
{
Vector3 mouseWorldPos = _mainCamera.ScreenToWorldPoint(Input.mousePosition);
Vector3 direction = mouseWorldPos - knobTransform.position;
float angle = Mathf.Atan2(direction.y, direction.x) * Mathf.Rad2Deg;
if (angle < 0) angle += 360f;
return angle;
}
#endregion
#region 功率控制
private float AngleToPower(float angle)
{
// 根据powerLevels计算功率
if (powerLevels == null || powerLevels.Length == 0)
{
return 100f - (angle / 360f) * 100f;
}
// 找到最近的两个功率等级进行插值
PowerLevel lowerLevel = powerLevels[0];
PowerLevel upperLevel = powerLevels[powerLevels.Length - 1];
for (int i = 0; i < powerLevels.Length - 1; i++)
{
if (angle >= powerLevels[i].angle && angle <= powerLevels[i + 1].angle)
{
lowerLevel = powerLevels[i];
upperLevel = powerLevels[i + 1];
break;
}
}
// 在相邻等级之间插值
float t = (angle - lowerLevel.angle) / (upperLevel.angle - lowerLevel.angle);
return Mathf.Lerp(lowerLevel.power, upperLevel.power, t);
}
private float PowerToAngle(float power)
{
// 根据powerLevels计算角度
if (powerLevels == null || powerLevels.Length == 0)
{
return (1f - power / 100f) * 360f;
}
// 找到最近的两个功率等级进行插值
PowerLevel lowerLevel = powerLevels[0];
PowerLevel upperLevel = powerLevels[powerLevels.Length - 1];
for (int i = 0; i < powerLevels.Length - 1; i++)
{
if (power >= powerLevels[i].power && power <= powerLevels[i + 1].power)
{
lowerLevel = powerLevels[i];
upperLevel = powerLevels[i + 1];
break;
}
}
// 在相邻等级之间插值
float t = (power - lowerLevel.power) / (upperLevel.power - lowerLevel.power);
return Mathf.Lerp(lowerLevel.angle, upperLevel.angle, 1f - t);
}
private void SetPower(float power, bool animate = true)
{
power = Mathf.Clamp(power, 0f, 100f);
_currentPower = power;
_targetAngle = PowerToAngle(power);
// 检查失败条件
if (power < minAcceptablePower && !_hasFailed && !_hasSucceeded)
{
TriggerFailure();
}
// 触发功率改变事件
onPowerChanged?.Invoke(power);
Debug.Log($"KnobController: 功率调整为{power:F1}%");
}
///
/// 功率调节失败
///
private void TriggerFailure()
{
_hasFailed = true;
// 显示信息面板
ShowInfoPanel(failMessage);
// 触发失败事件
onPowerAdjustmentFail?.Invoke(_currentPower);
Debug.Log($"KnobController: 功率调节失败 - 当前功率{_currentPower:F1}%低于最低值{minAcceptablePower}%");
// 调用Yarn命令
StartCoroutine(ExecuteFailCommands());
}
#endregion
#region 信息面板
private void ShowInfoPanel(string message)
{
if (infoPanel == null || infoText == null) return;
infoText.text = message;
infoPanel.SetActive(true);
// 面板从上方滑入
RectTransform rectTransform = infoPanel.GetComponent();
if (rectTransform != null)
{
Vector3 originalPosition = rectTransform.anchoredPosition;
Vector3 startPosition = originalPosition + Vector3.up * 100f;
rectTransform.anchoredPosition = startPosition;
rectTransform.DOAnchorPos(originalPosition, panelShowDuration)
.SetEase(Ease.OutCubic);
}
}
private void HideInfoPanel()
{
if (infoPanel == null) return;
RectTransform rectTransform = infoPanel.GetComponent();
if (rectTransform != null)
{
Vector2 endPosition = rectTransform.anchoredPosition + Vector2.up * 100f;
rectTransform.DOAnchorPos(endPosition, panelHideDuration)
.SetEase(Ease.InCubic)
.OnComplete(() => infoPanel.SetActive(false));
}
else
{
infoPanel.SetActive(false);
}
}
#endregion
#region 旋钮和灯光更新
private void UpdateKnobRotation()
{
// 平滑旋转到目标角度
_currentAngle = Mathf.Lerp(_currentAngle, _targetAngle, Time.deltaTime * 5f);
// 应用阻力效果
float adjustedAngle = _currentAngle * (1f - dragResistance);
// 更新旋钮旋转
knobTransform.localRotation = Quaternion.Euler(0f, 0f, -adjustedAngle);
}
private void UpdateNeonLight()
{
if (_neonMaterial == null) return;
// 根据功率计算发光强度
float powerRatio = _currentPower / 100f;
float targetIntensity = maxNeonFlicker * powerRatio;
// 闪烁效果
float flicker = Mathf.Sin(Time.time * neonFlickerSpeed) * 0.2f + 0.8f;
_neonIntensity = targetIntensity * flicker;
// 更新材质发光
Color emissionColor = Color.white * _neonIntensity;
_neonMaterial.SetColor(neonProperty, emissionColor);
}
#endregion
#region Yarn命令
private IEnumerator ExecuteFailCommands()
{
// 等待一段时间后执行Yarn跳转
yield return new WaitForSeconds(2f);
// 这里可以执行Yarn命令,比如跳转到下一个节点
// 具体实现需要根据游戏的Yarn流程来定制
Debug.Log("KnobController: 执行失败后的Yarn命令");
// 示例:调用Yarn命令
// YarnSpinnerIntegration.Instance.RunCommand("jump", "下一个节点");
}
///
/// Yarn命令:尝试调节功率
///
[YarnCommand("adjust_power")]
public static IEnumerator AdjustPower(float targetPower)
{
var controller = FindObjectOfType();
if (controller != null)
{
controller.SetPower(targetPower);
yield return new WaitForSeconds(1f);
}
}
///
/// Yarn命令:重置旋钮
///
[YarnCommand("reset_knob")]
public static void ResetKnob()
{
var controller = FindObjectOfType();
if (controller != null)
{
controller.Reset();
}
}
#endregion
#region 公共方法
///
/// 获取当前功率
///
public float GetCurrentPower()
{
return _currentPower;
}
///
/// 获取是否失败
///
public bool HasFailed()
{
return _hasFailed;
}
///
/// 重置旋钮状态
///
public void Reset()
{
_hasFailed = false;
_hasSucceeded = false;
if (_knobTween != null)
{
_knobTween.Kill();
_knobTween = null;
}
if (_neonTween != null)
{
_neonTween.Kill();
_neonTween = null;
}
// 重置到初始功率
SetPower(initialPower);
// 隐藏信息面板
HideInfoPanel();
Debug.Log("KnobController: 重置状态");
}
///
/// 设置最小可接受功率
///
public void SetMinAcceptablePower(float minPower)
{
minAcceptablePower = minPower;
}
///
/// 强制触发成功(调试用)
///
public void ForceSuccess()
{
_hasSucceeded = true;
onPowerAdjustmentSuccess?.Invoke(_currentPower);
}
#endregion
}
}