Here comes another little tutorial how to make a swinging hammer with Sprite Kit for your iOS game. It’s very easy to build such little objects with the given physics engine in Sprite Kit. All you need is the idea how you can use physical bodies and physical joints to realize the object you want.
Here comes the class code and some notes for a swinging hammer as you can see in this video capture.
When I start to write a class I think about the physical elements first. As you can see in this image we need only 3 elements: an anchor, a rope and the hammer.
The anchor is a physics body. The rope is a SKPhysicsJointLimit and the hammer is again a simple physics body with a huge mass value. So let’s see the code
The anchor:
1 2 3 4 5 6 7 |
SKSpriteNode * anchor = [SKSpriteNode spriteNodeWithImageNamed:@"dummypixel_transparent.png"]; anchor.position = pos; anchor.name = @"hammer_anchor"; anchor.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:1]; anchor.physicsBody.affectedByGravity = false; anchor.physicsBody.dynamic = false; [game addChild:anchor]; |
The rope:
1 2 3 4 5 6 7 8 |
SKSpriteNode * rope = [SKSpriteNode spriteNodeWithImageNamed:@"rope.png"]; rope.size = CGSizeMake(5, ropeLength); rope.zRotation = 90 / 180.0f * M_PI; rope.position = CGPointMake(anchor.position.x + startPos/2, anchor.position.y); rope.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:rope.size]; rope.physicsBody.affectedByGravity = false; rope.physicsBody.categoryBitMask = kNilOptions; [game addChild:rope]; |
The Hammer:
1 2 3 4 5 6 7 8 9 10 11 |
hammer = [SKSpriteNode spriteNodeWithImageNamed:@"hammer.png"]; hammer.name = @"hammer"; hammer.position = CGPointMake(anchor.position.x + startPos, anchor.position.y); [hammer setScale:0.1]; hammer.zRotation = 90 / 180.0f * M_PI; hammer.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:20]; hammer.physicsBody.mass = 99999999999999; hammer.physicsBody.friction = 0; hammer.physicsBody.linearDamping = 0; hammer.physicsBody.affectedByGravity = false; [game addChild:hammer]; |
I use some references and variables in this code snippets that are given from the method call of the complete class. So I can call this class in every level as often as I need it with a configurable position and rope length. Here is an example for the call of the hammer swing class:
1 |
[WWHammerSwing addHammerSwing:CGPointMake(500, 330) ropeLength:250 game:game start:1]; |
For some realistic effects I do simply some collision detections in the Sprite Kit game loop to play a sound and shake the background if the hammer smashes something:
1 2 3 4 5 6 |
if([contact.bodyA.node.name isEqualToString:@"hammer"] || [contact.bodyB.node.name isEqualToString:@"hammer"]) { [self runAction:self.stoneblowSound]; [self runAction:self.explosionSound]; [WWAnimationHelper screenQuake:self]; } |
Additionally I add this typical swoosh sound in my game loop if the hammer is moving downwards to make it more realistic:
1 2 3 4 5 6 7 8 |
if ([self childNodeWithName:@"hammer"]) { if ([self childNodeWithName:@"hammer"].physicsBody.velocity.dx >= 600) { [self.swooshSound play]; } if ([self childNodeWithName:@"hammer"].physicsBody.velocity.dx <= -600) { [self.swooshSound play]; } } |
So here is the complete hammer swing class code in objective-c for Sprite Kit in Xcode to add for an 2D iOS game. At the end of this class all physical built objects are pinned together with joints.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
// // WWHammerSwing.m // PoBo // // Created by zinne on 28.06.14. // Copyright (c) 2014 waveworks. All rights reserved. // #import "WWHammerSwing.h" @implementation WWHammerSwing static SKSpriteNode* hammer; +(void) addHammerSwing:(CGPoint)pos ropeLength:(int)ropeLength game:(SKScene *)game start:(int) start { int startPos; if (start == 0) { startPos = + ropeLength; } else { startPos = - ropeLength; } SKSpriteNode * anchor = [SKSpriteNode spriteNodeWithImageNamed:@"dummypixel_transparent.png"]; anchor.position = pos; anchor.name = @"hammer_anchor"; anchor.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:1]; anchor.physicsBody.affectedByGravity = false; anchor.physicsBody.dynamic = false; [game addChild:anchor]; SKSpriteNode * rope = [SKSpriteNode spriteNodeWithImageNamed:@"rope.png"]; rope.size = CGSizeMake(5, ropeLength); rope.zRotation = 90 / 180.0f * M_PI; rope.position = CGPointMake(anchor.position.x + startPos/2, anchor.position.y); rope.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:rope.size]; rope.physicsBody.affectedByGravity = false; rope.physicsBody.categoryBitMask = kNilOptions; [game addChild:rope]; hammer = [SKSpriteNode spriteNodeWithImageNamed:@"hammer.png"]; hammer.name = @"hammer"; hammer.position = CGPointMake(anchor.position.x + startPos, anchor.position.y); [hammer setScale:0.1]; hammer.zRotation = 90 / 180.0f * M_PI; hammer.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:20]; hammer.physicsBody.mass = 99999999999999; hammer.physicsBody.friction = 0; hammer.physicsBody.linearDamping = 0; hammer.physicsBody.affectedByGravity = false; [game addChild:hammer]; SKPhysicsJointLimit* joint = [SKPhysicsJointLimit jointWithBodyA:anchor.physicsBody bodyB:hammer.physicsBody anchorA:anchor.position anchorB:hammer.position]; [game.physicsWorld addJoint:joint]; SKPhysicsJointPin* jointPin_1 = [SKPhysicsJointPin jointWithBodyA:anchor.physicsBody bodyB:rope.physicsBody anchor:anchor.position]; [game.physicsWorld addJoint:jointPin_1]; SKPhysicsJointPin* jointPin_2 = [SKPhysicsJointPin jointWithBodyA:hammer.physicsBody bodyB:rope.physicsBody anchor:hammer.position]; jointPin_2.frictionTorque = 1; [game.physicsWorld addJoint:jointPin_2]; } @end |
Hi
Thanks for all this short bits for achieve cool physics mechanics with Sprite-Kit.
I have read your other tutorials and I have a question:
Why don’t you just instance the SKnode as a node for the anchors instead a transparent pixel png file?
Hi Juan,
there‘ s no specific reason for this. It’s kind of WIP… just to keep the possibility to replace this dummypixel also with some graphic/artwork.
Hi
Thanks for all this short bits for achieve cool physics mechanics with Sprite-Kit.
I have a question:
how you will call the ‚addHammerSwing‘ method in ‚initWithSize‘ method in your Scene?
Please replay with code in example.
Thanks in advance.
Hi Akshay,
first remember to make the method publicly available in your „WWHammerSwing.h“ like this:
+(void) addHammerSwing:(CGPoint)pos ropeLength:(int)ropeLength game:(SKScene *)game start:(int) start;
In your class with the initWithSize method you also have to import this header file like this:
#import "WWHammerSwing.h"
Then you can call the hammer method in your initWithSize like this:
-(id)initWithSize:(CGSize)size {
if (self = [super initWithSize:size]) {
[WWHammerSwing addHammerSwing:CGPointMake(500, 330) ropeLength:250 game:game start:1];
}
return self;
}
Thanks for this. Can you please share complete project of same.
Hi Sumit,
sorry I will not share the comlete project. It’s publicly available here:
Free PoBo