• Unity工具——LightTransition(光照过渡)


    需求描述

            在游戏中,开发者为了让玩家更直接地看到待拾取的物品从而为其添加一种闪烁效果,或者模拟现实中闪烁的灯光效果,我能够想到的一种方案则是通过控制光照强度来实现,那么本篇文章我们就尝试通过这个方案来实现一下,看看是否能够满足这类需求,这也能够作为我们个人资源库的一部分,以后如果在开发中有这方面需求,就可以直接把这个方案搬过来用,虽然这可能只是一个小小的功能,但这是一个积少成多的过程,只要我们能够完整地实现并使之通过测试,那么就算是一种成功,也能够从中获得收获。

    功能描述

            如果大家了解过LightLight2D组件,那么就应该知道其中的intensity属性用于控制光照强度,本质上闪烁就是通过改变光照强度的值来控制的,从暗到明,则对应intensity的值从小到大。        

            首先我们需要两个属性——光照强度起始值beginValue光照强度最终值endValue,还有从beginValue到endValue的光照强度变化的步长值stepValue,同时还要确定等待时间的属性timeSpan。为了使得这个组件应用更广泛,我们不公开beginValue和endValue,而是让使用者明确光照强度的最小值minValue以及光照强度最大值maxValue,所以beginValue既可以是minValue也可以是maxValue,这取决于使用者的需求。

            其次就是需要明确从beginValue到endValue的过渡方式了,我首先能够想到的是是否需要循环闪烁,假定属性Loop用于明确是否循环闪烁,如果不循环闪烁,那么只要从beginValue过渡到endValue就结束,若需要循环闪烁则需要明确循环的方式,如果每次循环都是从beginValue过渡到endValue则可以假定这种方式叫BeginToEnd,除此之外还可以是先从beginValue过渡到endValue然后再过渡到beginValue,类似一个钟摆一样,假定这种方式叫Pendulum

            最后我们还可以规定beginValue的取值,我们规定它要么是minValue,要么是maxValue,只要确定了beginValue,就可以确定endValue,所以我们假定属性beginValueType用于明确光照强度起始值的类型。

    属性解释
    LightUnity的Light组件
    Light2DUniversal RP中的Light2D组件
    intensity

    Light/Light2D组件的光照强度属性

    beginValue光照强度起始值
    endValue光照强度最终值
    stepValue光照强度变化的步长值
    timeSpan光照强度变化的时间间隔
    minValue光照强度的最小值
    maxValue光照强度的最大值
    Loop是否循环闪烁
    BeginToEnd每次循环都是从beginValue过渡到endValue
    Pendulum先从beginValue过渡到endValue然后再过渡到beginValue,类似一个钟摆
    beginValueType光照强度起始值的类型

    代码展示(C#)

    CommonLightTransition.cs

    1. using System.Collections;
    2. using UnityEngine;
    3. namespace Tools
    4. {
    5. public class CommonLightTransition : MonoBehaviour
    6. {
    7. [Header("必要属性")]
    8. [Tooltip("光照强度变化平均值,默认值为0.1(值>0)")]
    9. [SerializeField] private float IntensityStepValue = 0.1f;
    10. [Tooltip("光照强度最小值,默认值为1(值属于[0,IntensityMaxValue))")]
    11. [SerializeField] private float IntensityMinValue = 1;
    12. [Tooltip("光照强度最大值,默认值为2(值>IntensityMinValue)")]
    13. [SerializeField] private float IntensityMaxValue = 2;
    14. [Tooltip("过渡时间间隔,默认值为0.05,单位s(值>0)")]
    15. [SerializeField] private float TransitionTimeSpan = 0.05f;
    16. [Tooltip("是否开启光照过渡循环,默认值为true")]
    17. [SerializeField] private bool Loop = true;
    18. [Tooltip("光照过渡循环方式,需要勾选Loop该选项才有效,BeginToEnd是每次循环从光照过渡起始值开始,Pendulum是从光照过渡起始值至光照过渡最终值再过渡至光照过渡起始值(钟摆式过渡)")]
    19. [SerializeField] private LoopMode TheLoopMode;
    20. [Tooltip("光照过渡起始值类型,Min代表起始值从IntensityMinValue开始,Max同理")]
    21. [SerializeField] private BeginValueType TransitionBeginValueType;
    22. protected bool toMax;
    23. protected bool lockUnLoopTransition;
    24. protected int index;
    25. protected bool _isInit { get => isInit; }
    26. protected float[] _changedValues { get => changedValues; }
    27. protected BeginValueType _transitionBeginValueType { get => TransitionBeginValueType; }
    28. protected bool _loop { get => Loop; }
    29. protected LoopMode _loopMode { get => TheLoopMode; }
    30. protected float _intensityMinValue { get => IntensityMinValue; }
    31. protected float _intensityMaxValue { get => IntensityMaxValue; }
    32. private bool isInit, endTransition;
    33. private float[] changedValues;
    34. private IEnumerator coroutine;
    35. ///
    36. /// 启动过渡
    37. ///
    38. public void StartTransition()
    39. {
    40. if (isInit && endTransition)
    41. {
    42. StartCoroutine(coroutine);
    43. endTransition = false;
    44. }
    45. }
    46. ///
    47. /// 停止过渡
    48. ///
    49. public void StopTransition()
    50. {
    51. if (isInit && !endTransition)
    52. {
    53. StopCoroutine(coroutine);
    54. endTransition = true;
    55. }
    56. }
    57. ///
    58. /// 初始化游戏对象相关组件
    59. /// 返回值:初始化组件成功则返回true,否则返回false
    60. ///
    61. protected virtual bool InitComponents() { return false; }
    62. ///
    63. /// 光照过渡类型处理
    64. ///
    65. protected virtual void TransitionTypeDeal() { }
    66. ///
    67. /// 非循环光照过渡
    68. ///
    69. protected virtual void UnLoopLightTransition() { }
    70. ///
    71. /// 循环光照过渡
    72. ///
    73. protected virtual void LoopLightTransition() { }
    74. ///
    75. /// 组件检测控制台提示方法
    76. /// 声明:该方法仅在Unity Editor模式下且当Inspector面板中组件属性发生更改时执行
    77. ///
    78. protected virtual void ComponentLog() { }
    79. ///
    80. /// 光照过渡起始值类型
    81. ///
    82. protected enum BeginValueType
    83. {
    84. Min, Max
    85. }
    86. ///
    87. /// 循环光照过渡方式
    88. ///
    89. protected enum LoopMode
    90. {
    91. BeginToEnd, Pendulum
    92. }
    93. private void Start()
    94. {
    95. isInit = InitComponents() && InitParameters();
    96. }
    97. //初始化游戏对象相关参数
    98. private bool InitParameters()
    99. {
    100. if (IntensityStepValue <= 0 || IntensityMinValue < 0 || IntensityMaxValue <= 0) return false;
    101. if (IntensityMinValue >= IntensityMaxValue) return false;
    102. if (TransitionTimeSpan <= 0) return false;
    103. changedValues = NumberRange.FloatRange(IntensityMinValue, IntensityMaxValue, IntensityStepValue, true);
    104. if (changedValues == null && changedValues.Length == 0) return false;
    105. TransitionTypeDeal();
    106. coroutine = UnLoopTransition();
    107. if (Loop)
    108. {
    109. lockUnLoopTransition = true;
    110. coroutine = LoopTransition();
    111. }
    112. endTransition = true;
    113. return true;
    114. }
    115. private IEnumerator LoopTransition()
    116. {
    117. while (true)
    118. {
    119. LoopLightTransition();
    120. yield return new WaitForSeconds(TransitionTimeSpan);
    121. }
    122. }
    123. private IEnumerator UnLoopTransition()
    124. {
    125. while (!lockUnLoopTransition)
    126. {
    127. UnLoopLightTransition();
    128. yield return new WaitForSeconds(TransitionTimeSpan);
    129. }
    130. endTransition = true;
    131. }
    132. #if UNITY_EDITOR
    133. private void OnValidate()
    134. {
    135. ComponentLog();
    136. }
    137. #endif
    138. }
    139. }

    LightTransition2D.cs 

    1. using UnityEngine.Experimental.Rendering.Universal;
    2. using UnityEngine;
    3. namespace Tools
    4. {
    5. public class LightTransition2D : CommonLightTransition
    6. {
    7. [Header("必要组件(需要下载扩展包:Universal RP)")]
    8. [Tooltip("Light2D组件")]
    9. [SerializeField] private Light2D Light2D;
    10. private bool isLight2DLog;
    11. //初始化游戏对象相关组件
    12. protected sealed override bool InitComponents()
    13. {
    14. if (Light2D == null) return false;
    15. return true;
    16. }
    17. //光照过渡类型处理
    18. protected sealed override void TransitionTypeDeal()
    19. {
    20. if (_transitionBeginValueType == BeginValueType.Min)
    21. {
    22. Light2D.intensity = _intensityMinValue;
    23. index = 0;
    24. toMax = true;
    25. }
    26. else
    27. {
    28. Light2D.intensity = _intensityMaxValue;
    29. index = _changedValues.Length - 1;
    30. toMax = false;
    31. }
    32. }
    33. //非循环光照过渡
    34. protected sealed override void UnLoopLightTransition()
    35. {
    36. if (_isInit && !lockUnLoopTransition)
    37. {
    38. if (_transitionBeginValueType == BeginValueType.Min)
    39. {
    40. if (index >= _changedValues.Length)
    41. {
    42. lockUnLoopTransition = true;
    43. return;
    44. }
    45. Light2D.intensity = _changedValues[index++];
    46. }
    47. else
    48. {
    49. if (index < 0)
    50. {
    51. lockUnLoopTransition = true;
    52. return;
    53. }
    54. Light2D.intensity = _changedValues[index--];
    55. }
    56. }
    57. }
    58. //循环光照过渡
    59. protected sealed override void LoopLightTransition()
    60. {
    61. if (_isInit && _loop)
    62. {
    63. if (_loopMode == LoopMode.Pendulum)
    64. {
    65. if (index <= 0) toMax = true;
    66. else if (index >= _changedValues.Length - 1) toMax = false;
    67. }
    68. else if (index < 0 || index > _changedValues.Length - 1) TransitionTypeDeal();
    69. if (toMax) Light2D.intensity = _changedValues[index++];
    70. else Light2D.intensity = _changedValues[index--];
    71. }
    72. }
    73. //组件检测控制台提示方法
    74. protected sealed override void ComponentLog()
    75. {
    76. if (Light2D == null)
    77. {
    78. if (!isLight2DLog)
    79. {
    80. Debug.LogWarning("The component \"Light2D\" is null.");
    81. isLight2DLog = true;
    82. }
    83. }
    84. else isLight2DLog = false;
    85. }
    86. }
    87. }

    LightTransition.cs 

    1. using UnityEngine;
    2. namespace Tools
    3. {
    4. public class LightTransition : CommonLightTransition
    5. {
    6. [Header("必要组件")]
    7. [Tooltip("Light组件")]
    8. [SerializeField] private Light Light;
    9. private bool isLightLog;
    10. //初始化游戏对象相关组件
    11. protected sealed override bool InitComponents()
    12. {
    13. if (Light == null) return false;
    14. return true;
    15. }
    16. //光照过渡类型处理
    17. protected sealed override void TransitionTypeDeal()
    18. {
    19. if (_transitionBeginValueType == BeginValueType.Min)
    20. {
    21. Light.intensity = _intensityMinValue;
    22. index = 0;
    23. toMax = true;
    24. }
    25. else
    26. {
    27. Light.intensity = _intensityMaxValue;
    28. index = _changedValues.Length - 1;
    29. toMax = false;
    30. }
    31. }
    32. //非循环光照过渡
    33. protected sealed override void UnLoopLightTransition()
    34. {
    35. if (_isInit && !lockUnLoopTransition)
    36. {
    37. if (_transitionBeginValueType == BeginValueType.Min)
    38. {
    39. if (index >= _changedValues.Length)
    40. {
    41. lockUnLoopTransition = true;
    42. return;
    43. }
    44. Light.intensity = _changedValues[index++];
    45. }
    46. else
    47. {
    48. if (index < 0)
    49. {
    50. lockUnLoopTransition = true;
    51. return;
    52. }
    53. Light.intensity = _changedValues[index--];
    54. }
    55. }
    56. }
    57. //循环光照过渡
    58. protected sealed override void LoopLightTransition()
    59. {
    60. if (_isInit && _loop)
    61. {
    62. if (_loopMode == LoopMode.Pendulum)
    63. {
    64. if (index <= 0) toMax = true;
    65. else if (index >= _changedValues.Length - 1) toMax = false;
    66. }
    67. else if (index < 0 || index > _changedValues.Length - 1) TransitionTypeDeal();
    68. if (toMax) Light.intensity = _changedValues[index++];
    69. else Light.intensity = _changedValues[index--];
    70. }
    71. }
    72. //组件检测控制台提示方法
    73. protected sealed override void ComponentLog()
    74. {
    75. if (Light == null)
    76. {
    77. if (!isLightLog)
    78. {
    79. Debug.LogWarning("The component \"Light\" is null.");
    80. isLightLog = true;
    81. }
    82. }
    83. else isLightLog = false;
    84. }
    85. }
    86. }

    NumberRange.cs 

    1. using System.Collections.Generic;
    2. using System.Linq;
    3. namespace Tools
    4. {
    5. ///
    6. /// 数值范围数组工具类
    7. ///
    8. public static class NumberRange
    9. {
    10. ///
    11. /// 获取指定范围内指定步长的Float数值数组
    12. /// p_start:起始值
    13. /// p_end:终点值
    14. /// p_step:步长值
    15. /// [ContainsEnd]:是否包括终点值,默认为false
    16. /// 返回值:Float[]
    17. ///
    18. public static float[] FloatRange(float p_start, float p_end, float p_step, bool ContainsEnd = false)
    19. {
    20. if (!ContainsEnd) return DoFloatRange(p_start, p_end, p_step).ToArray();
    21. else
    22. {
    23. List<float> result = DoFloatRange(p_start, p_end, p_step).ToList();
    24. result.Add(p_end);
    25. return result.ToArray();
    26. }
    27. }
    28. static IEnumerable<float> DoFloatRange(float p_start, float p_end, float p_step)
    29. {
    30. for (float i = p_start; i <= p_end; i += p_step)
    31. {
    32. yield return i;
    33. }
    34. }
    35. }
    36. }

    界面展示

    LightTransition2D

    LightTransition

    部分演示效果

    LightTransition2D组件的简单演示效果

    自定义Unity组件LightTransition(2D)

    LightTransition组件的简单演示效果 

    自定义Unity组件LightTransition(3D)

    资源下载

    GitHub_LightTransition     百度网盘

     如果这篇文章对你有帮助,请给作者点个赞吧!

  • 相关阅读:
    大家在日常工作中有哪些非常好用的在线办公软件?
    Flutter Doctor:Xcode 安装不完整
    MATLAB中subplot函数的使用
    伯俊ERP与金蝶云星空对接集成表头表体组合查询打通应收单新增
    计算机毕业设计django基于python金太阳家居电商平台
    python代码优化学习
    GitHub常用命令
    【OpenCV入门】第七部分——图像的几何变换
    Python Opencv实践 - 人脸识别CascadeClassifier
    多级编号和目录
  • 原文地址:https://blog.csdn.net/hgf1037882434/article/details/132892190