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.
Related
I am working on a project and what I need to accomplish is to generate random curl line. At this point I have already have a line which is randomly generated but it is not curl. I am spawning points at different x positions on every 0.5 seconds and connect this points with bezier. Everything works perfectly except that it is not curl. On the picture below is shown on 1) How I have it now and on 2) How I suppose to make it. Any ideas how I can do that ? I am using SpriteKit - Objective C
Basically what you need to make and randomize a A Bézier (parametric) curve are control points.
After you read that great answer and get familiar with terms, you can try this example (I assume that your scene and view size are set correctly):
GameScene.m
#import "GameScene.h"
#implementation GameScene
-(void)didMoveToView:(SKView *)view {
}
-(NSInteger)randomNumberBetween:(NSInteger)from to:(NSInteger)to {
return (int)from + arc4random() % (to-from+1);
}
- (CGMutablePathRef)generatePath
{
CGMutablePathRef path = CGPathCreateMutable();
CGPoint p0 = CGPointMake(CGRectGetMidX(self.frame),self.scene.size.height-20.0f); //starting point just little below the upper edge of the screen
CGPathMoveToPoint(path, nil, p0.x, p0.y);
CGPoint p1 =
CGPointMake([self randomNumberBetween:150 to:300], self.scene.size.height- [self randomNumberBetween:150 to:300]);
CGPoint p2 = CGPointMake([self randomNumberBetween:150 to:300],[self randomNumberBetween:150 to:300]);
CGPoint p3 = CGPointMake(CGRectGetMidX(self.frame),0 + 20.0f); //ending point, just little above the bottom edge of the screen
CGFloat v = 0.3;
CGFloat cp1x = p1.x+v * (p1.x-p0.x);
CGFloat cp1y = p1.y+v * (p1.y-p0.y);
CGFloat cp2x = p2.x-v * (p3.x-p2.x);
CGFloat cp2y = p2.y-v * (p3.y-p2.y);
CGPathAddCurveToPoint(path,nil,cp1x,cp1y,cp2x,cp2y,p3.x,p3.y);
/*Debug - not needed*/
SKSpriteNode *sp0 = [SKSpriteNode spriteNodeWithColor:[SKColor yellowColor] size:CGSizeMake(5.0f,5.0f)];
sp0.zPosition = 5;
sp0.position = p0;
SKLabelNode *lp0 = [SKLabelNode labelNodeWithFontNamed:#"ArialMT"];
lp0.fontColor = [SKColor whiteColor];
lp0.fontSize = 20.0f;
lp0.text = #"p0";
lp0.position = CGPointMake(0.0f,-20.0f);
[sp0 addChild:lp0];
[self addChild:sp0];
SKSpriteNode *sp1 = [SKSpriteNode spriteNodeWithColor:[SKColor yellowColor] size:CGSizeMake(5.0f,5.0f)];
sp1.zPosition = 5;
sp1.position = p1;
SKLabelNode *lp1 = [SKLabelNode labelNodeWithFontNamed:#"ArialMT"];
lp1.fontColor = [SKColor whiteColor];
lp1.fontSize = 20.0f;
lp1.position = CGPointMake(0.0f,15.0f);
lp1.text = #"p1";
[sp1 addChild:lp1];
[self addChild:sp1];
SKSpriteNode *sp2 = [SKSpriteNode spriteNodeWithColor:[SKColor yellowColor] size:CGSizeMake(5.0f,5.0f)];
sp2.zPosition = 5;
sp2.position = p2;
SKLabelNode *lp2 = [SKLabelNode labelNodeWithFontNamed:#"ArialMT"];
lp2.fontColor = [SKColor whiteColor];
lp2.fontSize = 20.0f;
lp2.position = CGPointMake(0.0f,15.0f);
lp2.text = #"p2";
[sp2 addChild:lp2];
[self addChild:sp2];
SKSpriteNode *sp3 = [SKSpriteNode spriteNodeWithColor:[SKColor yellowColor] size:CGSizeMake(5.0f,5.0f)];
sp3.zPosition = 5;
sp3.position = p3;
SKLabelNode *lp3 = [SKLabelNode labelNodeWithFontNamed:#"ArialMT"];
lp3.fontColor = [SKColor whiteColor];
lp3.fontSize = 20.0f;
lp3.position = CGPointMake(0.0f,15.0f);
lp3.text = #"p3";
[sp3 addChild:lp3];
[self addChild:sp3];
SKShapeNode *p0p1 = [SKShapeNode node];
p0p1.zPosition = 2;
CGMutablePathRef path1 = CGPathCreateMutable();
CGPathMoveToPoint(path1, NULL, p0.x, p0.y);
CGPathAddLineToPoint(path1, NULL, p1.x, p1.y);
p0p1.path = path1;
[p0p1 setStrokeColor:[UIColor greenColor]];
[self addChild:p0p1];
SKShapeNode *p2p3 = [SKShapeNode node];
p2p3.zPosition = 2;
CGMutablePathRef path2 = CGPathCreateMutable();
CGPathMoveToPoint(path2, NULL, p2.x, p2.y);
CGPathAddLineToPoint(path2, NULL, p3.x, p3.y);
p2p3.path = path2;
[p2p3 setStrokeColor:[UIColor greenColor]];
[self addChild:p2p3];
return path;
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[self removeAllChildren];
SKShapeNode *yourline = [SKShapeNode node];
yourline.zPosition = 1;
yourline.path = [self generatePath];
[yourline setLineWidth:5];
[yourline setStrokeColor:[SKColor redColor]];
[self addChild:yourline];
}
Most of this code is used for visual debugging and its not needed in order to randomize the curve. The important part is the first part of the method generatePath. Here is the result:
I want to draw a circle and a line from from the circles center which is also twice as long as the circle's radius
My output is drawing a circle with the line next to it.
- (void)setupMainBall {
mainBall = [self makeMainBall];
mainBall.position = CGPointMake(self.size.width / 2, self.size.height / 2);
mainBall.zPosition = 3;
[self addChild:mainBall];
[mainBall addChild:[self makeCanon]];
}
-(SKShapeNode *)makeMainBall {
SKShapeNode *theMainBall = [[SKShapeNode alloc] init];
CGMutablePathRef myPath = CGPathCreateMutable();
CGPathAddArc(myPath, NULL, 0, 0, 10, 0, M_PI*2, YES);
theMainBall.fillColor = [SKColor blueColor];
theMainBall.path = myPath;
theMainBall.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:theMainBall.frame.size.width / 2];
return theMainBall;
}
-(SKSpriteNode *)makeCanon {
canon = [SKSpriteNode spriteNodeWithColor:[SKColor blackColor] size:CGSizeMake(3, 20)];
canon.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:canon.frame.size];
return canon;
}
Try:
SKSpriteNode *canon = [self makeCannon];
[mainBall addChild:canon];
canon.position = CGPointMake(mainBall.size.width / 2, mainBall.size.width /2);
I want to make a soccer ball by IOS SpriteKit
I was able to create a ball in the code such as the following.
However, it does not bounce at all.
To make rebound rate, How can I do this?
(UITouch *touch in touches) {
SKSpriteNode *sprite = [SKSpriteNode spriteNodeWithImageNamed:#"Ball"];
sprite.position = location;
const CGFloat radius = 20.0f;
SKPhysicsBody *pbody = [SKPhysicsBody bodyWithCircleOfRadius:radius];
sprite.physicsBody = pbody;
sprite.size = (CGSize){radius * 2, radius * 2};
sprite.physicsBody.linearDamping=0.12f;
[self addChild:sprite];
}
I have declared like this.
-(id)initWithSize:(CGSize)size {
if (self = [super initWithSize:size]) {
self.backgroundColor = [SKColor colorWithRed:0.15 green:0.15 blue:0.3 alpha:1.0];
self.physicsBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:(CGRect){CGPointZero, size}];
self.physicsWorld.gravity=CGVectorMake(0, -100);
}
return self;
}
This looks like a ball to me
- (void) soccerBallExample
{
// the world bounds
self.physicsBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:CGRectMake(0, 0, self.size.width, self.size.height)];
// the ball
SKShapeNode *ball;
ball = [[SKShapeNode alloc] init];
CGMutablePathRef myPath = CGPathCreateMutable();
CGPathAddArc(myPath, NULL, 0,0, 30, 0, M_PI*2, YES);
ball.path = myPath;
CGPathRelease(myPath);
ball.fillColor = [SKColor blueColor];
ball.position = CGPointMake(200, 200);
[self addChild:ball];
// set the physics
ball.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:30];
ball.physicsBody.restitution = 0.8;
}
In your example, you use a sprite so for radius use
// ball.size.width * 0.5;
I want a ball-sprite jump off the ground each time to the same height. But with every jump the maximum height position of the ball increases.
-(id)initWithSize:(CGSize)size {
if (self = [super initWithSize:size]) {
SKNode *ground = [SKNode node];
ground.physicsBody = [SKPhysicsBody bodyWithEdgeFromPoint:CGPointZero toPoint:CGPointMake(CGRectGetMaxX(self.frame), 0)];
[self addChild:ground];
SKShapeNode *ball = [[SKShapeNode alloc] init];
CGMutablePathRef myPath = CGPathCreateMutable();
CGPathAddArc(myPath, NULL, 0, 0, 30, 0, M_PI*2, YES);
ball.path = myPath;
ball.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMaxY(self.frame)-100);
ball.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:ball.frame.size.width/2];
ball.physicsBody.linearDamping = 0.0;
ball.physicsBody.restitution = 1.0;
[self addChild:ball];
}
return self;
}
Any suggestions?
Look at setting both the restitution and friction on both bodies, not just the ball. If it's growing and not shrinking though, there is likely an error with the physics bodies. SKShapeNode is notoriously unreliable in my testing - I would look into using SKSpriteNode instead to maintain your sanity.
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)];
}