You need to enable JavaScript to run this app. 如何在Unity协程中实现带自定义生效区间的浮点值缓动变更?
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.23 13:45:06