当前位置: 首页 > 面试题库 >

用SKNode绕点恒速运行

邬博涉
2023-03-14
问题内容

我的目标是使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的速度正在放缓。你会发现,我设置各式各样的东西像gravitySKPhysicsWorldfriction
linearDampingangularDampingSKPhysicsBodyfrictionTorqueSKPhysicsJoint

那么,我在做什么错呢?以及如何在不进行可怕的计算的情况下保持secondNode的速度恒定-update

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

如果我缺少一些简单的东西,也可以建议删除我设置的“ 0”和“ false”中的哪一个。

谢谢


问题答案:

当与物理引擎打交道时,通常会放慢行为。它们并不完美,尤其是在约束等更复杂的场景中。您不应该依赖Sprite
Kit提供完美的连续运动仿真,因为我们不知道物理引擎在引擎盖下做什么。涉及的因素太多。

在需要连续运动的情况下(尤其是恒定的向心运动),最好总是自己计算并保存这些值。对于这种行为,在update方法中根本没有逃脱编写计算的麻烦。

因此,我写了一个快速的示例项目,计算出绕特定点运行所需的必要速度。您只需指定周期,轨道位置和轨道半径。请注意,由于我正在计算所有内容,因此不需要任何内容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图像。注意,因为它是完全动态的,所以实际上我们可以在向心点旋转时移动它。

enter image description here

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!



 类似资料:
  • 我正在尝试使用LibGDX CatmullRomSpline在路径上实现恒定速度,但在使其工作时遇到了问题。我曾多次尝试研究这个话题,包括阅读LibGDX维基,但他们对实现恒定速度的解释没有真正意义,我无法让他们的方法发挥作用。https://github.com/libgdx/libgdx/wiki/Path-interface- 在我的例子中,我有几个与球的速度一致的视觉辅助工具,屏幕底部的条

  • 问题内容: 我已经在这个问题上进行了很多搜索,但是我找不到真正合适的答案。 我需要围绕给定点(例如0,0,0)旋转圆柱体,但是默认情况下会给出圆柱体的枢轴。我该如何改变? 为了更好地说明我想做什么,我将显示3张图像。 imageshack.us/photo/my-images/259/aintgood.jpg imageshack.us/photo/my-images/840/whatineed.

  • 问题内容: 我试图在这个问题中创建一个类似于“奖杯轮”的可旋转节点。到目前为止,我具有甩尾功能,可以使用效果很好的UIPanGestureRecognizer在物理物体上添加角度脉冲。我也可以通过触摸停止旋转。 现在,我试图通过拖动或滑动手势来微调方向盘,这样,如果玩家对最终的效果不满意,就可以手动旋转/拖动/旋转它所喜欢的旋转方式。 目前,我将触摸的位置保存在touchesBegan中,并尝试在

  • 问题内容: 我有一个带有多个子SKSpriteNode的SKNode。一个简化的例子: 我想对所有这些孩子采取行动。当我在上执行操作时,没有任何效果。 我不能在父项上使用,因为它的许多子项已经具有我正在使用的名称。 有没有一种方法可以遍历的所有子项,以便对所有子项执行单个操作? 问题答案: 您可以简单地列举: 如有必要,请检查每个孩子是否确实是: 从 Swift 2(Xcode 7)开始, 可以将

  • 下面是java中的一个代码段,用于将坐标为a(10,10),B(20,10),C(20,20),D(10,20)的顶点围绕正方形的中心点旋转一个角度。正方形的边是10分。旋转角度为90度。理想情况下,旋转后A必须变成B,B必须变成C,C必须变成D,D必须变成A。 所取得的结果是不正确的 > 点A(10,10)旋转到(20,10)---正确 点B(20,10)旋转到(30,10)----不正确 nu

  • 我正在使用OpenCV和Python在图像中查找圆。我能够使用OpenCV教程中的Hough圆变换代码找到圆。我想在圆心周围裁剪一个矩形。我没有能够得到正确的裁剪功能,并尝试了多种裁剪组合,要么得到了一个错误或图像的不正确部分。有人能说明我应该如何输入裁剪坐标吗?这就是我一直遇到的错误: 错误:(-215)大小。宽度 谢谢!