自定义UIFieldBehavior

时间:2018-05-20 20:48:49

标签: ios swift uikit physics uikit-dynamics

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

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

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来证明这个问题。

我在数学中忽略了什么?

1 个答案:

答案 0 :(得分:0)

答案字面意思是在梦中找到我,哈哈。

出乎意料的行为是负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)
        }
    }
}