different reaction to collision on node using sprite kit - ios

I have rectangle shape paddle node, my question is - is it possible to "cut" node in half so when, for example ball, hit right side of node ball will go back with bigger angle, that it came, and same thing on other side. Im bad with words so, here are image of what I want to do :
For paddle node i use this code:
paddle = [[SKSpriteNode alloc] initWithImageNamed: #"board.png"];
paddle.name = paddleCategoryName;
paddle.position = CGPointMake(self.frame.origin.x + 50, CGRectGetMidY(self.frame));
[self addChild:paddle];
paddle.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:paddle.frame.size];
paddle.physicsBody.restitution = 0.1f;
paddle.physicsBody.friction = 0.4f;
paddle.physicsBody.dynamic = NO;
and for ball :
ball = [SKSpriteNode spriteNodeWithImageNamed: #"ball.png"];
[self addChild:ball];
ball.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:ball.size.width];
ball.physicsBody.friction = 0.0f;
ball.physicsBody.restitution = 1.0f;
ball.physicsBody.linearDamping = 0.0f;
ball.physicsBody.allowsRotation = NO;

Related

Add sprite to other sprite position

I have two body
SKShapeNode *hero = [SKShapeNode shapeNodeWithCircleOfRadius:HERO_SIZE];
hero.lineWidth = 1;
hero.fillColor = [SKColor orangeColor];
hero.name = #"Hero";
hero.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:HERO_SIZE];
hero.physicsBody.categoryBitMask = hero;
hero.physicsBody.collisionBitMask = friendlyCategory | enemyCategory;
hero.physicsBody.contactTestBitMask = friendlyCategory | enemyCategory;
hero.position = [self getStartPosition];
SKShapeNode *circle = [SKShapeNode shapeNodeWithCircleOfRadius:BALL_SIZE];
circle.position = [self randomPossition];
circle.lineWidth = 2;
circle.strokeColor = [SKColor blueColor];
circle.fillColor = color;
circle.name = #"Circle";
circle.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:BALL_SIZE];
circle.physicsBody.categoryBitMask = friendlyCategory;
circle.physicsBody.collisionBitMask = hero;
circle.physicsBody.contactTestBitMask = hero;
then,
- (void)didEndContact:(SKPhysicsContact *)contact
{
uint32_t collision = (contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask);
if (collision == (friendlyCategory | hero ))
{
SKShapeNode* node = (SKShapeNode*)contact.bodyA.node;
if ([node.name isEqualToString:#"Hero"])
{
self.activeFriendlyBall = (SKShapeNode*)contact.bodyB.node;
}
else
{
self.activeFriendlyBall = (SKShapeNode*)contact.bodyA.node;
}
self.hero.position = self.activeFriendlyBall.position;
}
}
Hero must be added above activeFriendlyBall, for him center position. But it added near him. I think it because physic body added. But I need to use physic body for other logic.
http://cl.ly/image/0g1S0d3h1h0w
must be like, how in top screen.
I find solution.
self.heroBall.physicsBody.velocity = CGVectorMake(0, 0);
[self.heroBall runAction: [SKAction moveTo:self.activeFriendlyBall.position duration:0.0]];
I believe it is because you have collision detection enabled for both, which means they can't be put on top of one another. If you are just trying to determine if one sprite comes into contact with another all you need is the contact detection. Removing either hero or friendlyball from the collision detection bit mask will allow them to be placed on top of each other/go through each other etc.
If you don't care about collisions at all for one of them (the sprite doesn't 'bounce' off anything) I'd recommend just setting collision detection to 0 for that sprite.
Best

iOS - SpriteKit : ApplyImpulse not working on SKSpriteNode

I'm kind of new with SpriteKit and I'm having some troubles with the physics, I've tried many things to make a SKSpriteNode move with a force or an impulse but it never moves, only gravity affects it when i set it.
-(id)initWithSize:(CGSize)size {
if (self = [super initWithSize:size]) {
self.anchorPoint = CGPointMake(0.5, 0.5);
myWorld = [SKNode node];
[self addChild:myWorld];
SKSpriteNode* map = [SKSpriteNode spriteNodeWithImageNamed:#"grass"];
[myWorld addChild:map];
self.physicsBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:map.frame];
self.physicsBody.friction = 0.0f;
self.physicsBody.categoryBitMask = 2;
self.physicsWorld.gravity = CGVectorMake(0.0, 0.0);
self.physicsWorld.contactDelegate = self;
pointOfView = [SKSpriteNode spriteNodeWithColor:[UIColor colorWithWhite:1 alpha:0.2] size:CGSizeMake(300, 548)];
[myWorld addChild:pointOfView];
pointOfView.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:pointOfView.frame.size];
pointOfView.physicsBody.friction = 0.0f;
pointOfView.physicsBody.restitution = 1.0f;
pointOfView.physicsBody.linearDamping = 0.0f;
pointOfView.physicsBody.allowsRotation = NO;
pointOfView.physicsBody.collisionBitMask = 2;
pointOfView.physicsBody.categoryBitMask = 3;
[pointOfView.physicsBody applyImpulse:CGVectorMake(10.0f, -10.0f)];
}
return self;
}
Here is most of my code in my main scene, there's nothing else except some empty methods like update or touchesBegan.. Am I missing something ? I've tried so many things, i'm starting to lose it haha
Thanks very much for any help !
It's a bit late, but the answer is here: Not able to apply impulse to SKSpriteNode physics body
The problem is that you've created a physics body with bodyWithEdgeLoopFromRect; this creates a static physics body which won't respond to applyImpulse. You need to add the physics body using bodyWithRectangleOfSize: instead.
pointOfView.physicsBody.dynamic = YES;
The dynamic property decides if a sprite should be affected by physics forces.
you have written wrong code your pointOfView not affected by gravity you are just applying a small impusle on it.
change this line self.physicsWorld.gravity = CGVectorMake(0.0, 0.0) to self.physicsWorld.gravity = CGVectorMake(0.0, -9.8); if u looking for negative gravity towards up direction and CGVectorMake(0.0, 9.8) if you looking for positive gravity towards downwards. and try to apply impulse after a interval [pointOfView.physicsBody applyImpulse:CGVectorMake(10.0f, -10.0f)];

