diff --git a/Assets/Resources/Materials/PlasmaParticle.mat b/Assets/Resources/Materials/PlasmaParticle.mat
new file mode 100644
index 000000000..04da1b3af
--- /dev/null
+++ b/Assets/Resources/Materials/PlasmaParticle.mat
@@ -0,0 +1,85 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!21 &2100000
+Material:
+ serializedVersion: 8
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_Name: PlasmaParticle
+ m_Shader: {fileID: 200, guid: 0000000000000000f000000000000000, type: 0}
+ m_Parent: {fileID: 0}
+ m_ModifiedSerializedProperties: 0
+ m_ValidKeywords: []
+ m_InvalidKeywords: []
+ m_LightmapFlags: 4
+ m_EnableInstancingVariants: 0
+ m_DoubleSidedGI: 0
+ m_CustomRenderQueue: -1
+ stringTagMap: {}
+ disabledShaderPasses: []
+ m_LockedProperties:
+ m_SavedProperties:
+ serializedVersion: 3
+ m_TexEnvs:
+ - _BumpMap:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _DetailAlbedoMap:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _DetailMask:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _DetailNormalMap:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _EmissionMap:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _MainTex:
+ m_Texture: {fileID: 2800000, guid: 72872287c0cfd8a468e047b93b3d8413, type: 3}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _MetallicGlossMap:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _OcclusionMap:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ - _ParallaxMap:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
+ m_Ints: []
+ m_Floats:
+ - _BumpScale: 1
+ - _Cutoff: 0.5
+ - _DetailNormalMapScale: 1
+ - _DstBlend: 0
+ - _GlossMapScale: 1
+ - _Glossiness: 0.5
+ - _GlossyReflections: 1
+ - _InvFade: 1
+ - _Metallic: 0
+ - _Mode: 0
+ - _OcclusionStrength: 1
+ - _Parallax: 0.02
+ - _SmoothnessTextureChannel: 0
+ - _SpecularHighlights: 1
+ - _SrcBlend: 1
+ - _UVSec: 0
+ - _ZWrite: 1
+ m_Colors:
+ - _Color: {r: 1, g: 1, b: 1, a: 1}
+ - _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
+ - _TintColor: {r: 1, g: 1, b: 1, a: 1}
+ m_BuildTextureStacks: []
diff --git a/Assets/Resources/Materials/PlasmaParticle.mat.meta b/Assets/Resources/Materials/PlasmaParticle.mat.meta
new file mode 100644
index 000000000..3f422fc8c
--- /dev/null
+++ b/Assets/Resources/Materials/PlasmaParticle.mat.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: c3a322f56de44a941b232cf5730be4be
+NativeFormatImporter:
+ externalObjects: {}
+ mainObjectFileID: 0
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Scripts/MiniGame/HuoShan/SalesSystem/SliderController.cs b/Assets/Scripts/MiniGame/HuoShan/SalesSystem/SliderController.cs
index 15e128609..066bf1b47 100644
--- a/Assets/Scripts/MiniGame/HuoShan/SalesSystem/SliderController.cs
+++ b/Assets/Scripts/MiniGame/HuoShan/SalesSystem/SliderController.cs
@@ -1,3 +1,4 @@
+using AibisDream;
using UnityEngine;
using UnityEngine.Events;
using DG.Tweening;
@@ -7,9 +8,9 @@ namespace AibisDream.MiniGame.HuoShan
///
/// 滑片控制器 - 实现滑片沿圆环滑动以及与波形联动
/// 功能:
- /// - 滑片拖拽沿外环滑动
+ /// - 仅通过Yarn指令控制移动,不接受玩家直接交互
/// - 滑片角度/弧度驱动波形参数
- /// - 等离子体发光段显示
+ /// - 等离子体发光段:从起始位置到当前位置显示等离子体进度指示
///
public class SliderController : MonoBehaviour
{
@@ -36,28 +37,45 @@ namespace AibisDream.MiniGame.HuoShan
[Tooltip("滑片电夹Transform")]
[SerializeField] private Transform clampTransform;
- [Tooltip("滑片拖拽阻力")]
- [SerializeField] private float dragResistance = 0.05f;
-
- [Tooltip("是否自动吸附到离散位置")]
- [SerializeField] private bool snapToSegments = true;
-
- [Tooltip("离散段数量")]
+ [Tooltip("离散段数量(用于slide_to_segment等Yarn命令)")]
[SerializeField] private int segmentCount = 12;
- [Header("等离子体发光")]
- [Tooltip("等离子体发光对象(可多个)")]
- [SerializeField] private GameObject[] plasmaObjects;
+ [Header("等离子体弧线(Particle System)")]
+ [Tooltip("用于等离子体效果的粒子系统,不赋值则自动创建")]
+ [SerializeField] private ParticleSystem plasmaParticleSystem;
- [Tooltip("等离子体发光材质属性名")]
- [SerializeField] private string glowProperty = "_GlowIntensity";
+ [Tooltip("粒子数量下限(短弧时)")]
+ [SerializeField] [Min(2)] private int minParticleCount = 20;
- [Tooltip("发光强度")]
- [SerializeField] private float glowIntensity = 1f;
+ [Tooltip("粒子数量上限(满弧时)")]
+ [SerializeField] [Min(2)] private int maxParticleCount = 48;
+
+ [Tooltip("粒子大小")]
+ [SerializeField] private float particleSize = 0.08f;
+
+ [Tooltip("粒子材质(Additive 发光,需手动引用)")]
+ [SerializeField] private Material plasmaParticleMaterial;
+
+ [Tooltip("粒子纹理(圆形中心亮边沿渐隐,不引用则自动生成软圆)")]
+ [SerializeField] private Texture2D plasmaParticleTexture;
+
+ [Tooltip("流动速度(小球沿弧线移动速度,1=每秒跑完一整圈)")]
+ [SerializeField] private float flowSpeed = 3f;
[Tooltip("发光颜色")]
[SerializeField] private Color glowColor = new Color(0.3f, 0.9f, 0.55f);
+ [CustomSortingLayer]
+ [Tooltip("粒子渲染 Sorting Layer")]
+ [SerializeField] private int plasmaSortingLayerId;
+
+ [Tooltip("粒子渲染 Sorting Order")]
+ [SerializeField] private int plasmaSortingOrder = 51;
+
+ [Header("兼容旧版 LineRenderer(可留空)")]
+ [Tooltip("若存在则禁用,改用 ParticleSystem")]
+ [SerializeField] private LineRenderer plasmaLineRenderer;
+
[Header("波形联动")]
[Tooltip("波形检测器引用")]
[SerializeField] private WaveformDetector waveformDetector;
@@ -69,53 +87,42 @@ namespace AibisDream.MiniGame.HuoShan
[Tooltip("滑片位置改变时触发(参数:标准化位置0-1)")]
public UnityEvent onSliderPositionChanged;
- [Tooltip("滑片开始拖拽时触发")]
- public UnityEvent onSliderStartDrag;
+ [Header("调试测试")]
+ [Tooltip("勾选后,拖拽下方滑块可直接测试滑片与弧线(Play 模式下生效)")]
+ [SerializeField] private bool useTestSlider;
- [Tooltip("滑片释放时触发")]
- public UnityEvent onSliderReleased;
+ [Tooltip("测试用滑块:0=起始位置,1=终点位置")]
+ [SerializeField] [Range(0f, 1f)] private float testSliderPosition;
- private bool _isDragging = false;
private float _currentAngle = 0f;
private float _targetAngle = 0f;
- private float _startAngle = 0f;
- private Camera _mainCamera;
- private Vector3 _dragStartPosition;
- private Material[] _plasmaMaterials;
- private int _glowPropertyID;
private WaveformRenderer _waveformRenderer;
private Tweener _moveTween;
private Vector3 _lastValidPosition;
+ private ParticleSystem.Particle[] _particles;
+ private float[] _particlePhases;
+ private Material _plasmaMaterialInstance;
+ private Texture2D _generatedSoftCircleTexture;
+
#region 生命周期
private void Awake()
{
- _mainCamera = Camera.main;
- _glowPropertyID = Shader.PropertyToID(glowProperty);
-
if (sliderTransform == null)
{
sliderTransform = transform;
}
- // 缓存等离子体材质
- if (plasmaObjects != null && plasmaObjects.Length > 0)
+ // 禁用旧版 LineRenderer(改用 ParticleSystem)
+ if (plasmaLineRenderer != null)
{
- _plasmaMaterials = new Material[plasmaObjects.Length];
- for (int i = 0; i < plasmaObjects.Length; i++)
- {
- if (plasmaObjects[i] != null)
- {
- Renderer renderer = plasmaObjects[i].GetComponent();
- if (renderer != null)
- {
- _plasmaMaterials[i] = renderer.material;
- }
- }
- }
+ plasmaLineRenderer.enabled = false;
}
+ // 初始化等离子体粒子系统
+ EnsurePlasmaParticleSystem();
+
// 获取波形渲染器
if (waveformDetector != null && waveformDetector.IsShown)
{
@@ -125,105 +132,16 @@ namespace AibisDream.MiniGame.HuoShan
private void Update()
{
- HandleMouseInput();
UpdateSliderPosition();
UpdatePlasmaGlow();
}
- #endregion
-
- #region 输入处理
-
- private void HandleMouseInput()
+ private void OnDestroy()
{
- 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;
- _startAngle = GetMouseAngle();
-
- if (_moveTween != null)
- {
- _moveTween.Kill();
- _moveTween = null;
- }
-
- onSliderStartDrag?.Invoke();
- }
-
- private void ContinueDrag()
- {
- // 计算鼠标相对于中心的角度
- float mouseAngle = GetMouseAngle();
- float deltaAngle = mouseAngle - _startAngle;
-
- // 限制角度范围
- deltaAngle = Mathf.Clamp(deltaAngle, 0f, slideAngleRange);
-
- // 应用阻力
- _targetAngle = deltaAngle * (1f - dragResistance);
-
- // 更新起始角度用于下次计算
- _startAngle = mouseAngle;
- }
-
- private void EndDrag()
- {
- _isDragging = false;
-
- // 如果启用了离散位置,吸附到最近的段
- if (snapToSegments)
- {
- SnapToNearestSegment();
- }
-
- // 触发释放事件
- float normalizedPosition = _currentAngle / slideAngleRange;
- onSliderReleased?.Invoke(normalizedPosition);
- }
-
- private float GetMouseAngle()
- {
- Vector3 mouseWorldPos = _mainCamera.ScreenToWorldPoint(Input.mousePosition);
- Vector3 direction = mouseWorldPos - ringCenter.position;
- float angle = Mathf.Atan2(direction.y, direction.x) * Mathf.Rad2Deg;
- if (angle < 0) angle += 360f;
- return angle;
- }
-
- private void SnapToNearestSegment()
- {
- float segmentAngle = slideAngleRange / segmentCount;
- int targetSegment = Mathf.RoundToInt(_currentAngle / segmentAngle);
- _targetAngle = targetSegment * segmentAngle;
+ if (_plasmaMaterialInstance != null)
+ Destroy(_plasmaMaterialInstance);
+ if (_generatedSoftCircleTexture != null)
+ Destroy(_generatedSoftCircleTexture);
}
#endregion
@@ -232,6 +150,14 @@ namespace AibisDream.MiniGame.HuoShan
private void UpdateSliderPosition()
{
+#if UNITY_EDITOR
+ // 调试模式:Inspector 滑块直接驱动滑片
+ if (useTestSlider && Application.isPlaying)
+ {
+ _targetAngle = testSliderPosition * slideAngleRange;
+ }
+#endif
+
// 平滑移动到目标角度
_currentAngle = Mathf.Lerp(_currentAngle, _targetAngle, Time.deltaTime * 10f);
@@ -245,21 +171,13 @@ namespace AibisDream.MiniGame.HuoShan
sliderTransform.position = position;
- // 滑片朝向中心
- Vector3 direction = ringCenter.position - position;
- float angle = Mathf.Atan2(direction.y, direction.x) * Mathf.Rad2Deg;
- sliderTransform.rotation = Quaternion.Euler(0f, 0f, angle);
+ // 滑片沿轨道顺时针方向(切线方向,与逆时针相反)
+ 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);
- // 更新电夹位置(保持在圆环上)
- if (clampTransform != null)
- {
- Vector3 clampPosition = ringCenter.position + new Vector3(
- Mathf.Cos(radian) * (outerRadius - 0.2f),
- Mathf.Sin(radian) * (outerRadius - 0.2f),
- clampTransform.position.z
- );
- clampTransform.position = clampPosition;
- }
+ // 夹子不跟随滑片移动,保持原位
// 触发位置改变事件
float normalizedPosition = _currentAngle / slideAngleRange;
@@ -273,37 +191,178 @@ namespace AibisDream.MiniGame.HuoShan
#endregion
- #region 等离子体发光
+ #region 等离子体弧线
+
+ private void EnsurePlasmaParticleSystem()
+ {
+ if (plasmaParticleSystem != null)
+ {
+ ConfigureParticleSystem(plasmaParticleSystem);
+ return;
+ }
+
+ // 自动创建粒子系统
+ var go = new GameObject("PlasmaParticles");
+ go.transform.SetParent(transform);
+ go.transform.localPosition = Vector3.zero;
+ go.transform.localScale = Vector3.one;
+
+ plasmaParticleSystem = go.AddComponent();
+ ConfigureParticleSystem(plasmaParticleSystem);
+
+ var renderer = go.GetComponent();
+ if (renderer != null)
+ renderer.renderMode = ParticleSystemRenderMode.Billboard;
+ }
+
+ private void ConfigureParticleSystem(ParticleSystem ps)
+ {
+ var main = ps.main;
+ main.simulationSpace = ParticleSystemSimulationSpace.World;
+ main.loop = false;
+ main.startLifetime = 999f;
+ main.startSize = particleSize;
+ main.maxParticles = maxParticleCount;
+ main.playOnAwake = false;
+ main.startSpeed = 0f;
+ main.startColor = glowColor;
+
+ var emission = ps.emission;
+ emission.enabled = false;
+
+ var velocity = ps.velocityOverLifetime;
+ velocity.enabled = false;
+
+ var colorOverLifetime = ps.colorOverLifetime;
+ colorOverLifetime.enabled = false;
+
+ var sizeOverLifetime = ps.sizeOverLifetime;
+ sizeOverLifetime.enabled = false;
+
+ var renderer = ps.GetComponent();
+ if (renderer != null)
+ {
+ ApplyPlasmaMaterial(renderer);
+ int layerId = SortingLayer.IsValid(plasmaSortingLayerId) ? plasmaSortingLayerId : SortingLayer.layers[0].id;
+ renderer.sortingLayerID = layerId;
+ renderer.sortingOrder = plasmaSortingOrder;
+ }
+
+ // 初始化粒子数组
+ _particles = new ParticleSystem.Particle[maxParticleCount];
+ _particlePhases = new float[maxParticleCount];
+ for (int i = 0; i < maxParticleCount; i++)
+ {
+ _particlePhases[i] = (float)i / maxParticleCount;
+ }
+
+ ps.Play();
+ ps.Emit(maxParticleCount);
+ }
+
+ private void ApplyPlasmaMaterial(ParticleSystemRenderer renderer)
+ {
+ var tex = plasmaParticleTexture != null ? plasmaParticleTexture : GetOrCreateSoftCircleTexture();
+ if (tex == null) return;
+
+ Material mat = plasmaParticleMaterial != null ? plasmaParticleMaterial : null;
+ if (mat == null)
+ {
+ var shader = Shader.Find("Legacy Shaders/Particles/Additive") ?? Shader.Find("Particles/Additive");
+ if (shader == null) return;
+ mat = new Material(shader);
+ mat.SetColor("_TintColor", Color.white);
+ }
+ else
+ {
+ mat = new Material(plasmaParticleMaterial);
+ }
+ mat.mainTexture = tex;
+ _plasmaMaterialInstance = mat;
+ renderer.material = mat;
+ }
+
+ private Texture2D GetOrCreateSoftCircleTexture()
+ {
+ if (_generatedSoftCircleTexture != null) return _generatedSoftCircleTexture;
+
+ const int size = 64;
+ _generatedSoftCircleTexture = new Texture2D(size, size);
+ _generatedSoftCircleTexture.wrapMode = TextureWrapMode.Clamp;
+ _generatedSoftCircleTexture.filterMode = FilterMode.Bilinear;
+
+ var pixels = new Color[size * size];
+ float center = (size - 1) * 0.5f;
+ float radius = center;
+ for (int y = 0; y < size; y++)
+ for (int x = 0; x < size; x++)
+ {
+ float dx = x - center;
+ float dy = y - center;
+ float dist = Mathf.Sqrt(dx * dx + dy * dy);
+ float t = 1f - Mathf.Clamp01(dist / radius);
+ float alpha = t * t;
+ pixels[y * size + x] = new Color(1f, 1f, 1f, alpha);
+ }
+ _generatedSoftCircleTexture.SetPixels(pixels);
+ _generatedSoftCircleTexture.Apply();
+ return _generatedSoftCircleTexture;
+ }
private void UpdatePlasmaGlow()
{
- if (_plasmaMaterials == null || _plasmaMaterials.Length == 0) return;
+ if (plasmaParticleSystem == null || ringCenter == null || _particles == null) return;
- // 计算滑片当前位置占整个圆环的比例
- float progress = _currentAngle / slideAngleRange;
- float glowRange = progress * glowIntensity;
+ float progress = Mathf.Clamp01(_currentAngle / slideAngleRange);
- // 更新每个等离子体对象的发光强度
- for (int i = 0; i < _plasmaMaterials.Length; i++)
+ // 进度为 0 时隐藏粒子
+ if (progress <= 0.001f)
{
- if (_plasmaMaterials[i] != null)
- {
- // 根据等离子体对象的索引计算其位置
- float plasmaProgress = (float)i / _plasmaMaterials.Length;
-
- // 只有在滑片经过的位置才发光
- if (plasmaProgress <= progress)
- {
- float localGlow = Mathf.Lerp(0f, glowIntensity, 1f - (progress - plasmaProgress));
- _plasmaMaterials[i].SetFloat(_glowPropertyID, localGlow);
- _plasmaMaterials[i].SetColor("_Color", glowColor);
- }
- else
- {
- _plasmaMaterials[i].SetFloat(_glowPropertyID, 0f);
- }
- }
+ plasmaParticleSystem.SetParticles(_particles, 0);
+ return;
}
+
+ 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;
+ Vector3 center = ringCenter.position;
+
+ int aliveCount = plasmaParticleSystem.GetParticles(_particles);
+ if (aliveCount == 0)
+ {
+ plasmaParticleSystem.Emit(maxParticleCount);
+ return;
+ }
+
+ // 随进度在 min~max 间平滑过渡粒子数量
+ float countF = Mathf.Lerp(minParticleCount, maxParticleCount, progress);
+ int actualCount = Mathf.Clamp(Mathf.RoundToInt(countF), minParticleCount, maxParticleCount);
+
+ for (int i = 0; i < maxParticleCount; i++)
+ {
+ // 相位沿弧线流动
+ _particlePhases[i] += flowSpeed * Time.deltaTime;
+ if (_particlePhases[i] >= 1f) _particlePhases[i] -= 1f;
+ if (_particlePhases[i] < 0f) _particlePhases[i] += 1f;
+
+ float t = _particlePhases[i];
+ float angle = startRad + arcSpan * t;
+ Vector3 pos = center + new Vector3(Mathf.Cos(angle) * innerRadius, Mathf.Sin(angle) * innerRadius, z);
+
+ _particles[i].position = pos;
+ _particles[i].remainingLifetime = 999f;
+ _particles[i].startLifetime = 999f;
+ _particles[i].startSize = particleSize;
+ _particles[i].startColor = Color.Lerp(
+ new Color(glowColor.r, glowColor.g, glowColor.b, 0.5f),
+ glowColor,
+ t
+ );
+ }
+
+ plasmaParticleSystem.SetParticles(_particles, actualCount);
}
#endregion
@@ -396,11 +455,6 @@ namespace AibisDream.MiniGame.HuoShan
return _currentAngle / slideAngleRange;
}
- ///
- /// 是否正在拖拽
- ///
- public bool IsDragging => _isDragging;
-
///
/// 重置滑片位置
///
@@ -414,7 +468,6 @@ namespace AibisDream.MiniGame.HuoShan
_targetAngle = 0f;
_currentAngle = 0f;
- _isDragging = false;
}
///