You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Unity中控制AnimationCurve缓入/缓出速度且不改变总时长

解决方案

问题1:总时长固定的缓入/缓出逻辑实现

核心思路是将缓入/缓出时间作为总时长的比例部分,而非额外追加时间。比如总时长设为5秒,缓入2秒,那这2秒是包含在5秒内的,不会导致总时长增加。具体实现时,我们通过新增变量控制缓入/缓出的绝对时长,再转换为总时长的比例,以此约束动画曲线的有效作用区间。

问题2:通过代码关联变量与AnimationCurve的缓入/缓出时长

Inspector手动调整曲线难以精准对应时长比例,我们可以通过代码将缓入/缓出的时间比例映射到曲线的输入参数,让曲线只在对应比例的时间区间内生效,中间阶段保持匀速(或自定义状态)。

修改后的完整脚本

using System.Collections;
using UnityEngine;

public class Scaling : MonoBehaviour
{
    public GameObject objectToScale;
    public float duration = 5f; // 固定总时长
    public Vector3 minSize;
    public Vector3 maxSize;
    public bool scaleUp = false;
    public Coroutine scaleCoroutine;
    public AnimationCurve easeCurve; // 建议设为S型曲线(0到1的平滑过渡)
    public bool automatic = false;
    public bool coroutineIsRunning = false;
    
    // 新增:控制缓入/缓出的绝对时长(需小于总时长)
    public float easeInDuration = 1f; 
    public float easeOutDuration = 1f;

    private void Update()
    {
        if (automatic)
        {
            if (!coroutineIsRunning)
            {
                Scale();
            }
        }
        else
        {
            if (Input.GetKeyDown(KeyCode.G))
            {
                Scale();
            }
        }
    }

    private void Scale()
    {
        scaleUp = !scaleUp;

        if (scaleCoroutine != null)
            StopCoroutine(scaleCoroutine);

        scaleCoroutine = StartCoroutine(ScaleOverTime(objectToScale, (scaleUp ? maxSize : minSize), duration));
    }

    private IEnumerator ScaleOverTime(GameObject targetObj, Vector3 toScale, float duration)
    {
        float counter = 0;
        Vector3 startScaleSize = targetObj.transform.localScale;
        // 将缓入/缓出时长转换为总时长的比例
        float easeInRatio = Mathf.Clamp01(easeInDuration / duration);
        float easeOutRatio = Mathf.Clamp01(easeOutDuration / duration);
        // 确保缓入+缓出比例不超过1,避免逻辑冲突
        float totalEaseRatio = Mathf.Min(easeInRatio + easeOutRatio, 1f);
        float steadyRatio = 1f - totalEaseRatio;

        coroutineIsRunning = true;

        while (counter < duration)
        {
            counter += Time.deltaTime;
            float normalizedTime = counter / duration;
            float curveFactor;

            if (normalizedTime <= easeInRatio)
            {
                // 缓入阶段:将当前时间映射到曲线的0~1区间
                float curveInput = normalizedTime / easeInRatio;
                curveFactor = easeCurve.Evaluate(curveInput);
            }
            else if (normalizedTime >= 1f - easeOutRatio)
            {
                // 缓出阶段:将当前时间反转映射到曲线的0~1区间
                float curveInput = (1f - normalizedTime) / easeOutRatio;
                curveFactor = 1f - easeCurve.Evaluate(curveInput);
            }
            else
            {
                // 匀速阶段:直接取曲线的最大值(或固定为1)
                curveFactor = easeCurve.Evaluate(1f);
            }

            targetObj.transform.localScale = Vector3.Lerp(startScaleSize, toScale, curveFactor);

            if (counter >= duration)
            {
                coroutineIsRunning = false;
                targetObj.transform.localScale = toScale;
            }

            yield return null;
        }
    }
}

使用说明

  1. 参数设置:

    • 在Inspector中设置duration为固定总时长(比如5秒)
    • easeInDuration和easeOutDuration设为你需要的缓入/缓出绝对时长(比如各1秒,总占2秒,剩余3秒匀速)
    • 将easeCurve设为S型曲线(右键曲线→预设→In-Out),无需手动调整关键帧位置
  2. 逻辑说明:

    • 缓入阶段:前easeInDuration时间内,按曲线平滑加速缩放
    • 匀速阶段:中间剩余时间内保持匀速缩放
    • 缓出阶段:最后easeOutDuration时间内,按曲线平滑减速到目标尺寸
    • 所有阶段总时长严格等于duration,不会额外增加

内容的提问来源于stack exchange,提问作者Daniel Lip

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 15:00:36