How can I apply physics to a SKShapeNode in Sprite Kit?

In the following example, there are three things on the screen:
ball (a SKShapeNode)
spriteContainer (a SKSpriteNode that contains ball2, a SKShapeNode)
box (a SKSpriteNode)
Why does ball fall out of view? Does a SKShapeNode need to be inside a SKSpriteNode to have physics properly applied to it?
-(id)initWithSize:(CGSize)size {
if (self = [super initWithSize:size]) {
SKColor * warmRed = [SKColor colorWithRed:0.99 green:0.41 blue:0.25 alpha:1.0];
self.physicsBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:self.frame];
self.backgroundColor = warmRed;
//falls out of view
SKShapeNode * ball = [[SKShapeNode alloc] init];
CGMutablePathRef ballPath = CGPathCreateMutable();
CGPathAddArc(ballPath, NULL, size.width-40, self.size.height/2, 20, 0, M_PI*2, YES);
ball.path = ballPath;
ball.lineWidth = 2;
ball.fillColor = warmRed;
ball.strokeColor = [SKColor whiteColor];
ball.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:20];
[self addChild:ball];
//lands on bottom of screen
SKShapeNode * ball2 = [[SKShapeNode alloc] init];
CGMutablePathRef ball2Path = CGPathCreateMutable();
CGPathAddArc(ball2Path, NULL, 0, 0, 20, 0, M_PI*2, YES);
ball2.path = ball2Path;
ball2.lineWidth = 2;
ball2.fillColor = warmRed;
ball2.strokeColor = [SKColor whiteColor];
CGSize spriteContainerSize = CGSizeMake(40,40);
CGPoint spriteContainerPosition = CGPointMake(size.width/2, size.height/2);
SKSpriteNode * spriteContainer = [SKSpriteNode spriteNodeWithColor:[SKColor blackColor] size:spriteContainerSize];
spriteContainer.position = spriteContainerPosition;
spriteContainer.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:spriteContainerSize];
[spriteContainer addChild:ball2];
[self addChild:spriteContainer];
//lands on bottom of screen
CGSize boxSize = CGSizeMake(40,40);
CGPoint boxPosition = CGPointMake(boxSize.width, size.height/2);
SKSpriteNode * box = [SKSpriteNode spriteNodeWithColor:[SKColor blackColor] size:boxSize];
box.position = boxPosition;
box.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:boxSize];
[self addChild:box];
}
return self;
}
Screenshot:
https://dl.dropboxusercontent.com/u/164157126/example.jpg
Note that you don't set a position for the node which falls off the screen, but set a position for the other two nodes you create.
The default position of a node is 0,0. Your ball will appear at the bottom left of the scene, and since it is over the edge body you defined, will fall off immediately.
Set the ball's position appropriately so that it does not intersect the edge of the screen, and the ball will not fall off.

