首页 > 解决方案 > 在 Swift 游戏中处理圆-圆碰撞的最佳方法是什么?

问题描述

我正在制作一个类似于 SpriteKit 中的 Air Hockey 的 Swift 游戏。

当冰球被球员的木槌击中时,我试图将准确/预期的“脉冲”应用于冰球。

我可以访问玩家的速度。我还可以通过使用在两个圆圈之间进行准确的碰撞检测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 添加到结果中来转换回来。(如果你是这样计算的,你不不必应用Impulse,直接设置新速度即可。)"

我无法理解如何实现这个想法,但如果有人可以帮助提供伪代码或代码,那就太好了!

编辑:这是我在下面的帮助下的方法。

        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)
        }

标签: swiftxcodesprite-kitgame-physicscollision

解决方案


伪代码:

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

推荐阅读