【问题标题】:SKPhysicsWorld Simulate Physics in Scaled NodesSKPhysicsWorld 在缩放节点中模拟物理
【发布时间】:2014-03-12 18:20:36
【问题描述】:

我正在尝试构建一个 SpriteKit 游戏,该游戏涉及带有可以放大和缩小的物理实体的关卡。物理世界的行为不像我预期的那样,当缩放级别改变时会导致奇怪的事情发生。

具有物理实体的节点会按预期进行动画和行为。缩放级别是通过捏合手势来处理的,该手势正在调整包含所有游戏元素的单个“世界节点”的比例。这是一种方便的处理方式,因为缩放场景似乎会做一些可怕的事情,并且可以很容易地为世界节点之上的任何游戏界面元素添加一个单独的未缩放节点。

缩放工作如下:

- (void) handlePinchGesture:(UIPinchGestureRecognizer *) gesture {
    if (gesture.state == UIGestureRecognizerStateChanged) {
        [self.worldNode runAction:[SKAction scaleBy:gesture.scale duration:0.0]];
        gesture.scale = 1;
    }
}

在正常缩放级别时,一切都很好,而且在视觉上,在不同的缩放级别下一切看起来也很好。问题是当缩放改变时,物理实体继续以相同的速度在相对于其他对象的速度上移动,而不是以相同的速度移动。结果是,当缩小以查看更多场景时,一切都移动得更快。

这似乎是物理世界仅连接到场景并且不知道“世界节点”的调整比例这一事实的副作用。物理实体不应该继续在它们的相对空间中以相同的速度移动节点吗?

谁能提供任何关于 SpriteKit 为何如此行事的见解,或者如何解决这个问题?

【问题讨论】:

    标签: ios objective-c sprite-kit skphysicsbody sknode


    【解决方案1】:

    它这样做的原因是显而易见的。想象一下,你想把一个球缩小到一个更小的尺寸,它应该仍然以同样的方式移动,对吧?

    出现问题是因为您同时缩放“整个球系统”。除了正在发生的事情之外,这没有任何真正明智的结果。 SpriteKit 确实需要猜测您正在尝试做什么,并根据它为使其工作而进行的缩放多少来缩放物理速度或不使用它。

    解决方案是缩放整个场景而不是子节点。

    编辑:要缩放场景,您可以设置大小。您需要将场景的 scaleMode 设置为 SKSceneScaleModeAspectFill。

    Edit2:子场景解决方案只有在您将它们添加到专用的第二个 SKView 时才有效,我承认这有点牵强。您可能需要使用单个场景,上下缩放,相应地移动子节点并隐藏界面元素(或“反缩放它们”)。

    【讨论】:

    • 天哪。我当然没有考虑将场景添加为子节点。这可能是完美的解决方案。缩小一盒球似乎是合理的,这会导致所有球在他们的小盒子里仍然表现正常,但如果一些小球试图与大球互动,这确实会立即崩溃。
    • 似乎需要花点功夫才能让场景围绕接触点很好地缩放,但是哦,物理!在场景中设置比例不是一个有效的操作,像self.size = CGSizeMake(self.size.width / gesture.scale, self.size.height / gesture.scale); 这样的操作看起来合理吗?
    • 是的,对不起,一个场景使用大小,然后你将 scaleMode 设置为:SKSceneScaleModeAspectFill。
    • 这似乎是一个很有前途的解决方案,但实际上它似乎根本不起作用。场景的scaleMode 属性和调整大小似乎只有在场景是 UIView 的直接子级时才有效。此外,嵌套场景引入了大量与子节点相关的问题,并且由于无法定位子场景,因此平移场景也很麻烦。
    • 好吧,我不能停止摆弄这个问题。这里什么都没有。我一直在努力实现拥有一个实际物理世界和一个表示层的想法。所以你基本上有一个物理世界作用于你的场景,但你没有显示任何节点。然后你有一组不同的节点连接到第一层的节点,但是这一层你可以随意放大和缩小。这应该基本上保持一切到位。我认为这是一个更好的方法。
    【解决方案2】:

    此答案基于@TheisEgeberg 在其答案的 cmets 中建议的方法。做出这个答案是因为我认为它需要是一个答案而不是评论。如果他用这种方法更新他的答案,我会删除这个答案。将这种方法作为问题的答案将使人们省去很多麻烦。

    1.创建一个包含物理节点的 SKScene。

    2.创建一个 SKNode 来模拟 SKScene

    3.对于您创建并添加到 SKScene 的每个节点,您创建另一个模拟节点 - 但没有物理体 - 并将其添加到模拟 SKNode;

    4.在您的 SKScene 中创建一个名为 updateMimicNodes 的方法,该方法遍历所有节点并更新相应节点的位置,即模拟节点中的 zRotation。从您的更新方法中调用该方法,因此它会在每一帧中更新。

    5.随意缩放模拟节点。

    6.使用 hidden 属性隐藏具有物理体的 SKScene 节点。如果将所有节点都放在添加到 SKScene 的 SKNode 层上,则只需将该 SKNode 的 hidden 属性设置为 YES;

    为了更易于管理,我在所有节点上创建了一个“模拟”属性,并将该属性设置为模拟节点上的相应节点。然后,您可以像这样更新更新中的每个节点:

    node.mimic.position = node.position
    node.mimic.zRotation = node.zRotation
    

    我稍后可能会发布一些此方法的示例代码,但如果您按照这些步骤操作,您应该会到达应许之地。

    另外请记住,任何触摸都需要将位置转换为具有物理实体的 SKScene 坐标系。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-10-19
      • 2015-02-06
      • 1970-01-01
      • 1970-01-01
      • 2018-03-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多