如何使用 SpriteKit 使精灵跳到特定高度?
How to make a sprite jump to a specific height with SpriteKit?
我正在尝试使用 applyImpulse 使精灵跳到特定高度。在下面的示例代码中,动态黑色圆圈跳到与静态红色圆圈相同的高度,但它只适用于一个kludge。
如果我的物理学是正确的,将弹丸发射到高度 Y 所需的初始垂直动量由质量 * 平方根(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 class 的完整内容,如果您想复制和粘贴...
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)))
}
}
}
不要使用 applyImpulse,而是使用 velocity。速度将更加具体。
jumpingCircle.physicsBody?.velocity = CGVectorMake(jumpingCircle.physicsBody.velocity.dx, 300.0f);
代码未测试。
想通了。
SpriteKit 显然有一个未记录的像素与 "meter" 比率 150。
当我意识到 SpriteKit 自动为我的圈子计算的质量 而不是 50*pi*r^2 时,我发现了这一点。我从质量向后计算 SpriteKit 使用的半径,结果是 7500,恰好是 50*150。
还有 12.3?它恰好是(大约)150 的平方根。
所以要让这些物理模拟起作用,你必须考虑这个比例。我称它为 "pixel to unit" (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))
现在黑色圆圈跳到与红色圆圈完美对齐,我晚上可以回去睡觉了。
我正在尝试使用 applyImpulse 使精灵跳到特定高度。在下面的示例代码中,动态黑色圆圈跳到与静态红色圆圈相同的高度,但它只适用于一个kludge。
如果我的物理学是正确的,将弹丸发射到高度 Y 所需的初始垂直动量由质量 * 平方根(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 class 的完整内容,如果您想复制和粘贴...
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)))
}
}
}
不要使用 applyImpulse,而是使用 velocity。速度将更加具体。
jumpingCircle.physicsBody?.velocity = CGVectorMake(jumpingCircle.physicsBody.velocity.dx, 300.0f);
代码未测试。
想通了。
SpriteKit 显然有一个未记录的像素与 "meter" 比率 150。
当我意识到 SpriteKit 自动为我的圈子计算的质量 而不是 50*pi*r^2 时,我发现了这一点。我从质量向后计算 SpriteKit 使用的半径,结果是 7500,恰好是 50*150。
还有 12.3?它恰好是(大约)150 的平方根。
所以要让这些物理模拟起作用,你必须考虑这个比例。我称它为 "pixel to unit" (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))
现在黑色圆圈跳到与红色圆圈完美对齐,我晚上可以回去睡觉了。