自定义 UIFieldBehavior 中的意外加速

Unexpected Acceleration in Custom UIFieldBehavior

我正在创建一个自定义字段以在用户执行平移手势后减慢对象的运动。使用正常摩擦会使物体感觉太滑,所以我尝试应用 spring 物理来代替摩擦。

我有一个函数似乎可以正确计算我正在寻找的行为。

extension UIFieldBehavior {
    static func dampingField(_ constant: CGFloat) -> UIFieldBehavior {
        return UIFieldBehavior.field { field, position, velocity, mass, charge, time in
            let speed = sqrt(pow(velocity.dx, 2) + pow(velocity.dy, 2))
            let angle = acos(velocity.dx / speed)
            let force = -constant * speed
            guard angle.isNaN == false, force.isNaN == false
                else { return .zero }
            return  CGVector(dx: cos(angle) * force, dy: sin(angle) * force)
        }
    }
}

但是,垂直运动的表现与我预期的不同。朝向参考视图顶部的任何运动都会导致对象加速更快。

我玩三角函数有一段时间了,但我被难住了。 GitHub 上的 an example swift playground 证明了这个问题。

我在数学中忽略了什么?

答案简直是在梦中得到的,哈哈。

意外的行为是负 y 方向的力应该是正的,但它是负的——导致最终速度的绝对值增加。

果然,添加检查以确保力的 y 分量始终与给定速度的 y 分量具有相反的符号解决了问题。

var vector = CGVector(dx: cos(angle) * force, dy: sin(angle) * force)
if vector.dy.sign == velocity.dy.sign {
    vector.dy *= -1
}
return vector

试图思考为什么只有 y 分量被错误地签名,我注意到角度是相对于 x 轴计算的。

let angle = acos(velocity.dx / speed)

我想我会尝试根据相对于 y 轴的角度计算 y 坐标的力,这也解决了问题。

return CGVector(dx: cos(angle) * force, dy: sin(asin(velocity.dy / speed)) * force)

想了一下,我意识到,由于asinacos分别是sincos的倒数,所以可以减少代码完全删除 sincos 的使用。

return CGVector(dx: velocity.dx / speed * force, dy: velocity.dy / speed * force)

不过,实际上,我根本不需要将三角函数引入其中,因为对向量分量的运算等同于对向量本身的运算。现在我的力按预期工作并且更容易推理。

extension UIFieldBehavior {
    static func dampingField(_ constant: CGFloat) -> UIFieldBehavior {
        return UIFieldBehavior.field { field, position, velocity, mass, charge, time in
            return  CGVector(dx: -constant * velocity.dx, dy: -constant * velocity.dy)
        }
    }
}