2

I've got a working clock with a pendulum, but the swinging arm does not scale correctly. Here's what it looks like before scaling...

enter image description here

And then, after scaling...

enter image description here

The clock face scales down, and so does the swing arm (the green line), but it looks like it scales around it's center point not the fulcrum at the center of the face. I can fix that scaling by setting the swing's anchorPoint so it scales toward one end rather than the center...

swing.anchorPoint = CGPointMake(0, 0.5);

but doing that causes the pendulum to not swing. (I think because physics forces are applied to swing's anchorPoint which, if I move it to one end, is at the pin anchor which is fixed).

How can I get the arm to scale towards the fulcrum and still allow it to swing?

Here's the code...

// in my SKScene
ClockFace *face = [ClockFace face]; // just an SKNode subclass
face.name = @"face";
face.position = CGPointMake(150, 150);
[self addChild:face];

// add the pendulum
SKSpriteNode *fulcrum = [SKSpriteNode spriteNodeWithColor:[UIColor redColor] size:CGSizeMake(5, 5)];
[face addChild:fulcrum];
fulcrum.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:fulcrum.frame.size];
fulcrum.physicsBody.dynamic = NO;

SKSpriteNode *swing = [SKSpriteNode spriteNodeWithColor:[UIColor greenColor] size:CGSizeMake(190, 2)];
[face addChild:swing];
swing.position = CGPointMake(95, 0);
swing.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:swing.frame.size];

SKPhysicsJointPin *pinJoint = [SKPhysicsJointPin jointWithBodyA:fulcrum.physicsBody bodyB:swing.physicsBody anchor:face.position];
[self.physicsWorld addJoint:pinJoint];
Fluidity
  • 3,985
  • 1
  • 13
  • 34
user1272965
  • 2,814
  • 8
  • 29
  • 49

2 Answers2

3

In Swift 3 example of this:

enter image description here

    let nodeSize = CGSize(width: 10, height: 10)
    let node = SKSpriteNode(color: .red, size: nodeSize)
    node.physicsBody = SKPhysicsBody(rectangleOf: nodeSize)
    node.physicsBody?.isDynamic = false
    self.addChild(node)

    let node2Size = CGSize(width: 60, height: 8)
    let node2 = SKSpriteNode(color: .green, size: node2Size)
    node2.position = CGPoint(x: 5, y: 0)
    node2.anchorPoint = CGPoint(x: 0.0, y: 0.5) // <- New Line
    node2.physicsBody = SKPhysicsBody(rectangleOf: node2Size)
    node2.physicsBody?.mass = 1.0
    self.addChild(node2)

    // Scale Line
    node2.run(SKAction.repeatForever(SKAction.sequence([
        SKAction.scale(to: 0.2, duration: 1.0),
        SKAction.scale(to: 1.5, duration: 0.5),
        ])))
// Anchor Point
        let a = SKPhysicsJointPin.joint(withBodyA: node.physicsBody! , bodyB: node2.physicsBody!, anchor: CGPoint(x: 0.0, y: 0.0))
            self.physicsWorld.add(a)
Maetschl
  • 1,330
  • 14
  • 23
  • I don't understand. Isn't this exactly my code plus assigning node2 anchorPoint? When I move the anchor there the joint doesn't work. Can you show me your code to add the joint? – user1272965 Jul 22 '17 at 22:32
  • Maybe also can you tell me in words what the idea is, and maybe post your project? Thanks! – user1272965 Jul 22 '17 at 22:46
  • I update the repo and answer with anchor point code. :) https://github.com/Maetschl/SpriteKitExamples – Maetschl Jul 23 '17 at 00:28
  • @Maetschl He is scaling both the face and pendulum, you may want to update your code to reflect that – Knight0fDragon Jul 23 '17 at 13:00
  • @Maetschl - my code and yours were the same with an important exception not mentioned anywhere: `node2.position = CGPoint(x: 5, y: 0)`. That little nudge x==5 off of the pin joint anchor makes it work. The nearer it gets to the anchor, the slower it swings, down to no swing at all. Did you know this? Any idea why? – user1272965 Jul 23 '17 at 15:33
  • @user1272965 Maybe your pendulum is balanced on joint point. I update the repo! adding some visual helps :) github.com/Maetschl/SpriteKitExamples recommend look documentation also: https://developer.apple.com/documentation/spritekit/skphysicsjoint – Maetschl Jul 23 '17 at 18:05
  • Thanks again @Maetschl, but the other doesn't require the little unexplained bump in the swing arm. Really appreciate the help! – user1272965 Jul 24 '17 at 02:46
