From 03b77ef1bf7d66c91c5b294dc92e0ee4b815f9ee Mon Sep 17 00:00:00 2001 From: bottlefish <781230111@qq.com> Date: Fri, 27 Feb 2026 15:04:50 +0800 Subject: [PATCH] =?UTF-8?q?refactor(huoshan):=20SliderController=20?= =?UTF-8?q?=E7=A7=BB=E9=99=A4=E6=B3=A2=E5=BD=A2=E8=81=94=E5=8A=A8=E3=80=81?= =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E9=A1=BA=E6=97=B6=E9=92=88=E9=80=BB=E8=BE=91?= =?UTF-8?q?=E3=80=81=E6=B7=BB=E5=8A=A0=20Gizmo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Made-with: Cursor --- .../HuoShan/SalesSystem/SliderController.cs | 177 ++++++++++++------ 1 file changed, 115 insertions(+), 62 deletions(-) diff --git a/Assets/Scripts/MiniGame/HuoShan/SalesSystem/SliderController.cs b/Assets/Scripts/MiniGame/HuoShan/SalesSystem/SliderController.cs index 6d1853df6..4aa32ad07 100644 --- a/Assets/Scripts/MiniGame/HuoShan/SalesSystem/SliderController.cs +++ b/Assets/Scripts/MiniGame/HuoShan/SalesSystem/SliderController.cs @@ -6,11 +6,11 @@ using DG.Tweening; namespace AibisDream.MiniGame.HuoShan { /// - /// 滑片控制器 - 实现滑片沿圆环滑动以及与波形联动 + /// 滑片控制器 - 实现滑片沿圆环滑动 /// 功能: /// - 仅通过Yarn指令控制移动,不接受玩家直接交互 - /// - 滑片角度/弧度驱动波形参数 /// - 等离子体发光段:从起始位置到当前位置显示等离子体进度指示 + /// - 位置变化通过 onSliderPositionChanged 通知(EmotionWaveManager 等可订阅) /// public class SliderController : MonoBehaviour { @@ -75,17 +75,6 @@ namespace AibisDream.MiniGame.HuoShan [Tooltip("粒子渲染 Sorting Order")] [SerializeField] private int plasmaSortingOrder = 51; - [Header("兼容旧版 LineRenderer(可留空)")] - [Tooltip("若存在则禁用,改用 ParticleSystem")] - [SerializeField] private LineRenderer plasmaLineRenderer; - - [Header("波形联动")] - [Tooltip("波形检测器引用")] - [SerializeField] private WaveformDetector waveformDetector; - - [Tooltip("等离子体发光影响波形参数")] - [SerializeField] private bool plasmaAffectsWaveform = true; - [Header("事件")] [Tooltip("滑片位置改变时触发(参数:标准化位置0-1)")] public UnityEvent onSliderPositionChanged; @@ -103,7 +92,7 @@ namespace AibisDream.MiniGame.HuoShan public UnityEvent onSlideComplete; [Header("调试测试")] - [Tooltip("勾选后,拖拽下方滑块可直接测试滑片与弧线(Play 模式下生效);有程序控制滑动时会自动跳过")] + [Tooltip("勾选后,拖拽下方滑块可直接测试滑片与弧线(Play 模式下生效,优先于程序控制)")] [SerializeField] private bool useTestSlider; [Tooltip("测试用滑块:0=起始位置,1=终点位置")] @@ -111,7 +100,6 @@ namespace AibisDream.MiniGame.HuoShan private float _currentAngle = 0f; private float _targetAngle = 0f; - private WaveformRenderer _waveformRenderer; private bool _phaseSemanticFired; private bool _phaseReviewFired; private bool _phaseStyleFired; @@ -132,20 +120,8 @@ namespace AibisDream.MiniGame.HuoShan sliderTransform = transform; } - // 禁用旧版 LineRenderer(改用 ParticleSystem) - if (plasmaLineRenderer != null) - { - plasmaLineRenderer.enabled = false; - } - // 初始化等离子体粒子系统 EnsurePlasmaParticleSystem(); - - // 获取波形渲染器 - if (waveformDetector != null && waveformDetector.IsShown) - { - _waveformRenderer = waveformDetector.GetComponentInChildren(); - } } private void Update() @@ -166,22 +142,16 @@ namespace AibisDream.MiniGame.HuoShan #region 位置更新 - private void UpdateSliderPosition() + /// + /// 根据角度应用滑片位置与旋转(顺时针移动:角度取负) + /// + /// 滑片世界坐标 + private Vector3 ApplyAngleToTransform(float angle) { -#if UNITY_EDITOR - // 调试模式:Inspector 滑块直接驱动滑片(有程序控制的滑动时跳过,避免覆盖 crank 驱动) - if (useTestSlider && Application.isPlaying && (_moveTween == null || !_moveTween.IsActive())) - { - _targetAngle = testSliderPosition * slideAngleRange; - } -#endif + if (ringCenter == null || sliderTransform == null) return _lastValidPosition; - // 匀速移动到目标角度(避免 Lerp 导致的越接近越慢、卡顿感) - float maxDelta = slideSpeed * Time.deltaTime; - _currentAngle = Mathf.MoveTowards(_currentAngle, _targetAngle, maxDelta); - - // 计算滑片在世界空间的位置 - float radian = (_currentAngle + startAngleOffset) * Mathf.Deg2Rad; + // 顺时针:标准数学角度增加为逆时针,取负则为顺时针 + float radian = -(angle + startAngleOffset) * Mathf.Deg2Rad; Vector3 position = ringCenter.position + new Vector3( Mathf.Cos(radian) * outerRadius, Mathf.Sin(radian) * outerRadius, @@ -190,12 +160,39 @@ namespace AibisDream.MiniGame.HuoShan sliderTransform.position = position; - // 滑片沿轨道顺时针方向(切线方向,与逆时针相反) + // 滑片沿轨道顺时针方向(切线方向) Vector3 direction = position - ringCenter.position; float radialAngle = Mathf.Atan2(direction.y, direction.x) * Mathf.Rad2Deg; float tangentAngle = radialAngle - 90f; // 顺时针切线 sliderTransform.rotation = Quaternion.Euler(0f, 0f, tangentAngle); + return position; + } + + private void UpdateSliderPosition() + { +#if UNITY_EDITOR + // 调试模式:Inspector 滑块直接驱动滑片,勾选后始终优先(覆盖程序控制) + if (useTestSlider && Application.isPlaying) + { + if (_moveTween != null && _moveTween.IsActive()) + { + _moveTween.Kill(); + _moveTween = null; + } + _targetAngle = testSliderPosition * slideAngleRange; + } +#endif + + // 匀速移动到目标角度(避免 Lerp 导致的越接近越慢、卡顿感) + float maxDelta = slideSpeed * Time.deltaTime; + _currentAngle = Mathf.MoveTowards(_currentAngle, _targetAngle, maxDelta); + + if (ringCenter == null || sliderTransform == null) return; + + // 计算滑片在世界空间的位置(顺时针:角度取负) + Vector3 position = ApplyAngleToTransform(_currentAngle); + // 夹子不跟随滑片移动,保持原位 // 触发位置改变事件 @@ -203,7 +200,6 @@ namespace AibisDream.MiniGame.HuoShan if (Vector3.Distance(position, _lastValidPosition) > 0.01f) { onSliderPositionChanged?.Invoke(normalizedPosition); - UpdateWaveform(normalizedPosition); _lastValidPosition = position; // 阶段阈值事件:1/3 语义组织, 2/3 审查, 1 风格 @@ -360,8 +356,9 @@ namespace AibisDream.MiniGame.HuoShan return; } - float startRad = startAngleOffset * Mathf.Deg2Rad; - float endRad = (startAngleOffset + _currentAngle) * Mathf.Deg2Rad; + // 顺时针:弧线从 startAngleOffset 向负角度延伸 + float startRad = -startAngleOffset * Mathf.Deg2Rad; + float endRad = -(startAngleOffset + _currentAngle) * Mathf.Deg2Rad; float arcSpan = endRad - startRad; float z = sliderTransform != null ? sliderTransform.position.z : ringCenter.position.z; @@ -405,34 +402,90 @@ namespace AibisDream.MiniGame.HuoShan #endregion - #region 波形联动 + #region Gizmo 与编辑器 - private void UpdateWaveform(float normalizedPosition) + private void OnDrawGizmosSelected() { - if (!plasmaAffectsWaveform || waveformDetector == null) return; + var center = ringCenter != null ? ringCenter.position : transform.position; + float z = sliderTransform != null ? sliderTransform.position.z : center.z; - // 将滑片位置映射到波形参数 - float waveformPosition = normalizedPosition; + // 外环 + Gizmos.color = new Color(0.2f, 0.8f, 1f, 0.6f); + DrawCircleGizmo(center, outerRadius, z, 64); - // 更新波形检测器的扫描位置 - if (waveformDetector.IsScanMode) + // 内环(等离子体弧线) + Gizmos.color = new Color(0.3f, 0.9f, 0.55f, 0.5f); + DrawCircleGizmo(center, innerRadius, z, 64); + + // 起始位置标记(绿色) + float startRad = -(0f + startAngleOffset) * Mathf.Deg2Rad; + Vector3 startPos = center + new Vector3(Mathf.Cos(startRad) * outerRadius, Mathf.Sin(startRad) * outerRadius, 0f); + Gizmos.color = Color.green; + Gizmos.DrawWireSphere(startPos, outerRadius * 0.05f); + + // 终点位置标记(黄色) + float endRad = -(slideAngleRange + startAngleOffset) * Mathf.Deg2Rad; + Vector3 endPos = center + new Vector3(Mathf.Cos(endRad) * outerRadius, Mathf.Sin(endRad) * outerRadius, 0f); + Gizmos.color = Color.yellow; + Gizmos.DrawWireSphere(endPos, outerRadius * 0.05f); + + // 段分割线 + Gizmos.color = new Color(1f, 1f, 0.5f, 0.3f); + float segAngle = slideAngleRange / Mathf.Max(1, segmentCount); + for (int i = 1; i < segmentCount; i++) { - // 如果处于扫描模式,更新扫描滑块 - // 这会是集成的一部分,具体实现需要根据游戏流程调整 + float rad = -(i * segAngle + startAngleOffset) * Mathf.Deg2Rad; + Vector3 segPos = center + new Vector3(Mathf.Cos(rad) * outerRadius, Mathf.Sin(rad) * outerRadius, 0f); + Gizmos.DrawLine(center, segPos); } - // 更新波形渲染器 - if (_waveformRenderer != null) + // 当前滑片位置(红色,仅 Play 模式有值) +#if UNITY_EDITOR + if (Application.isPlaying) +#endif { - // 根据滑片位置调整波形清晰度 - float clarity = Mathf.Lerp(0f, 1f, normalizedPosition); - _waveformRenderer.SetClarity(clarity); - - // 根据滑片位置调整波形位置 - _waveformRenderer.SetClarityPosition(normalizedPosition); + float curRad = -(_currentAngle + startAngleOffset) * Mathf.Deg2Rad; + Vector3 curPos = center + new Vector3(Mathf.Cos(curRad) * outerRadius, Mathf.Sin(curRad) * outerRadius, 0f); + Gizmos.color = Color.red; + Gizmos.DrawWireSphere(curPos, outerRadius * 0.08f); } } + private void DrawCircleGizmo(Vector3 center, float radius, float z, int segments) + { + Vector3 prev = center + new Vector3(radius, 0f, 0f); + for (int i = 1; i <= segments; i++) + { + float rad = (float)i / segments * Mathf.PI * 2f; + Vector3 next = center + new Vector3(Mathf.Cos(rad) * radius, Mathf.Sin(rad) * radius, 0f); + Gizmos.DrawLine(prev, next); + prev = next; + } + } + + /// + /// 在编辑器中一键将滑片重置到初始状态 + /// + [ContextMenu("重置到初始状态")] + private void ResetToInitialStateInEditor() + { + _targetAngle = 0f; + _currentAngle = 0f; + ResetPhaseFlags(); + if (_moveTween != null && _moveTween.IsActive()) + { + _moveTween.Kill(); + _moveTween = null; + } + if (ringCenter != null && sliderTransform != null) + ApplyAngleToTransform(0f); +#if UNITY_EDITOR + UnityEditor.EditorUtility.SetDirty(this); + if (gameObject.scene.IsValid()) + UnityEditor.SceneManagement.EditorSceneManager.MarkSceneDirty(gameObject.scene); +#endif + } + #endregion #region 公共方法