Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SpriteKit physics bodies not colliding when connected with joints

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?

like image 356
bio Avatar asked Nov 01 '25 07:11

bio


1 Answers

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.

like image 167
bio Avatar answered Nov 03 '25 21:11

bio



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!