【问题标题】:Best way to handle circle-circle collisions in a Swift game?在 Swift 游戏中处理圆-圆碰撞的最佳方法是什么?
【发布时间】:2021-01-07 21:48:12
【问题描述】:

我正在用 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)
        }

【问题讨论】:

    标签: swift xcode sprite-kit game-physics collision


    【解决方案1】:

    伪代码:

    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
    

    【讨论】:

    • 非常感谢您帮助我解决这个问题,这很有意义!我遇到的唯一问题是您在哪里调用 dotProduct 伪函数。我正在尝试这样实现:let vperpendicular = ((vrelative.dx * contact.contactNormal.dx) + (vrelative.dy * contact.contactNormal.dy)) * contact.contactNormal。我收到一个错误,因为我试图将 CGVector 乘以 CGFloat。这是做 dotProduct 的正确方法吗?
    • 缩放必须按组件进行。 let c = (vrelative.dx * contact.contactNormal.dx) + (vrelative.dy * contact.contactNormal.dy)。然后let vperpendicular = CGVector(x: contact.contactNormal.x * c, y: contact.contactNormal.y * c)。或者为常见的向量操作添加一些辅助函数,如点积、标量*向量、向量加/减等。
    • 我刚刚用我目前拥有的代码更新了我上面的帖子,但我觉得这可能是我的播放器类内部的一个问题(只是预感,可能是错误的)。很抱歉给您带来的所有麻烦!
    • 当球速 = 0 时完美运行。当球在移动并且槌击球时,它会变得非常不稳定和故障/不可预测。但是在 0 速度下,球的移动非常完美,这绝对是我使用过的 0 时预期冲量的最佳方法。我不确定我是否在某个地方犯了错误,我猜这个问题以某种方式直接与球速度有关。
    • 我认为刚刚修好了 :) 谢谢!我尝试使用 CGVector(0,0) 来计算球速,而不是采用实际的球速,现在它似乎可以工作了。不完全理解为什么。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-06
    • 2012-08-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多