physicssprite-kitzoomingrevolute-joints

Joints break when zooming


I've been rehearsing Sprite Kit lately and I've come across a very strange problem. When zooming (changing the scale of) the parent node, bodies that are joined together by SKPhysicsJointPin separate from each other gradually and then joints break. Let me show you the images.

This is for the normal state: Here's the normal state

Here's when zoomed in: Zoomed in

And here's when zoomed out: Zoomed out

If you ask how I join bodies: I join the brown sticks to the blue nodes on the center of the blue nodes. Any ideas what my problem is?

EDIT: I've recently found out that joints don't break and everything works as expected when the joining bodies are not dynamic. So for example, if I use [SKPhysicsBody bodyWithEdgleLoopFromRect] instead of [SKPhysicsBody bodyWithRectangleOfSize] to create physics body for a sprite, there's no problem. But I need the bodies to be dynamic.

Here's the code that I use to attach physics to nodes. Of course it's all done dynamically. I just hard coded for brevity.

 -(void)attachPhysics{
    //fixedComponentLeft & fixedComponentRight are two SKSprites
    fixedComponentLeft.physicsBody=[SKPhysicsBody bodyWithCircleOfRadius:fixedComponentLeft.frame.size.width];
    fixedComponentRight.physicsBody=[SKPhysicsBody bodyWithCircleOfRadius:fixedComponentLeft.size.width];
    beam1.physicsBody=[SKPhysicsBody bodyWithRectangleOfSize:beam1.size];
    joiningBody.physicsBody=[SKPhysicsBody bodyWithCircleOfRadius:joiningBody1.size.width];
    [self.scene.physicsWorld addJoint:[SKPhysicsJointPin jointWithBodyA:fixedComponentLeft.physicsBody bodyB:beam1.physicsBody anchor:fixedComponentLeft.position]];
    [self.scene.physicsWorld addJoint:[SKPhysicsJointPin  jointWithBodyA:joiningBody.physicsBody bodyB:beam1.physicsBody anchor:beam1.endPoint]];
    beam2.physicsBody=[SKPhysicsBody bodyWithRectangleOfSize:beam2.size];
    [self.scene.physicsWorld addJoint:[SKPhysicsJointPin  jointWithBodyA:joiningBody.physicsBody bodyB:beam2.physicsBody anchor:beam2.position]];
    [self.scene.physicsWorld addJoint:[SKPhysicsJointPin jointWithBodyA:fixedComponentRight.physicsBody bodyB:beam2.physicsBody anchor:beam2.endPoint]];
 }

On the above code, beam1 and beam2 are instances of subclass of SKSpriteNode. By default the anchor point is (0,0.5) and I've added a property called endPoint which serves as the rightmost edge point on the sprite.


Solution

  • In fact this is not an answer but I thought I'd not use the comment area for this, as the issue is big enough to not accommodate there. I should have guessed that the problem was caused by the fact that the node where the elements are drawn and the physics world their bodies are added to have different coordinate systems. It's because physics world belong to the scene and this means there's typically only one physics world no matter how many child nodes are added to the scene, all the bodies attached to different nodes on different child nodes share the same world. I don't know whether it's good or not. So here are the things we can try:

    1. Scale the scene itself instead of the child nodes: When I tried it, not surprisingly I had a very big problem. As scene is typically the root node for all the nodes in a game, this means everything will be scaled up or down accordingly. This includes the control hud too. So, not a good idea

    2. You can try to subclass SKNode so that it implements its own SKPhysicsWrold instance and add everything to that world: Unfortunately, for some reasons Apple made it impossible to have your own physics world. Yes, you can add your joints to any world you want. But joints need bodies to share the same world. From pure, unwrapped Box2D I remember bodies also needed adding to a physics world. So I assume, apple has made this automatic, when you set the physics body, it gets added to the scene.physicsWorld. And if you try to add joints to a custom created physics world, you're going to get a Box2D error stating that joint capacity is less than the joint count. :))

    3. The only realistic way seems to be to rebuild the physics bodies and joints. But this is a real pain and I have not been successful with it either. Besides a potential performance impact, this approach needs a very accurate order of recreation of bodies and joints, setting their previous velocities and etc.

      So, having searched the net for 20+ days and not found a real working solution I can say that this is a real problem that I think Apple needs to consider revisiting, or at least offer good solutions for.