我的目标是使firstBody以恒定的速度(在本例中为500)处于“轨道” firstBody。
基于SpriteKit中的恒定运动,我实现了以下内容:
override func didMoveToView(view: SKView) { physicsWorld.gravity = CGVector(dx: 0, dy: 0) let firstNode = SKShapeNode(circleOfRadius: 10) addChild(firstNode) firstNode.position = CGPointMake(CGRectGetWidth(frame) / 2.0, CGRectGetHeight(frame) / 2.0) let firstPhysicsBody = SKPhysicsBody(circleOfRadius: 10) firstPhysicsBody.dynamic = false firstNode.physicsBody = firstPhysicsBody let secondNode = SKShapeNode(circleOfRadius: 10) addChild(secondNode) secondNode.position = CGPointMake(CGRectGetWidth(frame) / 2.0 + 40, CGRectGetHeight(frame) / 2.0 + 40) let secondPhysicsBody = SKPhysicsBody(circleOfRadius: 10) secondPhysicsBody.friction = 0 secondPhysicsBody.linearDamping = 0 secondPhysicsBody.angularDamping = 0 secondPhysicsBody.affectedByGravity = false secondNode.physicsBody = secondPhysicsBody let joint = SKPhysicsJointPin.jointWithBodyA(firstPhysicsBody, bodyB: secondPhysicsBody, anchor: firstNode.position) joint.frictionTorque = 0 physicsWorld.addJoint(joint) secondPhysicsBody.velocity = CGVector(dx: 0, dy: 500) }
我遇到的问题是,随着时间的流逝,secondNode的速度正在放缓。你会发现,我设置各式各样的东西像gravity上SKPhysicsWorld,friction linearDamping与angularDamping上SKPhysicsBody和frictionTorque上SKPhysicsJoint。
gravity
SKPhysicsWorld
friction
linearDamping
angularDamping
SKPhysicsBody
frictionTorque
SKPhysicsJoint
那么,我在做什么错呢?以及如何在不进行可怕的计算的情况下保持secondNode的速度恒定-update?
-update
另外-我知道我可以添加SKAction来遵循循环路径,但是在这种情况下,这不是一个合理的解决方案。
如果我缺少一些简单的东西,也可以建议删除我设置的“ 0”和“ false”中的哪一个。
谢谢
当与物理引擎打交道时,通常会放慢行为。它们并不完美,尤其是在约束等更复杂的场景中。您不应该依赖Sprite Kit提供完美的连续运动仿真,因为我们不知道物理引擎在引擎盖下做什么。涉及的因素太多。
在需要连续运动的情况下(尤其是恒定的向心运动),最好总是自己计算并保存这些值。对于这种行为,在update方法中根本没有逃脱编写计算的麻烦。
因此,我写了一个快速的示例项目,计算出绕特定点运行所需的必要速度。您只需指定周期,轨道位置和轨道半径。请注意,由于我正在计算所有内容,因此不需要任何内容SKJoints,因此使此实现也更加轻巧。我强烈建议您以这种方式进行轨道运行,因为它可以让您完全控制节点彼此之间的运行方式(例如,可以让节点轨道移动的节点,可以具有椭圆形的轨道,可以在关键时刻调整轨道游戏中的瞬间等)
SKJoints
import SpriteKit class GameScene: SKScene { var node1: SKShapeNode! var node2: SKShapeNode! var node2AngularDistance: CGFloat = 0 override func didMoveToView(view: SKView) { physicsWorld.gravity = CGVector(dx: 0, dy: 0) node1 = SKShapeNode(circleOfRadius: 10) node1.position = CGPoint(x: self.size.width/2.0, y: self.size.height/2.0) node1.physicsBody = SKPhysicsBody(circleOfRadius: 10) node2 = SKShapeNode(circleOfRadius: 10) node2.position = CGPoint(x: self.size.width/2.0+50, y: self.size.height/2.0) node2.physicsBody = SKPhysicsBody(circleOfRadius: 10) self.addChild(node1) self.addChild(node2) } override func update(currentTime: NSTimeInterval) { let dt: CGFloat = 1.0/60.0 //Delta Time let period: CGFloat = 3 //Number of seconds it takes to complete 1 orbit. let orbitPosition = node1.position //Point to orbit. let orbitRadius = CGPoint(x: 50, y: 50) //Radius of orbit. let normal = CGVector(dx:orbitPosition.x + CGFloat(cos(self.node2AngularDistance))*orbitRadius.x ,dy:orbitPosition.y + CGFloat(sin(self.node2AngularDistance))*orbitRadius.y); self.node2AngularDistance += (CGFloat(M_PI)*2.0)/period*dt; if (fabs(self.node2AngularDistance)>CGFloat(M_PI)*2) { self.node2AngularDistance = 0 } node2.physicsBody!.velocity = CGVector(dx:(normal.dx-node2.position.x)/dt ,dy:(normal.dy-node2.position.y)/dt); } override func touchesMoved(touches: Set<NSObject>, withEvent event: UIEvent) { node1.position = (touches.first! as! UITouch).locationInNode(self) } }
以下是显示向心运动的gif图像。注意,因为它是完全动态的,所以实际上我们可以在向心点旋转时移动它。
If however you really want to use your currentSKJoints implementation for some reason then I have another solution for you. Simply keep updating your node’s linear velocity so that it never slows down.
override func update(currentTime: NSTimeInterval) { let magnitude = sqrt(secondNode.physicsBody!.velocity.dx*secondNode.physicsBody!.velocity.dx+secondNode.physicsBody!.velocity.dy*secondNode.physicsBody!.velocity.dy) let angle = Float(atan2(secondNode.physicsBody!.velocity.dy, secondNode.physicsBody!.velocity.dx)) if magnitude < 500 { secondNode.physicsBody!.velocity = CGVector(dx: CGFloat(cosf(angle)*500), dy: CGFloat(sinf(angle)*500)) } }
Regardless of the solution you pick (and once again I highly recommend the first solution!), you can choose to apply the velocity over time rather than instantaneously for a more realistic effect. I talk more about this in my answer here
Hopefully I have provided you with enough information to resolve your issue. Let me know if you have any questions. And best of luck with your game!