Impulse doesn't apply in Sprite Kit - sprite-kit

I'm attempting to apply an impulse to a sprite node in SK every time I touch, but nothing is happening. The touch is registering, but there is no impulse.
-(id)initWithSize:(CGSize)size {
if (self = [super initWithSize:size]) {
/* Setup your scene here */
self.backgroundColor = [SKColor colorWithRed:0.15 green:0.15 blue:0.3 alpha:1.0];
self.physicsBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:self.frame];
SKSpriteNode *torso = [SKSpriteNode spriteNodeWithColor:[SKColor blueColor] size:CGSizeMake(40, 60)];
torso.position = CGPointMake (250,250);
torso.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:CGSizeMake(40, 60)];
torso.physicsBody.dynamic = YES;
[self addChild: torso];
SKSpriteNode *arm = [SKSpriteNode spriteNodeWithColor:[SKColor redColor] size:CGSizeMake(15, 50)];
arm.position = CGPointMake (235,235);
arm.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:CGSizeMake(40, 60)];
arm.physicsBody.dynamic = YES;
[self addChild: arm];
SKPhysicsJointPin *leftArm = [SKPhysicsJointPin jointWithBodyA:torso.physicsBody bodyB:arm.physicsBody anchor:torso.position];
[self.physicsWorld addJoint:leftArm];
}
return self;
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
[_torso.physicsBody applyImpulse:CGVectorMake(12, 10)];
NSLog(#"touch");
}
My sprite node does have another node linked to it, but I tried the impulse on it without the additional node and it still did not work.

For some reason, in order to move my sprite node I had to create it like this
_torso = [SKSpriteNode spriteNodeWithColor:[SKColor blueColor] size:CGSizeMake(40, 60)];
rather than
SKSpriteNode *torso = [SKSpriteNode spriteNodeWithColor:[SKColor blueColor] size:CGSizeMake(40, 60)];
Once I set a breakpoint and saw that _torso was nil, I referred to some previous work and saw my mistake.

Related

Sprite Node leaving frame

I've set the physics body for both the background and the other sprite node, yet the node can still leave the the border. It doesn't fall through the bottom, it can leave on the sides though.
SKSpriteNode *bg = [SKSpriteNode spriteNodeWithImageNamed:#"bg"];
bg.position = CGPointMake(self.scene.size.width/2, self.scene.size.height/2);
self.physicsBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:self.frame];
self.physicsWorld.contactDelegate = self;
[self addChild:bg];
SKSpriteNode *player = [SKSpriteNode spriteNodeWithImageNamed:#"ball"];
player.position = CGPointMake(self.frame.size.width*.5, 200);
player.name = #"player";
player.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:30];
player.physicsBody.categoryBitMask = playerCategory;
player.physicsBody.contactTestBitMask = barCategory;
[self addChild:player];
What i think is happening is the body of the the background node is wider than what the view is showing. How can i make it so that the body dimension is what ever the view is.
Change the initialisation line of GameScene in GameViewController to
GameScene *scene = [[GameScene alloc]
initWithSize:CGSizeMake(self.view.frame.size.width,
self.view.frame.size.height)];

How to synchronize circle (with SKAction by SKShapeNode) to ball (by SKShapeNode)?

I try to synchronize circle (create with SKAction by SKShapeNode) to ball (create by SKShapeNode).
Here is this code. But it couldn't work well.
What should I do?
-(void)makeContents{
//make ground
UIBezierPath *groundPath = [UIBezierPath bezierPath];
[groundPath moveToPoint:CGPointMake(0,250)];
[groundPath addLineToPoint:CGPointMake(568,100)];
SKShapeNode *ground = [[SKShapeNode alloc] init];
ground.path = groundPath.CGPath;
[self addChild:ground];
//make ball
SKSpriteNode *ball = [SKSpriteNode spriteNodeWithImageNamed:#"ball.jpeg"];
ball.position = CGPointMake(10, 320);
ball.size = CGSizeMake(20, 20);
ball.physicsBody.dynamic = YES;
ball.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:3];
[self addChild:ball];
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
//make circle
UIBezierPath *circlePath = [UIBezierPath bezierPath];
[circlePath addArcWithCenter:ball.position radius:10 startAngle:0 endAngle:2*M_PI clockwise:NO];
circle = [[SKShapeNode alloc] init];
circle.path = circlePath.CGPath;
circle.strokeColor = [SKColor blackColor];
//this line added after first post.
circle.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:10 center:ball.postion];
[self addChild:circle];
//make action
SKAction *scale = [SKAction sequence:#[[SKAction scaleBy:0.1 duration:2],
[SKAction scaleBy:0 duration:0.01]]];
[circle runAction:[SKAction repeatActionForever:scale]];
}
Thank you in advance for your help.

