首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用SKNode实现定速绕点轨道

用SKNode实现定速绕点轨道
EN

Stack Overflow用户
提问于 2015-02-28 21:10:13
回答 1查看 1.5K关注 0票数 6

我的目标是有一个恒速的secondBody‘轨道’firstBody (在这种情况下是500)。

基于Constant movement in SpriteKit,我实现了以下内容:

代码语言:javascript
复制
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 on SKPhysicsWorldfriction linearDamping & angularDamping on SKPhysicsBodyfrictionTorque on SKPhysicsJoint

那我做错什么了?在-update中,如何在不做可怕的计算的情况下保持二节点的速度恒定

而且-我知道我可以添加一个SKAction来遵循循环路径,但在这种情况下这不是一个合理的解决方案。

如果我遗漏了一些简单的东西,你还能建议删除我设置的‘0’和‘false’中的哪一个。

谢谢

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2015-03-04 01:47:27

在处理物理引擎时,减速行为通常是可以预料到的。它们并不完美,特别是在更复杂的情况下,比如约束。你不应该依赖雪碧套件提供完美的连续运动模拟,因为我们不知道物理引擎在引擎罩下做什么,有太多的因素涉及到。

在你需要连续运动的情况下(特别是像恒定向心运动),最好是自己计算和保存这些值。在您的update方法中,对于这样的行为,根本没有转义的编写计算。

因此,我写了一个快速的例子项目,计算必要的速度所需的轨道,一个特定的点。您只需指定一个周期、轨道位置和轨道半径。注意,因为我正在计算一切,所以不需要任何SKJoints,因此这个实现也更加轻量级。我强烈建议你这样做你的轨道,因为它让你完全控制你想让你的节点彼此围绕轨道运行(即你可以有节点轨道移动的节点,你可以有椭圆形的轨道路径,你可以在游戏的关键时刻调整轨道,等等)。

代码语言:javascript
复制
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。请注意,因为它是完全动态的,我们实际上可以移动向心点,因为它在轨道上运行。

然而,如果您确实出于某种原因想使用当前的SKJoints 实现,那么我有另一个解决方案,只需不断更新节点的线性速度,这样它就不会慢下来。

代码语言:javascript
复制
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))
        }
    }

不管您选择哪种解决方案(我再次强烈推荐第一种解决方案!),您可以选择在一段时间内应用速度,而不是立即应用速度来获得更实际的效果。我在回答here时更多地谈到了这一点

希望我已经为你提供了足够的信息来解决你的问题。如果你有任何问题,请告诉我。祝你的比赛好运!

票数 8
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/28786940

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档