使用 SceneKit 的台球游戏中的后旋效果

Posted

技术标签:

【中文标题】使用 SceneKit 的台球游戏中的后旋效果【英文标题】:Backspin effect in pool game with SceneKit 【发布时间】:2016-06-11 20:07:51 【问题描述】:

我想创建一个逼真的台球游戏并至少实现一些基本的球效果。我从头开始使用 SceneKit,此时我只是在研究适合它的技术。SceneKit 将是理想的。 我设法为侧旋和某种前旋实现了可接受的球效果。我正在努力解决的问题是后旋。我正在使用 applyForce 方法的 position 参数,但似乎仅靠它不会给我我正在寻找的结果。要么我遗漏了一些东西(我对物理的了解有限),要么 SceneKit 的物理模拟不足以满足我的需求。基本上我有一个半径为 1.5 的球体,我在 Y 分量上的位置矢量从 -1.5 变为 1.5,结果是发生碰撞时我击中的白球或球跳跃。

第一个屏幕截图显示了撞击的时刻,而后者显示了碰撞之后以及它是如何跳跃的。

两个球体是这样配置的

    let sphereGeometry = SCNSphere(radius: 1.5)
    sphere1 = SCNNode(geometry: sphereGeometry)
    sphere1.position = SCNVector3(x: -15, y: 0, z: 0)
    sphere2 = SCNNode(geometry: sphereGeometry)
    sphere2.position = SCNVector3(x: 15, y: 0, z: 0)    

给我带来这种效果的代码如下:

sphere1.physicsBody?.applyForce(SCNVector3Make(350, 0, 0), atPosition:SCNVector3Make(1.5, -0.25, 0), impulse: true)

我在该代码中试图做的是将球击打到略低于中心的位置。我如何得到 -0.25 是得到一个 10 度的角度并计算它的 sin 函数。然后我将它乘以球体半径,这样我就可以得到一个正好位于球体表面上的点。

【问题讨论】:

请缩小这个问题的范围,以便我们为您提供帮助。提供一个简洁的代码示例,也许还有几个屏幕截图。你做了什么?你看见什么了?相反,您的期望是什么? 感谢您的意见。我编辑了我的问题。 【参考方案1】:

所以我一直在阅读几篇关于池物理的论文/章节,我想我发现了一些至少证明我可以使用 SceneKit 做到这一点的东西。所以我缺少的是我。 ii. 正确的公式角速度。物理学仍然需要大量的润色,但至少它似乎得到了应用这些效果时所期望的大致轨迹。以下是代码,以防有人感兴趣:

            //Cue strength
            let strength : Float = 1000

            //Cue mass expressed in terms of ball's mass
            let cueMass : Float = self.balls[0].mass * 1.25

            //White ball
            let whiteBall = self.balls[0]

            //The ball we are trying to hit
            let targetBall = self.balls[1]

            //White ball radius
            let ballRadius = whiteBall.radius

            //This should be in the range of -R, R where R is the ball radius. It determines how much off the center we would like to hit the ball along the z-axis. Produces left/right spin
            let a : Float = 0

            //This should be in the range of -R, R where R is the ball radius. It determines how much off the center we would like to hit the ball along the y-axis. Produces top/back spin
            let b : Float = -ballRadius * 0.7

            //This is calculated based off a and b and it is the position that we will be hitting the ball along the x-axis.
            let c : Float = sqrt(ballRadius * ballRadius - a * a - b * b)

            //This is the angle of the cue expressed in degrees. Values greater than zero will produce jump shots
            let cueAngle : Float = 0

            //Cue angle in radians for math functions
            let cueAngleInRadians : Float = (cueAngle * 3.14) / 180

            let cosAngle = cos(cueAngleInRadians)
            let sinAngle = sin(cueAngleInRadians)

            //Values to calculate the magnitude to be applied given the above variables
            let m0 = a * a
            let m1 = b * b * cosAngle * cosAngle
            let m2 = c * c * sinAngle * sinAngle
            let m3 = 2 * b * c * cosAngle * sinAngle

            let w = (5 / (2 * ballRadius * ballRadius)) * (m0 + m1 + m2 + m3)

            let n = 2 * whiteBall.mass * strength

            let magnitude = n / (1 + whiteBall.mass / cueMass + w)

            //We would like to point to the target ball
            let targetVector = targetBall.position

            //Get the unit vector of our target
            var target = (targetVector - whiteBall.position).normal

            //Multiply our direction by the force's magnitude. Y-axis component reflects the angle of the cue
            target.x *= magnitude
            target.y = (magnitude / whiteBall.mass) * sinAngle
            target.z *= magnitude

            //Apply the impulse at the given position by c, b, a
            whiteBall.physicsBody?.applyForce(target, atPosition: SCNVector3Make(c, b, a), impulse: true)

            //Values to calculate angular force
            let i = ((2 / 5) * whiteBall.mass * ballRadius * ballRadius)
            let wx = a * magnitude * sinAngle
            let wy = -a * magnitude * cosAngle
            let wz = -c * magnitude * sinAngle + b * magnitude * cosAngle
            let wv = SCNVector3Make(wx, wy, wz) * (1 / i)

            //Apply a torque
            whiteBall.physicsBody?.applyTorque(SCNVector4Make(wv.x, wv.y, wv.z, 0.4), impulse: true)

请注意,a、b、c 的值应考虑目标向量的方向。

【讨论】:

您是如何制作靠垫的?我已经通过 SCNBox 完成了,但即使左右旋转也反应不佳,并且垫子不会与高速球碰撞,球直接穿过它们内部..

以上是关于使用 SceneKit 的台球游戏中的后旋效果的主要内容,如果未能解决你的问题,请参考以下文章

如何为溶解效果编写 sceneKit 着色器修改器

探索 Unity 中的后处理

SceneKit 中地形的 Splatmap

SceneKit:简单的3D游戏场景搭建

SceneKit - 在着色器修改器中访问目标颜色以进行混合

虚拟台球4出现图像性能检测报错出现virtual pool4停止工作的解决办法