Not able to apply impulse to SKSpriteNode physics body

I am new to xcode's sprite kit and I'm an trying to apply an impulse to a SKSpriteNode's physics body.
Here is how I create the scene:
self.backgroundColor = [SKColor colorWithRed:0 green:0 blue:0 alpha:1.0];
self.physicsBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:self.frame];
self.physicsBody.friction = 0.0f;
self.physicsWorld.gravity = CGVectorMake(0.0f, 0.0f);
ballCategory = 1;
wallCategory = 2;
self.physicsBody.categoryBitMask = wallCategory;
Here is how I create the player AND give it its impulse:
player = [SKSpriteNode spriteNodeWithImageNamed:filePath];
player.size = CGSizeMake(100, 100);
player.position = CGPointMake(150, 250);
player.physicsBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:player.frame];
player.physicsBody.categoryBitMask = ballCategory;
player.physicsBody.collisionBitMask = wallCategory;
player.physicsBody.friction = 0.0f;
player.physicsBody.restitution = 1.0f;
player.physicsBody.linearDamping = 0.0f;
player.physicsBody.allowsRotation = NO;
[self addChild:player];
CGVector impulse = CGVectorMake(100,100);
[player.physicsBody applyImpulse:impulse];
Is there anything obvious that I am missing because I've been following the iOS Developer Library Sprite Kit Programming Guide perfectly? Thanks in advance for the help!
You are creating the player's physicsBody as an edge body - these are always static (immovable by forces/impulses). You should change that line to:
player.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:player.frame.size];
This example makes it a dynamic volume based on a rectangle which will be affected by physics forces. You can read up on the types of physics bodies here.

vertical scrollable CCLayerColor issue

