3
votes

I am evaluating the iOS SpriteKit physics engine, and for a test I have created a simple scene with Xcode that contains two circle-shaped nodes:

Two nodes in SpriteKit scene

Both nodes have physics bodies of circular shape and 5 kg of mass. I am connecting both nodes with a SKPhysicsJointSpring. Here is the entire setup (in viewDidLoad()):

let path = NSBundle.mainBundle().pathForResource("MyScene", ofType: "sks")!
let scene = NSKeyedUnarchiver.unarchiveObjectWithFile(path) as! SKScene

let border = SKPhysicsBody(edgeLoopFromRect: scene.frame)
border.restitution = 0;
border.friction = 0;
scene.physicsBody = border

let player = scene.childNodeWithName("player")! // large ball
let tail1 = scene.childNodeWithName("tail1")! // smaller ball

player.physicsBody!.usesPreciseCollisionDetection = true
tail1.physicsBody!.usesPreciseCollisionDetection = true

let spring1 = SKPhysicsJointSpring.jointWithBodyA(player.physicsBody!, bodyB: tail1.physicsBody!, anchorA: player.position, anchorB: tail1.position)
spring1.damping = 1
spring1.frequency = 3
scene.physicsWorld.addJoint(spring1)

spriteKitView.presentScene(scene)

Note: The gravity is set to (0,0) in the scene editor.

When I move the bigger node (say, by capturing touches with touchesBegan() and setting the node's position to the touch position), the other follows according to spring parameters.

However, if I move the node fast enough, so that the spring forces become extreme, both nodes overlap when the spring is contracting. I am expecting them to collide with each other since their collisionBitMask is by default set to -1 (all bits set). I have enabled usesPreciseCollisionDetection but the effect is still visible.

When I add an edge loop around the scene they do collide with that edge as expected. Same with additional nodes that have a physics body (but no joints attached).

I have the impression that the presence of the spring somehow makes the engine ignore collisions between nodes that are connected with joints. Did anyone else observe this, too? Did I forget anything? Or is this working as intended?

1

1 Answers

1
votes

Attempting to answer my own question.

I found out that other joints (such as SKPhysicsJointLimit) disable collision between the joined nodes as well. My only conclusion is that all SpriteKit joints somehow consider two objects as one, where collisions are deemed undesirable. Though in my app I would prefer to have collisions enabled. Maybe I should file an enhancement at Apple developer feedback.

So far my workarounds include:

  1. Create spring behaviour by adding a SKFieldNode.springField plus a SKFieldNode.dragField as children to the sprite node. Pro: as children these fields automatically follow their parent position; Con: this spends 2 precious bits of fieldBitMask which puts a natural limit to the number of such nodes.
  2. Manually apply some spring + drag force at every frame. Pro: does not waste bits of fieldBitMask, Con: compute spring + drag forces manually.

So I tend to favor option 2.

To summarize: If you want spring behaviour between 2 nodes while maintaining collisions, implement forces manually and do not use a joint.