如何使用 SpriteKit 使精灵跳到特定高度?

Posted

技术标签:

【中文标题】如何使用 SpriteKit 使精灵跳到特定高度?【英文标题】:How to make a sprite jump to a specific height with SpriteKit? 【发布时间】:2015-04-13 02:51:20 【问题描述】:

我正在尝试使用 applyImpulse 使精灵跳转到特定高度。在下面的示例代码中,动态黑圈跳到与静态红圈相同的高度,但它只适用于 kludge。

如果我的物理学是正确的,将弹丸发射到高度 Y 所需的初始垂直动量由质量 * sqrt(2 * 重力 * Y) 给出。然而,这个公式导致黑色圆圈移动很小。

通过反复试验,我发现我可以通过将脉冲向量的垂直分量乘以 12.3 或多或少准确地使红色圆圈跳跃,如下面的代码所示。

这似乎完全是武断的,让我发疯。我显然做错了什么。这样做的正确方法是什么?

以下是我认为相关的代码:

let dy = mass * sqrt( 
    2 * -self.physicsWorld.gravity.dy 
    * (fixedCircle.position.y-jumpingCircle.position.y)) 
    * 12.3

jumpingCircle.physicsBody?.applyImpulse(CGVectorMake(0, CGFloat(dy)))

这里是完整的 GameScene.swift 类,如果您想复制和粘贴...

import SpriteKit

class GameScene: SKScene 

var jumpingCircle = SKShapeNode()
var fixedCircle = SKShapeNode()

override func didMoveToView(view: SKView) 

    self.scaleMode = .AspectFit

    // Create an exterior physical boundary
    self.physicsBody = SKPhysicsBody(edgeLoopFromRect:self.frame)
    self.physicsWorld.gravity = CGVectorMake(0, -5);


    // Create the jumping circle
    jumpingCircle = SKShapeNode(circleOfRadius: 50)
    jumpingCircle.position = CGPoint(x: 100,y: 0)
    jumpingCircle.strokeColor = .blackColor()
    jumpingCircle.physicsBody = SKPhysicsBody(circleOfRadius: 50)
    jumpingCircle.physicsBody?.linearDamping = 0.0
    self.addChild(jumpingCircle)


    // Create the fixed circle
    fixedCircle = SKShapeNode(circleOfRadius: 50)
    fixedCircle.position = CGPoint(x: 100,y: 384)
    fixedCircle.strokeColor = .redColor()
    self.addChild(fixedCircle)



override func touchesEnded(touches: Set<NSObject>, withEvent event: UIEvent) 

    // to reach certain height, initial y velocity should by sqrt(2 * gravity * Y)
    // momentum required to reach this velocity is mass * velocity
    // therefore, vertical impulse should be given by mass * sqrt(2 * gravity * Y)

    if let mass = jumpingCircle.physicsBody?.mass
        // calculate vertical impulse

        // this formula "should work" but does not
        // let dy = mass * sqrt(2 * -self.physicsWorld.gravity.dy * (fixedCircle.position.y-jumpingCircle.position.y))

        // this formula "works", but has the arbitrary multiplier
        let dy = mass * sqrt(2 * -self.physicsWorld.gravity.dy * (fixedCircle.position.y-jumpingCircle.position.y)) * 12.3

        // apply the Impulse
        jumpingCircle.physicsBody?.applyImpulse(CGVectorMake(0, CGFloat(dy)))
     
     
 

【问题讨论】:

你的方程在我看来没问题。脉冲是质量 * 速度的变化。由于您希望从零变为速度 (v),因此只要您仅使用 y 轴,您的 Impulse 将是 i = (m * sqrt(2(9.81)(y2-y1)))。编辑:不能在平方根内使用负数。 @Owatch:重力矢量本身是负的,所以在 dy 公式中 sqrt 是正的。我很高兴等式看起来没问题。但它仍然不起作用。红色圆圈跳了一点点。 你在使用 SpriteKit 的内置重力吗?编辑:好的,我明白了 是的,在代码示例的第 6 行左右:self.physicsWorld.gravity = CGVectorMake(0, -5)。 为什么重力是-5,尽管我想这应该没关系,因为你继续使用这个常数。即使你不小心在某个地方使用了 -9.81,它也会让它变得太高。 (或者相反,如果你让对象使用 -5 并且真实重力为 -9.81,则太低了) 【参考方案1】:

想通了。

SpriteKit 显然有一个未记录的像素与“米”比为 150。

当我意识到 SpriteKit 自动为我的圈子计算的质量不是应该是 50*pi*r^2 时,我发现了这一点。我从质量向后计算 SpriteKit 使用的半径,它是 7500,恰好是 50*150。

还有 12.3?它恰好是(大约)150 的平方根。

因此,要使这些物理模拟发挥作用,您必须考虑这个比率。我将其称为“像素到单位”(PTU),因为尽管 Apple 坚持 SpriteKit 使用 SI 单位,但它与米无关。但是因为它没有记录,所以似乎可以改变,所以我开始使用以下代码行来确定真正的 PTU:

let ptu = 1.0 / sqrt(SKPhysicsBody(rectangleOfSize: CGSize(width:1,height:1)).mass)

这是一个昂贵的操作,所以它应该只被调用一次。我在设置初始场景时调用它。

我现在的冲动计算如下:

let dy = mass * sqrt(2 
    * -self.physicsWorld.gravity.dy 
    * (fixedCircle.position.y-jumpingCircle.position.y 
    * ptu))

现在黑色圆圈跳到与红色圆圈完美对齐,我可以回去睡觉了。

【讨论】:

是 150 像素还是点?我需要一个非视网膜常数的视网膜,谢谢。 这太神奇了!!谢谢!!!!我敢肯定,这需要做很多工作。无论最新版本是什么,这里都是 ptu: let ptu = 1.0 / sqrt(SKPhysicsBody(rectangleOf:CGSize(width: 1.0, height: 1.0)).mass) 我们如何为水平移动做到这一点?我发现在较小的屏幕上,玩家以相同的速度移动得更快。然而水平重力为零,使这个计算无用。 这个等式中的括号准确吗?仅在 jumpingCircle 位置而不是两者的差异上乘以 ptu 似乎很奇怪。【参考方案2】:

使用速度而不是 applyImpulse。速度会更具体。 jumpingCircle.physicsBody?.velocity = CGVectorMake(jumpingCircle.physicsBody.velocity.dx, 300.0f); 代码未测试。

【讨论】:

谢谢,但它不能以正确的方式解决问题。 applyForce() 将“推动”圆圈向上,加速它,因为力在一段时间内是恒定的。我需要模拟重力垂直跳跃。这正是 applyImpulse 应该做的事情(事实上,确实如此——只是用这个奇怪的组合让它正常工作。)

以上是关于如何使用 SpriteKit 使精灵跳到特定高度?的主要内容,如果未能解决你的问题,请参考以下文章

iOS Swift SpriteKit:如何使子精灵节点的位置和动作与其父精灵节点相同?

Gamecenter init/authentication 使 SpriteKit 的精灵运动滞后

在 SpriteKit 中,如何制作我的英雄精灵的裁剪(带有透明段)图像?

使 spritekit 中的 SKLabelNode 出现在所有其他精灵之上

Swift - SpriteKit:如果添加不同的“addchild”父母,使精灵相互反应

SpriteKit - 如何使用“挡板”使奖品轮减速?