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

自定义UIFieldBehavior出现异常加速问题求助

问题分析与解决方案

你遇到的问题根源在于三角函数计算时没有考虑速度y分量的符号,导致阻尼力的方向在垂直向上运动时反而和运动方向一致,最终让物体越跑越快。

为什么原来的代码会出错?

UIKit的坐标系里,y轴是向下为正的——也就是说,物体向上运动时,velocity.dy是负数。你用acos(velocity.dx / speed)计算角度,这个函数的返回范围是0~π,对应的sin(angle)始终是非负的。再看力的计算:

let force = -constant * speed
// 当向上运动时,sin(angle)是正的,force是负的
return CGVector(dx: cos(angle) * force, dy: sin(angle) * force)

此时y方向的力是正 * 负 = 负,和velocity.dy的符号完全一致,相当于给向上运动的物体又加了一个向上的力,自然会加速。

修正方案:抛弃三角函数,直接基于速度向量生成阻尼力

其实你不需要用三角函数来分解力——我们要的阻尼力,本质就是与速度方向相反、大小和速度成正比的力,直接对速度向量做缩放就能实现,简单又准确:

extension UIFieldBehavior {
    static func dampingField(_ constant: CGFloat) -> UIFieldBehavior {
        return UIFieldBehavior.field { field, position, velocity, mass, charge, time in
            // 直接返回与速度反向的阻尼力,大小为 constant × 速度大小
            return CGVector(dx: -constant * velocity.dx, dy: -constant * velocity.dy)
        }
    }
}

逻辑验证

举个例子:

  • 当物体向上运动时,velocity.dy为负,力的y分量是-constant × 负 = 正(向下),正好阻碍向上运动;
  • 当物体向下运动时,velocity.dy为正,力的y分量是-constant × 正 = 负(向上),同样阻碍运动;
  • 水平方向的力也会严格和运动方向相反,完美实现你想要的阻尼效果。

如果之后需要做非线性阻尼(比如阻尼力和速度平方成正比),也可以先计算速度大小,再对速度向量归一化后缩放:

let speed = hypot(velocity.dx, velocity.dy)
guard speed > 0 else { return .zero }
let normalizedVelocity = CGVector(dx: velocity.dx / speed, dy: velocity.dy / speed)
return CGVector(dx: -constant * speed * normalizedVelocity.dx, dy: -constant * speed * normalizedVelocity.dy)

不过这个逻辑和上面的简化版完全等价,只是写法不同。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 07:17:27