You need to enable JavaScript to run this app. 如何在Unity中实现带升降变速的3D对象空闲浮动动画并优化实现
优惠活动
大模型
产品
解决方案
定价
更多

如何在Unity中实现带升降变速的3D对象空闲浮动动画并优化实现

浮动动画优化方案

原代码的实际问题

  • 手动堆了方向、进度、速度、加速度一堆状态变量,写得啰嗦就算了,逻辑还和需求反了:到最高点反向的时候,代码里存的速度是全流程最大值,然后下落过程中速度逐渐减小,也就是下落越来越慢,和你要的「下降逐渐加速、上升逐步放缓」的效果完全不沾边
  • 每帧固定累加进度,没接Time.deltaTime,高帧率设备上会飘得特别快
  • 硬编码了Y轴的最小/最大值,把对象挪到别的位置后,动画会直接把物体拽到预设的固定Y值上
  • 边界判断容易因为浮点精度问题出bug,比如进度刚好卡在0或者1的时候来回震荡

不需要复杂状态机的实现思路

你说的用Mathf.PingPong的方向是对的,根本不用自己维护方向反向的逻辑:

  • Mathf.PingPong本身就能输出0到1再回到0的往返值,自动帮你处理周期切换
  • 只要给这个往返值套一层不对称的缓动公式,就能刚好匹配你要的速度曲线:eased = t * (2 - t)
    • 上升阶段(PingPong值从0升到1):用一半的上升时间就能走完75%的路程,越靠近最高点速度越慢,刚好是上升逐步放缓的效果
    • 下落阶段(PingPong值从1降到0):用一半的下落时间才走25%的路程,越靠近最低点速度越快,刚好是下落逐渐加速的效果

简化后的代码

public class IdleAnimation : MonoBehaviour
{
    [Header("浮动参数")]
    [Tooltip("垂直浮动的总幅度")]
    public float floatRange = 0.4f;
    [Tooltip("完成一次完整上下浮动的周期(秒)")]
    public float floatCycleTime = 2f;

    private Vector3 _originPos;
    private float _timer;

    void Start()
    {
        // 缓存物体初始位置,不需要硬编码坐标
        _originPos = transform.position;
    }

    void Update()
    {
        _timer += Time.deltaTime;
        // 拿0-1范围的PingPong往返值
        float pingValue = Mathf.PingPong(_timer / floatCycleTime, 1f);
        // 套缓动曲线,生成不对称的速度变化
        float easedValue = pingValue * (2f - pingValue);
        // 把缓动值映射为Y轴偏移
        float targetY = _originPos.y + (easedValue - 0.5f) * floatRange;
        // 只更新Y值,保留原来的X/Z位置
        transform.position = new Vector3(_originPos.x, targetY, _originPos.z);
    }
}

关于Mathf.SmoothStep的误区

很多人第一反应会套Mathf.SmoothStep,但它生成的是完全对称的S型曲线——上升和下降过程都是两头慢、中间快,根本没办法实现你要的“上升减速、下落加速”的不对称效果。如果想要更强的动态感,只要改缓动公式就行,比如换成三次曲线easedValue = Mathf.Pow(pingValue, 3f),就能得到更明显的慢上快下的效果。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.23 09:15:10