i'm trying to do a scrollable layer with cocos2d
what i want is for the layer to start scrolling from the top to bottom but no matter what i do when it enters the scene the layer is positioned at (0,0) aka..bottom
i've tried a couple of things but nothing seems to work
-(id) init
{
if( (self=[super init] )) {
self.isTouchEnabled = YES;
isDragging = NO;
yvel = 0.0f;
contentHeight = 1000.0f;
scrollLayer = [CCLayerColor layerWithColor:ccc4(200, 200, 200, 240)];
scrollLayer.contentSize = CGSizeMake(320,contentHeight);
scrollLayer.anchorPoint = ccp(0,1);
scrollLayer.position = ccp(0, 480);
[self addChild: scrollLayer];
CCLabelTTF *label = [CCLabelTTF labelWithString:[NSString stringWithFormat:#"test label"]
fontName:#"Marker Felt"
fontSize:24];
label.position=ccp(100, 100);
[scrollLayer addChild:label];
[self scheduleUpdate];
}
return self;
}
the other methods are update and touches handlers so the problem couldn't be there
with this code...shouldn't it initialize with the content at the top left of the screen?
after a painful few hours i finally solved the problem...but i still dont know why it works
instead of scrollLayer.position = ccp(0, 480); i replaced with scrollLayer.position =ccp(0,-contentHeight); and deleted scrollLayer.anchorPoint = ccp(0,1); cuz it wasnt doing anything
and i have absolutely no idea why it works
can someone explain this?

how to add an animation effect of drawing a circle in cocos2d

i am working on a game to spot the difference between 2 images.
I want to add an effect when you spot it. drawing out a circle would be much better than just showing the circle suddenly. but i've never done core animation or opengl before.
i don't think preparing 100 sprites and changing the sprite frame by frame is a good idea.
here is my code: (just add a circle image to both left and right image. )
-(void) show {
CCSprite* leftCircle = [CCSprite spriteWithFile:#"circle.png"];
CCSprite* rightCircle = [CCSprite spriteWithFile:#"circle.png"];
leftCircle.scaleX = size.width / [leftCircle boundingBox].size.width;
leftCircle.scaleY = size.height / [leftCircle boundingBox].size.height;
rightCircle.scaleX = size.width / [rightCircle boundingBox].size.width;
rightCircle.scaleY = size.height / [rightCircle boundingBox].size.height;
leftCircle.anchorPoint = ccp(0, 1);
rightCircle.anchorPoint = ccp(0, 1);
leftCircle.position = leftPosition;
rightCircle.position = rightPosition;
[[GameScene sharedScene] addChild:leftCircle z: 3];
[[GameScene sharedScene] addChild:rightCircle z: 3];
shown = YES;
}
So how can i implement it? It would be great if you can provide some source code.
As a simple way i can recommend you to create a circle and put it's scale to zero. Then create a CCScale action and run it. It will give you a growing circle. Here is the code:
CCSprite *sprite = [CCSprite spriteWithFile:#"mySprite.png"];
[sprite setScale:0.01];
id scale = [CCScale actionWithDuration:0.3 scale:1];
[sprite runAction:scale];
The other action can be used is CCFadeIn.You can make your sprite invisible after creation and make it fade in:
CCSprite *sprite = [CCSprite spriteWithFile:#"mySprite.png"];
[sprite setOpacity:0];
id fade = [CCFadeIn actionWithDuration:0.3];
[sprite runAction:fade];
Also you can combine this actions:
[sprite runAction:fade];
[sprite runAction:scale];
Also you can make it big (set scale 3 for example) and transparent. And make it fade in and scale down to highlight your image
To Draw a circle via drawing effect you can make it from small parts (arcs) and then build your circle from them. I think it also will be cool if you make don't make the part visible when adding, but make it fade in. I mean something like this:
-(void) init
{
NSMutableArray *parts = [[NSMutableArray array] retain]; //store it in your class variable
parts_ = parts;
localTime_ = 0; //float localTime_ - store the local time in your layer
//create all the parts here, make them invisible and add to the layer and parts
}
-(void) update: (CCTime) dt //add update method to your layer that will be called every simulation step
{
localTime_ += dt;
const float fadeTime = 0.1;
int currentPart = localTime_ / fadeTime;
int i = 0;
for (CCSprite *part in parts)
{
//setup the opacity of each part according to localTime
if (i < currentPart) [part setOpacity:255];
else if (i == currentPart)
{
float localLocalTime = localTime - i*fadeTime;
float alpha = localLocalTime / fadeTime;
[part setOpacity:alpha];
}
++i;
}
}
It is rather simple to create the effect you want.
You can realize it by setting the strokeEnd of a CAShapeLayer.
Here are the details:
create a path you then assign to a CAShapeLayer
UIBezierPath* circlePath = [UIBezierPath bezierPathWithArcCenter:CGPointMake(100.0, 100.0) radius:80.0 startAngle:DEGREES_TO_RADIANS(270) endAngle:DEGREES_TO_RADIANS(270.01) clockwise:NO];
circle = [CAShapeLayer layer];
circle.path = circlePath.CGPath;
circle.strokeColor = [[UIColor blackColor] CGColor];
circle.fillColor = [[UIColor whiteColor] CGColor];
circle.lineWidth = 6.0;
circle.strokeEnd = 0.0;
[self.view.layer addSublayer:circle];
set the strokeEnd to implicitly animate the drawing of the circle
circle.strokeEnd = 1.0;
That's it! The circle will be automatically drawn for you ;). Here is the code from above with a GestureRecognizer to trigger the animation. Copy this to an empty project of type "Single View Application" and paste it to the ViewController.
#define DEGREES_TO_RADIANS(angle) ((angle) / 180.0 * M_PI)
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
UIBezierPath* circlePath = [UIBezierPath bezierPathWithArcCenter:CGPointMake(100.0, 100.0) radius:80.0 startAngle:DEGREES_TO_RADIANS(270) endAngle:DEGREES_TO_RADIANS(270.01) clockwise:NO];
circle = [CAShapeLayer layer];
circle.path = circlePath.CGPath;
circle.strokeColor = [[UIColor blackColor] CGColor];
circle.fillColor = [[UIColor whiteColor] CGColor];
circle.lineWidth = 6.0;
circle.strokeEnd = 0.0;
[self.view.layer addSublayer:circle];
// add a tag gesture recognizer
// add a single tap gesture recognizer
UITapGestureRecognizer* tapGR = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleTapGesture:)];
[self.view addGestureRecognizer:tapGR];
}
#pragma mark - gesture recognizer methods
//
// GestureRecognizer to handle the tap on the view
//
- (void)handleTapGesture:(UIGestureRecognizer *)gestureRecognizer {
circle.strokeEnd = 1.0;
}