1

The reason why the scaling is weird is because of how you do your anchor point. Imagine a rubber band with a thumbtack in it. The anchor point is where the thumbtack is. Now to scale. Just grab the rubber band and pull. When the thumbtack is the middle, you will find it easy to stretch both sides evenly (this is what you are doing on the y axis). When you place it on the left of the rubber band, you will only be able to scale the right side (This is what you want to be doing)

Now with PhysicsBody, you need to adjust the bodies anchor point based on the sprites anchor point. To do this you need to do some math:

let centerPoint = CGPointMake(sprite.size.width / 2 - (sprite.size.width * sprite.anchorPoint.x), sprite.size.height / 2 - (sprite.size.height * sprite.anchorPoint.y))
 sprite.physicsBody = SKPhysicsBody(rectangleOfSize: sprite.size, center: centerPoint)

Using centerPoint allows you to move where the center of your body is.

// in my SKScene
ClockFace *face = [ClockFace face]; // just an SKNode subclass
face.name = @"face";
face.position = CGPointMake(150, 150);
[self addChild:face];

// add the pendulum
SKSpriteNode *fulcrum = [SKSpriteNode spriteNodeWithColor:[UIColor redColor] size:CGSizeMake(5, 5)];
[face addChild:fulcrum];
fulcrum.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:fulcrum.frame.size];
fulcrum.physicsBody.dynamic = NO;

SKSpriteNode *swing = [SKSpriteNode spriteNodeWithColor:[UIColor greenColor] size:CGSizeMake(190, 2)];
[face addChild:swing];
swing.anchorPoint = CGPointMake(0,0.5);
CGPoint *centerPoint = CGPointMake(swing.size.width / 2 - (swing.size.width * swing.anchorPoint.x), swing.size.height / 2 - (swing.size.height * swing.anchorPoint.y));

swing.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:swing.frame.size center:centerPoint];

SKPhysicsJointPin *pinJoint = [SKPhysicsJointPin jointWithBodyA:fulcrum.physicsBody bodyB:swing.physicsBody anchor:face.position];
[self.physicsWorld addJoint:pinJoint];
Knight0fDragon
  • 16,609
  • 2
  • 23
  • 44
  • Thanks. I think I get your point (well explained) about the function of anchor. I'm still confused about why when the end of that rubber band is attached exactly to the other node, no motion occurs. See my last comment to @Maetschl (who has been very helpful with code, but less clear about what it means and how it relates to my question) – user1272965 Jul 23 '17 at 20:19
  • Did you put in my code to change the center of your physics body? – Knight0fDragon Jul 23 '17 at 22:54
  • No. I should try this (didn't read carefully enough). I'll try in a few hours and let you know. This might really be the more correct answer. Thanks – user1272965 Jul 23 '17 at 23:45
  • Thanks, this makes sense and works better because it doesn't rely on any unexplained position tweaks. (and is in objective c and uses my variable names, etc). – user1272965 Jul 24 '17 at 02:47
  • I figures the position push was to keep the arm aligned with the edge of the fulcrom. But his issue should be the same as yours, if you do `view.showsPhysics = true` you should see that the body does not correspond to the graphics – Knight0fDragon Jul 24 '17 at 12:02