SpriteKit ball loses all energy hitting wall, restitution=1

If I apply an impulse of 1 in the y direction, the ball bounces back and forth without losing any energy. However, if the initial impulse is 0.5 or below, the ball loses all energy instantly when it hits the wall. Why is this happening? I have a pretty good understanding of the properties of the SKPhysicsBody class. Try this code to see if you get the same behavior on your computer.
-(id)initWithSize:(CGSize)size {
if (self = [super initWithSize:size]) {
/* Setup your scene here */
self.physicsWorld.gravity = CGVectorMake(0.0f, 0.0f);
SKPhysicsBody* borderBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:self.frame];
self.physicsBody = borderBody;
self.physicsBody.friction = 0.0f;
self.backgroundColor = [SKColor colorWithRed:0.7 green:0.7 blue:0.7 alpha:1.0];
SKShapeNode *ball = [SKShapeNode node];
CGMutablePathRef pathToDraw = CGPathCreateMutable();
[ball setStrokeColor:[UIColor blackColor]];
CGPathMoveToPoint(pathToDraw, NULL, 0, 0);
CGPathAddEllipseInRect(pathToDraw, NULL, CGRectMake(-16, -16, 32, 32));
ball.path = pathToDraw;
ball.position = CGPointMake(size.width / 2, size.height / 2);
ball.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:ball.frame.size.width/2];
ball.physicsBody.friction = 0.0f;
ball.physicsBody.restitution = 1.0f;
ball.physicsBody.linearDamping = 0.0f;
ball.physicsBody.allowsRotation = NO;
[self addChild:ball];
[ball.physicsBody applyImpulse:CGVectorMake(0, 0.5)];
}
return self;
}
When the collision velocity is small enough (such as your CGVector of (0, 0.5)), Box2d underlying the Sprite Kit physics engine will compute the collision as inelastic (i.e. as if the restitution was 0, removing any bounciness), and the node will not bounce.
This is, per the Box2d documentation, to prevent jitter.
In the Box2d source code, you even have this line:
/// A velocity threshold for elastic collisions. Any collision with a relative linear
/// velocity below this threshold will be treated as inelastic.
#define b2_velocityThreshold
Your impulse should be above this threshold for the restitution to be respected.

Sprite Kit pin joints appear to have an incorrect anchor

