472 lines
15 KiB
C#
472 lines
15 KiB
C#
using UnityEngine;
|
||
using UnityEngine.Events;
|
||
using System.Collections.Generic;
|
||
using DG.Tweening;
|
||
|
||
namespace AibisDream.MiniGame.HuoShan
|
||
{
|
||
/// <summary>
|
||
/// 处理器灯光控制器 - 管理多个处理器灯的显示
|
||
/// 功能:
|
||
/// - 根据滑片位置或索引控制特定处理器灯亮起
|
||
/// - 提供灯光明暗、闪烁、颜色变化效果
|
||
/// - 支持顺序激活多个处理器
|
||
/// </summary>
|
||
public class ProcessorLightController : MonoBehaviour
|
||
{
|
||
[System.Serializable]
|
||
public class ProcessorLightConfig
|
||
{
|
||
public GameObject lightObject;
|
||
public Light lightComponent;
|
||
public Renderer lightRenderer;
|
||
public Color normalColor = Color.gray;
|
||
public Color activeColor = new Color(0.3f, 0.9f, 0.55f);
|
||
public float intensity = 1f;
|
||
public float blinkSpeed = 1f;
|
||
public float fadeInDuration = 0.3f;
|
||
public string emissionProperty = "_EmissionColor";
|
||
public int segmentIndex = 0; // 对应的段索引
|
||
public float segmentStartAngle = 0f; // 该段的开始角度
|
||
public float segmentEndAngle = 30f; // 该段的结束角度
|
||
}
|
||
|
||
[Header("处理器配置")]
|
||
[Tooltip("处理器灯光配置列表")]
|
||
[SerializeField] private List<ProcessorLightConfig> processorLights = new List<ProcessorLightConfig>();
|
||
|
||
[Tooltip("默认激活持续时间(秒)")]
|
||
[SerializeField] private float defaultActiveDuration = 2f;
|
||
|
||
[Tooltip("灯光强度曲线(用于闪烁效果)")]
|
||
[SerializeField] private AnimationCurve intensityCurve = AnimationCurve.EaseInOut(0f, 0f, 1f, 1f);
|
||
|
||
[Header("全局设置")]
|
||
[Tooltip("等离子体发光影响所有处理器灯")]
|
||
[SerializeField] private bool plasmaAffectsAll = false;
|
||
|
||
[Tooltip("等离子体发光强度")]
|
||
[SerializeField] private float plasmaGlowIntensity = 0.5f;
|
||
|
||
[Tooltip("等离子体发光颜色")]
|
||
[SerializeField] private Color plasmaGlowColor = new Color(0.3f, 0.9f, 0.55f);
|
||
|
||
[Header("滑片联动")]
|
||
[Tooltip("滑片控制器引用(用于监听位置变化)")]
|
||
[SerializeField] private SliderController sliderController;
|
||
|
||
[Tooltip("滑片位置变化时自动更新处理器灯")]
|
||
[SerializeField] private bool autoUpdateFromSlider = true;
|
||
|
||
[Tooltip("滑片弧度到处理器索引的映射表,按角度排序")]
|
||
[SerializeField] private AnimationCurve angleToProcessorCurve = new AnimationCurve(
|
||
new Keyframe(0f, 0f),
|
||
new Keyframe(1f, 11f)
|
||
);
|
||
|
||
[Header("事件")]
|
||
[Tooltip("处理器灯激活时触发")]
|
||
public UnityEvent<int> onProcessorActivated;
|
||
|
||
[Tooltip("所有处理器灯关闭时触发")]
|
||
public UnityEvent onAllLightsOff;
|
||
|
||
private Dictionary<int, ProcessorLightConfig> _processorMap = new Dictionary<int, ProcessorLightConfig>();
|
||
private List<Tween> _activeTweens = new List<Tween>();
|
||
private bool _isInitialized = false;
|
||
private int _lastActiveProcessor = -1;
|
||
|
||
#region 生命周期
|
||
|
||
private void Awake()
|
||
{
|
||
InitializeProcessorMap();
|
||
}
|
||
|
||
private void OnEnable()
|
||
{
|
||
if (sliderController != null && autoUpdateFromSlider)
|
||
{
|
||
sliderController.onSliderPositionChanged.AddListener(OnSliderPositionChanged);
|
||
}
|
||
}
|
||
|
||
private void OnDisable()
|
||
{
|
||
if (sliderController != null)
|
||
{
|
||
sliderController.onSliderPositionChanged.RemoveListener(OnSliderPositionChanged);
|
||
}
|
||
|
||
// 清理所有Tweens
|
||
foreach (var tween in _activeTweens)
|
||
{
|
||
if (tween != null && tween.IsActive())
|
||
{
|
||
tween.Kill();
|
||
}
|
||
}
|
||
_activeTweens.Clear();
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 初始化
|
||
|
||
private void InitializeProcessorMap()
|
||
{
|
||
_processorMap.Clear();
|
||
|
||
foreach (var config in processorLights)
|
||
{
|
||
if (config.lightObject != null)
|
||
{
|
||
// 查找灯光组件
|
||
if (config.lightComponent == null)
|
||
{
|
||
config.lightComponent = config.lightObject.GetComponent<Light>();
|
||
}
|
||
|
||
// 查找渲染器
|
||
if (config.lightRenderer == null)
|
||
{
|
||
config.lightRenderer = config.lightObject.GetComponent<Renderer>();
|
||
}
|
||
|
||
// 初始化为关闭状态
|
||
SetLightState(config, false, 0f);
|
||
|
||
_processorMap[config.segmentIndex] = config;
|
||
}
|
||
}
|
||
|
||
_isInitialized = true;
|
||
Debug.Log($"ProcessorLightController: 初始化完成,共{processorLights.Count}个处理器灯");
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 滑片位置监听
|
||
|
||
private void OnSliderPositionChanged(float normalizedPosition)
|
||
{
|
||
if (!autoUpdateFromSlider) return;
|
||
|
||
// 映射滑片位置到处理器索引
|
||
int processorIndex = GetProcessorIndexFromSlider(normalizedPosition);
|
||
|
||
// 如果到达新的处理器段,激活对应的灯
|
||
if (processorIndex != _lastActiveProcessor)
|
||
{
|
||
ActivateProcessor(processorIndex);
|
||
_lastActiveProcessor = processorIndex;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 将滑片标准化位置(0-1)映射到处理器索引(0-processorCount-1)
|
||
/// </summary>
|
||
public int GetProcessorIndexFromSlider(float normalizedPosition)
|
||
{
|
||
// 使用AnimationCurve进行映射
|
||
float processorValue = angleToProcessorCurve.Evaluate(normalizedPosition);
|
||
return Mathf.RoundToInt(processorValue);
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 处理器灯光控制
|
||
|
||
/// <summary>
|
||
/// 根据角度激活对应的处理器灯
|
||
/// </summary>
|
||
public void ActivateProcessorByAngle(float angle)
|
||
{
|
||
float normalizedAngle = angle / 360f;
|
||
int processorIndex = GetProcessorIndexFromSlider(normalizedAngle);
|
||
ActivateProcessor(processorIndex);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 激活指定索引的处理器灯
|
||
/// </summary>
|
||
public void ActivateProcessor(int processorIndex, float duration = -1f)
|
||
{
|
||
if (!_isInitialized)
|
||
{
|
||
InitializeProcessorMap();
|
||
}
|
||
|
||
if (duration < 0)
|
||
{
|
||
duration = defaultActiveDuration;
|
||
}
|
||
|
||
// 先关闭所有灯
|
||
DeactivateAllProcessors(0.2f);
|
||
|
||
// 检查索引是否有效
|
||
if (processorIndex < 0 || processorIndex >= processorLights.Count)
|
||
{
|
||
Debug.LogWarning($"ProcessorLightController: 处理器索引{processorIndex}超出范围");
|
||
return;
|
||
}
|
||
|
||
// 获取配置
|
||
ProcessorLightConfig config = null;
|
||
foreach (var kvp in _processorMap)
|
||
{
|
||
if (kvp.Key == processorIndex)
|
||
{
|
||
config = kvp.Value;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (config != null)
|
||
{
|
||
// 激活灯光
|
||
SetLightState(config, true, duration);
|
||
|
||
// 触发事件
|
||
onProcessorActivated?.Invoke(processorIndex);
|
||
|
||
Debug.Log($"ProcessorLightController: 激活处理器{processorIndex}");
|
||
}
|
||
else
|
||
{
|
||
Debug.LogWarning($"ProcessorLightController: 找不到处理器索引{processorIndex}的配置");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 关闭所有处理器灯
|
||
/// </summary>
|
||
public void DeactivateAllProcessors(float fadeOutDuration = 0.3f)
|
||
{
|
||
foreach (var config in processorLights)
|
||
{
|
||
SetLightState(config, false, fadeOutDuration);
|
||
}
|
||
|
||
_lastActiveProcessor = -1;
|
||
onAllLightsOff?.Invoke();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 显示异常段的处理器灯(闪烁效果)
|
||
/// </summary>
|
||
public void ShowAnomalyProcessor(int processorIndex)
|
||
{
|
||
ProcessorLightConfig config = FindProcessorConfig(processorIndex);
|
||
if (config != null)
|
||
{
|
||
// 闪烁效果
|
||
FlashLight(config, Color.red, 2f, 3);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 设置灯光状态
|
||
/// </summary>
|
||
private void SetLightState(ProcessorLightConfig config, bool isActive, float transitionDuration)
|
||
{
|
||
if (config.lightObject == null) return;
|
||
|
||
// 设置灯光组件
|
||
if (config.lightComponent != null)
|
||
{
|
||
float targetIntensity = isActive ? config.intensity : 0f;
|
||
|
||
// 使用Tween实现平滑过渡
|
||
Tweener intensityTween = DOTween.To(
|
||
() => config.lightComponent.intensity,
|
||
value => config.lightComponent.intensity = value,
|
||
targetIntensity,
|
||
transitionDuration
|
||
).SetEase(Ease.OutQuad);
|
||
|
||
_activeTweens.Add(intensityTween);
|
||
}
|
||
|
||
// 设置渲染器发光
|
||
if (config.lightRenderer != null)
|
||
{
|
||
Color targetColor = isActive ? config.activeColor : config.normalColor;
|
||
|
||
// 对于使用Emission的材质
|
||
Material material = config.lightRenderer.material;
|
||
if (!string.IsNullOrEmpty(config.emissionProperty))
|
||
{
|
||
int propertyID = Shader.PropertyToID(config.emissionProperty);
|
||
Tweener colorTween = DOTween.To(
|
||
() => material.GetColor(propertyID),
|
||
value => material.SetColor(propertyID, value),
|
||
targetColor,
|
||
transitionDuration
|
||
).SetEase(Ease.OutQuad);
|
||
|
||
_activeTweens.Add(colorTween);
|
||
}
|
||
|
||
// 设置基础颜色
|
||
Tweener baseColorTween = DOTween.To(
|
||
() => config.lightRenderer.material.color,
|
||
value => config.lightRenderer.material.color = value,
|
||
targetColor,
|
||
transitionDuration
|
||
).SetEase(Ease.OutQuad);
|
||
|
||
_activeTweens.Add(baseColorTween);
|
||
}
|
||
|
||
// 更新GameObject状态
|
||
config.lightObject.SetActive(true);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 灯光闪烁效果
|
||
/// </summary>
|
||
private void FlashLight(ProcessorLightConfig config, Color flashColor, float duration, int flashCount)
|
||
{
|
||
// 先停止之前的动画
|
||
config.lightObject.GetComponent<Renderer>()?.material?.DOComplete();
|
||
|
||
// 执行闪烁
|
||
if (config.lightComponent != null)
|
||
{
|
||
Sequence flashSequence = DOTween.Sequence();
|
||
|
||
for (int i = 0; i < flashCount; i++)
|
||
{
|
||
flashSequence.Append(config.lightComponent.DOIntensity(config.intensity * 2f, duration / (flashCount * 2)));
|
||
flashSequence.Append(config.lightComponent.DOIntensity(config.intensity, duration / (flashCount * 2)));
|
||
}
|
||
|
||
_activeTweens.Add(flashSequence);
|
||
}
|
||
|
||
if (config.lightRenderer != null)
|
||
{
|
||
Color originalColor = config.lightRenderer.material.color;
|
||
Sequence colorSequence = DOTween.Sequence();
|
||
|
||
for (int i = 0; i < flashCount; i++)
|
||
{
|
||
colorSequence.Append(config.lightRenderer.material.DOColor(flashColor, duration / (flashCount * 2)));
|
||
colorSequence.Append(config.lightRenderer.material.DOColor(originalColor, duration / (flashCount * 2)));
|
||
}
|
||
|
||
_activeTweens.Add(colorSequence);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 查找处理器配置
|
||
/// </summary>
|
||
private ProcessorLightConfig FindProcessorConfig(int processorIndex)
|
||
{
|
||
if (_processorMap.TryGetValue(processorIndex, out var config))
|
||
{
|
||
return config;
|
||
}
|
||
|
||
foreach (var lightConfig in processorLights)
|
||
{
|
||
if (lightConfig.segmentIndex == processorIndex)
|
||
{
|
||
return lightConfig;
|
||
}
|
||
}
|
||
|
||
return null;
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 映射配置
|
||
|
||
/// <summary>
|
||
/// 更新角度到处理器的映射曲线
|
||
/// </summary>
|
||
public void UpdateAngleToProcessorCurve(AnimationCurve curve)
|
||
{
|
||
angleToProcessorCurve = curve;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 根据滑片控制器自动配置映射
|
||
/// </summary>
|
||
public void AutoConfigureMapping()
|
||
{
|
||
if (sliderController == null) return;
|
||
|
||
int segmentCount = sliderController.GetCurrentSegment();
|
||
if (segmentCount <= 0) return;
|
||
|
||
// 创建线性映射
|
||
Keyframe[] keys = new Keyframe[processorLights.Count];
|
||
float step = 1f / (processorLights.Count - 1);
|
||
|
||
for (int i = 0; i < processorLights.Count; i++)
|
||
{
|
||
keys[i] = new Keyframe(i * step, i);
|
||
}
|
||
|
||
angleToProcessorCurve = new AnimationCurve(keys);
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 公共方法
|
||
|
||
/// <summary>
|
||
/// 获取活动中的处理器索引
|
||
/// </summary>
|
||
public int GetActiveProcessor()
|
||
{
|
||
return _lastActiveProcessor;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取处理器数量
|
||
/// </summary>
|
||
public int GetProcessorCount()
|
||
{
|
||
return processorLights.Count;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 设置等离子体发光影响
|
||
/// </summary>
|
||
public void SetPlasmaGlow(float intensity, Color? color = null)
|
||
{
|
||
plasmaGlowIntensity = intensity;
|
||
if (color.HasValue)
|
||
{
|
||
plasmaGlowColor = color.Value;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 重置所有灯光
|
||
/// </summary>
|
||
public void Reset()
|
||
{
|
||
DeactivateAllProcessors();
|
||
_lastActiveProcessor = -1;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 配置处理器灯光数据
|
||
/// </summary>
|
||
public void ConfigureProcessorLights(List<ProcessorLightConfig> configs)
|
||
{
|
||
processorLights = configs;
|
||
InitializeProcessorMap();
|
||
}
|
||
|
||
#endregion
|
||
}
|
||
}
|