如何在Unity协程中实现带自定义生效区间的浮点值缓动变更?
实现自定义数值区间的In-Out缓动方案
核心实现思路
常规Smoothstep缓动会强制在全流程先加速、后减速,我们可以将整个数值变化路径拆分为三个连续且速度无跳变的区段,仅在指定区段应用缓动:
- 起始缓动区段:从起始值到自定义的缓动结束值,实现从速度0到匀速的平滑加速
- 中间匀速区段:从起始缓动结束值到自定义的减速起始值,完全保持匀速运动
- 结束缓动区段:从减速起始值到目标最大值,实现从匀速到速度0的平滑减速
整个过程保证速度曲线连续无突变,同时完全自定义两个缓动段的生效数值范围。
具体实现代码
在原有代码基础上新增两个可配置参数,用来定义缓动的生效数值区间,替换原有协程逻辑即可直接运行:
// 原有基础参数 [SerializeField] float minValue = 0; [SerializeField] float maxValue = 100; [SerializeField] float duration = 10; // 新增自定义缓动区间参数 [SerializeField] float easeInRangeEnd = 20; // 从minValue到该值的数值区间,生效In加速缓动 [SerializeField] float easeOutRangeStart = 70; // 从该值到maxValue的数值区间,生效Out减速缓动 float value; void Start() { StartCoroutine(IncreaseSpeed(minValue, maxValue, duration)); } /// <summary> /// 带自定义区间缓动的数值递增协程 /// </summary> private IEnumerator IncreaseSpeed(float start, float end, float duration) { float time = 0; // 对自定义参数做边界校验,避免配置错误导致逻辑异常 easeInRangeEnd = Mathf.Clamp(easeInRangeEnd, minValue, maxValue); easeOutRangeStart = Mathf.Clamp(easeOutRangeStart, easeInRangeEnd, maxValue); while (time <= duration) { time += Time.deltaTime; // 先计算纯线性状态下的当前位置 float linearValue = Mathf.Lerp(start, end, time / duration); // 应用自定义区间的缓动映射 value = MapValueWithCustomEase(linearValue); yield return null; } // 修正浮点误差,确保最终值严格等于目标最大值 value = maxValue; } /// <summary> /// 对线性数值应用自定义区间的缓动映射 /// </summary> private float MapValueWithCustomEase(float x) { // 限制输入值在有效范围内 x = Mathf.Clamp(x, minValue, maxValue); // 1. 落在加速缓动段:应用三次In缓动函数,保证段边界斜率连续 if (x < easeInRangeEnd) { float segmentLength = easeInRangeEnd - minValue; float relativeX = x - minValue; // 三次缓动函数:满足端点速度为0、段末速度为1的连续条件 float mappedY = (-1f / (segmentLength * segmentLength)) * Mathf.Pow(relativeX, 3) + (2f / segmentLength) * Mathf.Pow(relativeX, 2); return minValue + mappedY; } // 2. 落在中间匀速段:直接返回原线性值,不做任何缓动处理 else if (x < easeOutRangeStart) { return x; } // 3. 落在减速缓动段:应用三次Out缓动函数,保证段边界斜率连续 else { float segmentLength = maxValue - easeOutRangeStart; float relativeX = x - easeOutRangeStart; // 三次缓动函数:满足段初速度为1、终点速度为0的连续条件 float mappedY = (-1f / (segmentLength * segmentLength)) * Mathf.Pow(relativeX, 3) + (1f / segmentLength) * Mathf.Pow(relativeX, 2) + relativeX; return easeOutRangeStart + mappedY; } }
效果验证
- 按照示例配置(minValue=0, maxValue=100, easeInRangeEnd=20, easeOutRangeStart=70),缓动效果完全匹配需求:仅在0-20的数值范围做从0开始的平滑加速,到达20后保持匀速运动,直到数值走到70后开始平滑减速,最终在10秒的总时长下稳定停在100的目标值
- 调整参数可以灵活适配不同需求:
- 当
easeInRangeEnd = minValue、easeOutRangeStart = maxValue时,全程为纯线性运动,无任何缓动效果,和原代码逻辑一致 - 当
easeInRangeEnd = (minValue+maxValue)/2、easeOutRangeStart = (minValue+maxValue)/2时,全程为标准的Smoothstep In-Out缓动,和Mathf.Smoothstep默认效果一致
- 当
- 整个速度曲线无突变,不会出现顿挫感,因为三个段在边界位置的运动斜率完全匹配,速度没有跳变
内容的提问来源于stack exchange,提问作者Abdo23
相关产品推荐
相关产品推荐

