我正在创建一个自定义字段,以在用户执行平移手势后减慢对象的运动。使用正常的摩擦使物体感觉太滑,所以我试图用弹簧物理代替摩擦。
我有一个似乎正确计算我正在寻找的行为的函数。
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来证明这个问题。
我在数学中忽略了什么?
答案 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)
稍微考虑一下,我意识到,由于asin
和acos
分别与sin
和cos
相反,因此代码可以减少以删除完全使用sin
和cos
。
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)
}
}
}