I'm testing out pin joints with Sprite Kit, and I'm finding something unusual happening.
My desired setup is this: one wide, flat box, and two circles; the circles are connected via SKPhysicsPinJoints to the box, so they can act as wheels.
Here's my code. I've tried to make it as concise as possible:
- (SKNode*) createWheelWithRadius:(float)wheelRadius {
CGRect wheelRect = CGRectMake(-wheelRadius, -wheelRadius, wheelRadius*2, wheelRadius*2);
SKShapeNode* wheelNode = [[SKShapeNode alloc] init];
wheelNode.path = [UIBezierPath bezierPathWithOvalInRect:wheelRect].CGPath;
wheelNode.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:wheelRadius];
return wheelNode;
}
- (void) createCar {
// Create the car
SKSpriteNode* carNode = [SKSpriteNode spriteNodeWithColor:[SKColor yellowColor] size:CGSizeMake(150, 50)];
carNode.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:carNode.size];
carNode.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame));
[self addChild:carNode];
// Create the left wheel
SKNode* leftWheelNode = [self createWheelWithRadius:30];
leftWheelNode.position = CGPointMake(carNode.position.x-80, carNode.position.y);
[self addChild:leftWheelNode];
// Create the right wheel
SKNode* rightWheelNode = [self createWheelWithRadius:30];
rightWheelNode.position = CGPointMake(carNode.position.x+80, carNode.position.y);
[self addChild:rightWheelNode];
// Attach the wheels to the body
CGPoint leftWheelPosition = leftWheelNode.position;
CGPoint rightWheelPosition = rightWheelNode.position;
SKPhysicsJointPin* leftPinJoint = [SKPhysicsJointPin jointWithBodyA:carNode.physicsBody bodyB:leftWheelNode.physicsBody anchor:leftWheelPosition];
SKPhysicsJointPin* rightPinJoint = [SKPhysicsJointPin jointWithBodyA:carNode.physicsBody bodyB:rightWheelNode.physicsBody anchor:rightWheelPosition];
[self.physicsWorld addJoint:leftPinJoint];
[self.physicsWorld addJoint:rightPinJoint];
}
What I'm expecting is that the pin joints are anchored at their centre points; however, when I test this, the anchors for the joints appear to be far off.
Am I missing something really obvious?
I also had this issue and the cause is setting the physics body before setting the sprites position.
carNode.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:carNode.size];
carNode.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame));
Change the above to
carNode.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame));
carNode.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:carNode.size];
It should work. Thanks Smick.
SpriteKit: How to create Basic Physics Joints
Try this code, I used yours and got weird issues, so started from scratch.
- (SKShapeNode*) makeWheel
{
SKShapeNode *wheel = [[SKShapeNode alloc] init];
CGMutablePathRef myPath = CGPathCreateMutable();
CGPathAddArc(myPath, NULL, 0,0, 16, 0, M_PI*2, YES);
wheel.path = myPath;
return wheel;
}
- (void) createCar
{
self.physicsBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:CGRectMake(0, 0, self.size.width, self.size.height)];
// 1. car body
SKSpriteNode *carBody = [SKSpriteNode spriteNodeWithColor:[UIColor whiteColor] size:CGSizeMake(120, 8)];
carBody.position = CGPointMake(200, 200);
carBody.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:carBody.size];
[self addChild:carBody];
// 2. wheels
SKShapeNode *leftWheel = [self makeWheel];
leftWheel.position = CGPointMake(carBody.position.x - carBody.size.width / 2, carBody.position.y);
leftWheel.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:16];
[self addChild:leftWheel];
SKShapeNode *rightWheel = [self makeWheel];
rightWheel.position = CGPointMake(carBody.position.x + carBody.size.width / 2, carBody.position.y);
rightWheel.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:16];
[self addChild:rightWheel];
// 3. Join wheels to car
[self.physicsWorld addJoint:[SKPhysicsJointPin jointWithBodyA:carBody.physicsBody bodyB:leftWheel.physicsBody anchor:leftWheel.position]];
[self.physicsWorld addJoint:[SKPhysicsJointPin jointWithBodyA:carBody.physicsBody bodyB:rightWheel.physicsBody anchor:rightWheel.position]];
// 4. drive car
[carBody.physicsBody applyForce:CGVectorMake(10, 0)];
}

Resources