1

I'm using SKSpriteKit to make a fishing game. I have a sprite node for a hook, and for some fish (I extended the SKSpriteNode class for this). Ideally, the behavior when a fish gets caught on a hook is that the fishes mouth will move to the tip of the hook (using an action to do this) :

CGPoint hp = CGPointMake(self.hook.frame.size.width/2, 0);    
CGPoint hookPoint = [self.scene convertPoint:hp fromNode:self.hook];    
SKAction *moveAction = [SKAction moveTo:hookPoint duration:.1];

and then the fish will rotate down a bit to simulate hanging on a hook ( another action : )

SKAction * flip = [SKAction  rotateToAngle:M_PI_4 duration:.1 ];

I think run these as such :

[fish runAction:[SKAction sequence:@[moveAction, flip]]];

this works more or less ( working out kinks based on the fish's direction)

What I later want to do is create a joint between the fish and the hook so if I move the hook around and it's already caught a fish, the fish follows along.

I do this :

SKPhysicsJointFixed *joint =
            [SKPhysicsJointFixed jointWithBodyA:self.hook.physicsBody
                                          bodyB:fish.physicsBody
                                         anchor:hookPoint];

SKAction *createJoint = [SKAction runBlock:^{
    [self.physicsWorld addJoint:joint];}];

[self.scene runAction:createJoint];

If I run the code without the joint, the fish will stay on the hook and rotate. HOWEVER, once the joint is create and the action ran, the rotation action from above DOES NOT GET INVOKED (the movement to the hook does though).

I have not the slightest idea of why this happens. Anyone have any pointers?

CodeSmile
  • 64,284
  • 20
  • 132
  • 217
pikovayadama
  • 808
  • 2
  • 8
  • 26

1 Answers1

2

I say it here for reference:

Using move or rotate actions on a node with a physics body will very likely result in unexpected behavior.

SKActions are overruled by physics behavior - actions are evaluated first, then the physics world is simulated.

If you want a node to behave according to its physics body, you must move and rotate the body by applying forces, impulses or directly changing the body's velocity. You can not move or rotate a physics body through actions. Actions affect the node the same way the body affects the node, but clearly you don't want both affecting the node at the same time - one has to take precedence.

You can ensure the physics body velocities are always zero, and the physics body never experiences any collision feedback. Then you can move it with actions but except for some odd scenarios (ie temporarily deactivating the physics body to move the body back to a spawn position or something) that's probably not very useful.

CodeSmile
  • 64,284
  • 20
  • 132
  • 217
  • thank you, that helps. I'm so new to this still - how would I apply forces to rotate the physics body? Can you show an example? – pikovayadama Nov 13 '13 at 19:11
  • At its simplest you just change the velocity property of the body. Otherwise use applyForce or applyImpulse https://developer.apple.com/library/ios/documentation/SpriteKit/Reference/SKPhysicsBody_Ref/Reference/Reference.html#//apple_ref/doc/uid/TP40013032 Basic trigonometry helps. Plenty of examples on SO or on the web, I'm sure. ;) – CodeSmile Nov 13 '13 at 19:18
  • One more thing worth mentioning is that SKPhysicsJointFixed does not seem to work correctly if allowRotation is set to false (as also described in https://stackoverflow.com/questions/45174110/skphysicsjointfixed-doesnt-keep-nodes-together-while-moving-one) – Leszek Szary Nov 16 '17 at 20:23