在 Swift 游戏中处理圆圈碰撞的最佳方法?
Best way to handle circle-circle collisions in a Swift game?
我正在用 SpriteKit 制作一个类似于 Air Hockey 的 Swift 游戏。
我正在尝试将 accurate/expected 'impulses' 应用到冰球上,当它被玩家的木槌敲击时。
我可以访问玩家的速度。我还通过使用 func didBegin(_ contact: SKPhysicsContact)
在两个圆圈之间进行了准确的碰撞检测。此外,我还根据球击中玩家槌的位置确定了球应该弹跳的预期方向(因为它是一个圆圈,所以这个方向可能与您通过查看玩家的 dx 和 dy 所期望的不同。)
这是我目前正在做的,但感觉有点不自然和不正常:
func didBegin(_ contact: SKPhysicsContact)
{
if (contact.bodyA.categoryBitMask == BodyType.ball.rawValue && contact.bodyB.categoryBitMask == BodyType.player.rawValue) && (contact.bodyA.contactTestBitMask == 25 || contact.bodyB.contactTestBitMask == 25) && bottomTouchForCollision == true
{
ball!.physicsBody!.applyImpulse(CGVector(dx: CGFloat(UserDefaults.standard.float(forKey: "BottomVelocity")) * contact.contactNormal.dx, dy: CGFloat(UserDefaults.standard.float(forKey: "BottomVelocity")) * contact.contactNormal.dy))
}
}
对球有准确和反应灵敏的冲动的最佳方法是什么。我认为完全依赖 contact.contactNormal.dy
的方向感觉不自然,因为如果玩家的圆圈在一个地方不动,那是预期的方向。几周来我一直在为这个问题苦苦挣扎,不知道如何最好地解决它。感谢代码解释,但任何帮助。
我以类似的方式问过这个问题并收到了回复:
"考虑球击中静止的木槌的情况。它会以相同的速度反射出去,并且运动的最终方向是入射角等于接触点处的反射角. 然后对于一个以速度矢量 v 移动的木槌,从所有速度中减去 v 以转换为固定木槌的情况。计算转换问题中的球速度。然后通过将 v 添加到结果来转换回来。(如果你正在计算它像那样,你不必applyImpulse,直接设置新的速度即可。)"
我无法理解如何实现这个想法,但如果有人可以提供伪代码或代码,那就太好了!
编辑:这是我在下面的帮助下得到的结果。
if (contact.bodyA.categoryBitMask == BodyType.ball.rawValue && contact.bodyB.categoryBitMask == BodyType.player.rawValue) && (contact.bodyA.contactTestBitMask == 75 || contact.bodyB.contactTestBitMask == 75) && northTouchForCollision == true
{
let vmallet = CGVector(dx: CGFloat(UserDefaults.standard.float(forKey: "NorthForceDX")), dy: CGFloat(UserDefaults.standard.float(forKey: "NorthForceDY")))
let vball = ball?.physicsBody?.velocity
let vrelativedx = vball!.dx - vmallet.dx
let vrelativedy = vball!.dy - vmallet.dy
let vrelative = CGVector(dx: vrelativedx, dy: vrelativedy)
let c = (vrelative.dx * contact.contactNormal.dx) + (vrelative.dy * contact.contactNormal.dy)
let vperpendicular = CGVector(dx: contact.contactNormal.dx * c, dy: contact.contactNormal.dy * c)
let vtangential = CGVector(dx: vrelative.dx - vperpendicular.dx, dy: vrelative.dy - vperpendicular.dy)
// vtangential is unchanged in the collision, vperpendicular reflects
let newvrelative = CGVector(dx: vtangential.dx - vperpendicular.dx, dy: vtangential.dy - vperpendicular.dy)
let newvball = CGVector(dx: newvrelative.dx + vmallet.dx, dy: newvrelative.dy + vmallet.dy)
// set ball velocity to newvball
// ball?.physicsBody?.velocity = newvball
ball!.physicsBody!.applyImpulse(newvball)
}
伪代码:
let vmallet = mallet velocity
let vball = ball velocity
let vrelative = vball - vmallet
let vperpendicular = dotProduct(vrelative, contactNormal) * contactNormal
let vtangential = vrelative - vperpendicular
// vtangential is unchanged in the collision, vperpendicular reflects
let newvrelative = vtangential - vperpendicular
let newvball = newvrelative + vmallet
// set ball velocity to newvball
我正在用 SpriteKit 制作一个类似于 Air Hockey 的 Swift 游戏。
我正在尝试将 accurate/expected 'impulses' 应用到冰球上,当它被玩家的木槌敲击时。
我可以访问玩家的速度。我还通过使用 func didBegin(_ contact: SKPhysicsContact)
在两个圆圈之间进行了准确的碰撞检测。此外,我还根据球击中玩家槌的位置确定了球应该弹跳的预期方向(因为它是一个圆圈,所以这个方向可能与您通过查看玩家的 dx 和 dy 所期望的不同。)
这是我目前正在做的,但感觉有点不自然和不正常:
func didBegin(_ contact: SKPhysicsContact)
{
if (contact.bodyA.categoryBitMask == BodyType.ball.rawValue && contact.bodyB.categoryBitMask == BodyType.player.rawValue) && (contact.bodyA.contactTestBitMask == 25 || contact.bodyB.contactTestBitMask == 25) && bottomTouchForCollision == true
{
ball!.physicsBody!.applyImpulse(CGVector(dx: CGFloat(UserDefaults.standard.float(forKey: "BottomVelocity")) * contact.contactNormal.dx, dy: CGFloat(UserDefaults.standard.float(forKey: "BottomVelocity")) * contact.contactNormal.dy))
}
}
对球有准确和反应灵敏的冲动的最佳方法是什么。我认为完全依赖 contact.contactNormal.dy
的方向感觉不自然,因为如果玩家的圆圈在一个地方不动,那是预期的方向。几周来我一直在为这个问题苦苦挣扎,不知道如何最好地解决它。感谢代码解释,但任何帮助。
我以类似的方式问过这个问题并收到了回复:
"考虑球击中静止的木槌的情况。它会以相同的速度反射出去,并且运动的最终方向是入射角等于接触点处的反射角. 然后对于一个以速度矢量 v 移动的木槌,从所有速度中减去 v 以转换为固定木槌的情况。计算转换问题中的球速度。然后通过将 v 添加到结果来转换回来。(如果你正在计算它像那样,你不必applyImpulse,直接设置新的速度即可。)"
我无法理解如何实现这个想法,但如果有人可以提供伪代码或代码,那就太好了!
编辑:这是我在下面的帮助下得到的结果。
if (contact.bodyA.categoryBitMask == BodyType.ball.rawValue && contact.bodyB.categoryBitMask == BodyType.player.rawValue) && (contact.bodyA.contactTestBitMask == 75 || contact.bodyB.contactTestBitMask == 75) && northTouchForCollision == true
{
let vmallet = CGVector(dx: CGFloat(UserDefaults.standard.float(forKey: "NorthForceDX")), dy: CGFloat(UserDefaults.standard.float(forKey: "NorthForceDY")))
let vball = ball?.physicsBody?.velocity
let vrelativedx = vball!.dx - vmallet.dx
let vrelativedy = vball!.dy - vmallet.dy
let vrelative = CGVector(dx: vrelativedx, dy: vrelativedy)
let c = (vrelative.dx * contact.contactNormal.dx) + (vrelative.dy * contact.contactNormal.dy)
let vperpendicular = CGVector(dx: contact.contactNormal.dx * c, dy: contact.contactNormal.dy * c)
let vtangential = CGVector(dx: vrelative.dx - vperpendicular.dx, dy: vrelative.dy - vperpendicular.dy)
// vtangential is unchanged in the collision, vperpendicular reflects
let newvrelative = CGVector(dx: vtangential.dx - vperpendicular.dx, dy: vtangential.dy - vperpendicular.dy)
let newvball = CGVector(dx: newvrelative.dx + vmallet.dx, dy: newvrelative.dy + vmallet.dy)
// set ball velocity to newvball
// ball?.physicsBody?.velocity = newvball
ball!.physicsBody!.applyImpulse(newvball)
}
伪代码:
let vmallet = mallet velocity
let vball = ball velocity
let vrelative = vball - vmallet
let vperpendicular = dotProduct(vrelative, contactNormal) * contactNormal
let vtangential = vrelative - vperpendicular
// vtangential is unchanged in the collision, vperpendicular reflects
let newvrelative = vtangential - vperpendicular
let newvball = newvrelative + vmallet
// set ball velocity to newvball