简体   繁体   English

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

[英]How to make a sprite jump to a specific height with SpriteKit?

I am trying to use applyImpulse to make a sprite jump to a specific height. 我正在尝试使用applyImpulse使sprite跳转到特定高度。 In the example code below, the dynamic black circle jumps to the same height as the static red circle, but it only works with a kludge. 在下面的示例代码中,动态黑色圆圈跳转到与静态红色圆圈相同的高度,但它仅适用于kludge。

If my physics is right, the required initial vertical momentum to launch a projectile to height Y is given by mass * sqrt(2 * gravity * Y). 如果我的物理学是正确的,那么将射弹发射到高度Y所需的初始垂直动量由质量* sqrt(2 *重力* Y)给出。 Yet this formula results in the black circle moving very little. 然而,这个公式导致黑圈移动很少。

Through trial and error, I have discovered that I can make the red circle jump more or less accurately by multiplying the vertical component of the impulse vector by 12.3, as illustrated in the code below. 通过反复试验,我发现通过将脉冲矢量的垂直分量乘以12.3,我可以或多或少准确地使红色圆圈跳跃,如下面的代码所示。

This seems completely arbitrary and is driving me crazy. 这似乎是完全随意的,让我发疯。 I am obviously doing something wrong. 我显然做错了什么。 What's the right way to do this? 这样做的正确方法是什么?

Here's what I think is the relevant bit of code: 以下是我认为相关的代码:

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

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

Here's the GameScene.swift class in its entirety, should you wish to copy and paste... 如果您希望复制和粘贴,这里是完整的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)))
     }
     }
 }

Figured it out. 弄清楚了。

SpriteKit apparently has an undocumented pixel-to-"meter" ratio of 150. SpriteKit显然没有未记录的像素到“米”比率为150。

I discovered this when I realized the mass SpriteKit was automatically calculating for my circles was not 50*pi*r^2 as it should be. 我发现这一点,当我意识到质量SpriteKit自动计算我的圈子不是 50 * pi * r ^ 2应该是。 I worked backward from mass to calculate the radius SpriteKit was using, and it was 7500, which happens to be 50*150. 我从质量向后工作来计算SpriteKit正在使用的半径,它是7500,恰好是50 * 150。

And 12.3? 和12.3? It just happens to be (approximately) the square root of 150. 它恰好是(大约)150的平方根。

So to make these physics simulations work, you have to consider this ratio. 因此,要使这些物理模拟工作,您必须考虑这个比例。 I'm calling it "pixel to unit" (PTU) because it has nothing to do with meters in spite of Apple's insistence that SpriteKit uses SI units. 我称之为“像素到单位”(PTU),因为尽管Apple坚持认为SpriteKit使用SI单位,但它与米无关。 But because it's undocumented it seems possible to change, so I'm kicking off my simulation using the following line of code to determine the true PTU: 但由于它没有文档,似乎有可能改变,所以我使用以下代码行开始模拟,以确定真正的PTU:

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

This is an expensive operation, so it should only be called once. 这是一项昂贵的操作,因此只应调用一次。 I'm calling it when setting up the initial Scene. 我在设置初始场景时调用它。

My impulse calculation is now as follows: 我的冲动计算现在如下:

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

And now the black circle jumps to perfect alignment with the red circle and I can go back to sleeping at night. 现在,黑色圆圈跳跃到与红色圆圈完美对齐,我可以在晚上回去睡觉。

Instead of applyImpulse use velocity. 而不是applyImpulse使用速度。 Velocity will be more specific. 速度将更加具体。 jumpingCircle.physicsBody?.velocity = CGVectorMake(jumpingCircle.physicsBody.velocity.dx, 300.0f); Code not tested. 代码未经测试。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM