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

带缓出效果的移动物体减速起始距离与幅度计算咨询

平滑缓出减速的计算方法与代码修改

一、核心计算逻辑

1. 减速起始距离怎么算?

用匀减速模型最容易落地,核心物理公式是 v² = 2*a*s:

  • v是你的初始速度:400px/s
  • a是减速度(自己定,直接决定减速幅度:a越大,减速越猛,需要的减速距离越短;a越小,减速越平缓,得留更长距离)
  • s就是你要的「减速起始距离」

举个实际例子:
如果想让减速过程持续1秒(用户感知自然),减速度a = 400px/s ÷ 1s = 400px/s²。
代入公式得:s = (400²) ÷ (2*400) = 200px——意思是当物体离目标点只剩200px时,开始减速。

要是觉得1秒太长,比如想0.5秒刹停,那a=400÷0.5=800px/s²,算出来s=100px,也就是剩100px时启动减速。

2. 减速过程的每帧速度计算

进入减速阶段后,不能再用固定速度,两种靠谱方式:

  • 逐帧递减:当前速度 = max(当前速度 - a*帧时长, 0)——保证速度不会变负,到0就停
  • 按剩余距离算:当前速度 = sqrt(2*a*剩余距离)——精准匹配匀减速到停止的速度,注意浮点精度问题

二、你的代码修改(带中文注释)

先把你提供的原代码翻译成中文注释版:

// 更新偏移量的方法:参数为帧持续时间、移动速度、总时长、到目标点的剩余距离
func updateOffset(frameDuration: TimeInterval, speed: CGFloat, duration: TimeInterval, distanceToTarget: CGFloat) {
    // 原逻辑:直接累加固定速度,无减速处理
    self.currentOffset += speed
}

下面是加入减速逻辑的修改版,直接可用:

// 存储当前实时速度,避免每次调用重置
private var currentSpeed: CGFloat = 0.0
// 自定义减速度,这里设为400px/s²(对应1秒从400px/s减到0),可按需调整
private let deceleration: CGFloat = 400.0

func updateOffset(frameDuration: TimeInterval, initialSpeed: CGFloat, distanceToTarget: CGFloat) {
    // 首次调用或重置时初始化速度
    if currentSpeed == 0.0 {
        currentSpeed = initialSpeed
    }
    
    // 计算减速起始距离
    let decelerationStartDistance = (initialSpeed * initialSpeed) / (2 * deceleration)
    
    if distanceToTarget > decelerationStartDistance {
        // 离目标尚远,保持初始速度移动
        currentOffset += currentSpeed * CGFloat(frameDuration)
    } else {
        // 进入减速阶段,逐帧降低速度
        currentSpeed = max(currentSpeed - deceleration * CGFloat(frameDuration), 0.0)
        currentOffset += currentSpeed * CGFloat(frameDuration)
        
        // 最后几帧防抖动:如果当前速度移动距离超过剩余距离,直接跳到目标点
        if currentSpeed * CGFloat(frameDuration) > distanceToTarget {
            currentOffset += distanceToTarget
            currentSpeed = 0.0
        }
    }
}

三、更丝滑的缓出效果:用缓动函数

如果觉得匀减速太生硬,想要「先慢减、后快减」的自然缓出,可用二次缓动函数(easeOutQuad):

// 缓出二次曲线函数:输入0~1的进度,输出缓动后的进度
private func easeOutQuad(t: CGFloat) -> CGFloat {
    return 1.0 - (1.0 - t) * (1.0 - t)
}

func updateOffsetWithEase(frameDuration: TimeInterval, initialSpeed: CGFloat, distanceToTarget: CGFloat) {
    // 自定义减速起始距离,比如设为200px
    let decelerationStartDistance: CGFloat = 200.0
    
    if distanceToTarget > decelerationStartDistance {
        // 未到减速点,正常匀速移动
        currentOffset += initialSpeed * CGFloat(frameDuration)
    } else {
        // 计算当前减速阶段的进度:0=刚进入减速,1=到达目标
        let progress = 1.0 - (distanceToTarget / decelerationStartDistance)
        // 用缓动函数处理进度,让减速更自然
        let easeProgress = easeOutQuad(t: progress)
        // 计算当前帧的移动距离
        let moveDistance = decelerationStartDistance * easeProgress - (decelerationStartDistance - distanceToTarget)
        currentOffset += moveDistance
        
        // 最后直接跳到目标,避免抖动
        if distanceToTarget <= moveDistance {
            currentOffset += distanceToTarget
        }
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 21:50:38