Reanimating a bouncing ball in sprite-kit - sprite-kit

Reanimating a bouncing ball in sprite-kit
I have a question about the best way to reanimate a bouncing ball. Using Ray Wenderlich's tutorial on building a break out game as a reference I have a number of circular shape nodes which continually bounce around a gravity-less environment. When the user touches one of them, it centers on the screen, stops moving, and transforms into something else. When the user touches it again, it is supposed to transform back into the circular shape node and then continue bouncing around the screen.
I have it all working as I like except for reanimating the ball. The manner in which I stop the animation is simply to set the physicsBody to nil. Once I want to reanimate, I call the method that sets up the physicsBody for the node and I apply an impulse to it. But frustratingly, the impulse does not have the effect I think it should. Clearly, my expectations are incorrect.
Here is the code in question:
- (void)applyPhysics
{
// Set physics properties
self.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:self.frame.size.width/2];
self.physicsBody.friction = 0.0f;
self.physicsBody.restitution = 1.0f;
self.physicsBody.linearDamping = 0.0f;
self.physicsBody.allowsRotation = NO;
self.physicsBody.collisionBitMask = wallCategory;
self.physicsBody.categoryBitMask = bubbleCategory;
}
- (void)morphPicker
{
BOOL check = NO;
if (check) NSLog(#"morphPicker called.");
[self runAction:[SKAction fadeAlphaTo:0.0 duration:.5]];
if (self.flipped) {
if (check) NSLog(#"The information side is showing.");
self.fillColor = bubbleColors[self.index % bubbleColors.count];
self.alpha = .9;
// Resume physics:
[self applyPhysics];
[self.physicsBody applyImpulse:CGVectorMake(10.0f, -10.0f)];
} else {
// stop physics:
self.physicsBody = nil;
if (check) NSLog(#"The statistic side is showing.");
self.fillColor = [SKColor blackColor];
self.alpha = .9;
[self transformToPickerNode];
[self removeAllChildren];
}
self.flipped = !self.flipped;
}
So my questions are these:
How should I be reanimating the ball if applying an impulse to it is not the correct method?
Is there a more elegant way to stop the animation after centering the node than setting the physicsBody to nil? Even to my novice instincts it feels like a brutish method.

After all my trials and searching for an answer to this I firmly believe that there is no elegant way to apply a new impulse to a sprite and expect it to move in the physics world. Thus my answer must be "it cannot be done at this point." However, my solution of removing all the the animated sprites from the scene and recreating them turned out to be the best solution for a completely different reason. The nature of my physics world caused my "floating bubbles" to eventually end up in the corners of the scene where they remained unmoving. Occasionally removing and recreating them had the effect of sending them happily bouncing around the scene again :)

Related

How to create a pendulum with spritekit

I'm trying to create a pendalum in spritekit but i cannot figure out how to make the pendalum swing. So far the code is:
transparentpixel = [SKSpriteNode spriteNodeWithImageNamed:#"transparent_pixel"];
[transparentpixel setPosition:CGPointMake(150,150)];
transparentpixel.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:CGSizeMake(1, 1)];
transparentpixel.physicsBody.dynamic = YES;
[_bg addChild:transparentpixel];
pendalum = [SKSpriteNode spriteNodeWithImageNamed:#"pendalum_image"];
[pendalum setPosition:CGPointMake(150,120)];
pendalum.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:pendalum.size];
pendalum.physicsBody.dynamic = YES;
[_bg addChild:pendalum];
CGPoint pendalumjointanchor = CGPointMake(150,150);
SKPhysicsJointPin *pendalumJointPin = [SKPhysicsJointPin jointWithBodyA:transparentpixel.physicsBody bodyB:pendalum.physicsBody anchor:pendalumjointanchor];
[self.physicsWorld addJoint:pendalumJointPin];
I can't figure out how to make the pendalum swing indefinetely.
You can create physics bodies on each side of the pendulum around where the pendulum would reach it's max height.
Set an event to trigger when the pendulum hits these physics bodies. In this event, Apply a downward force.
After playing with the physics bodies locations and the amount of force, you should be able to achieve something very similar to the effect you are after.

Moving sprite "smoothly"

I'm trying to move a sprite in a set direction on-screen, using the physicsBody.velocity property. However, the motion is quite "jumpy" (makes the game look like it's lagging). I assume this has something to do with the different time intervals between each call to the update-method. How could I achieve a more "smooth" motion?
Right now this is the code I have in my update-loop to make the sprite move forward:
if (_movingForward) {
CGFloat forwardVel = _ball.physicsBody.velocity.dx;
forwardVel += 20.0;
if (forwardVel > bMaxForwardVelocity) {
forwardVel = bMaxForwardVelocity;
}
_ball.physicsBody.velocity = CGVectorMake(forwardVel, _ball.physicsBody.velocity.dy);
}
As you can see, I'm trying to make the speed pick up, so it doesn't immediately reach it's terminal velocity. This is to make the motion look more natural. However, the lagging is ruining this effect greatly, even when the sprite supposedly is traveling at a set speed.
EDIT 1:
I'm trying to make a platform-style game (like Super Mario etc) where the _ball moves horizontally along the ground when the user taps the screen. The code for moving the ball to the right is included above the edit. The ground is made up of multiple tiles, each 32x32 and positioned right next to each other with no gap in-between.
As per request, here's the code for setting up the _balls physicsBody:
self.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:self.size.width/2.0];
self.physicsBody.dynamic = YES;
self.physicsBody.restitution = 0.5f;
self.physicsBody.usesPreciseCollisionDetection = YES;
self.physicsBody.allowsRotation = NO;
self.physicsBody.mass = 0.5f;
self.physicsBody.friction = 0.0f;
self.physicsBody.linearDamping = 0.0f;
self.physicsBody.categoryBitMask = CollisionCategoryBall;
And here's the code for the physicsBody of each individual tile:
tile.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:tile.size];
tile.physicsBody.dynamic = NO;
tile.physicsBody.categoryBitMask = CollisionCategoryGround;
The physicsWorld is set up like this:
self.physicsWorld.gravity = CGVectorMake(0, -4);
self.physicsWorld.contactDelegate = self;
Thanks!
EDIT 2:
This is a side-scrolling game, so the "camera" follows the ball. Here's the code for moving the background layer:
- (void)centerViewOn:(CGPoint)centerOn {
CGFloat x = Clamp(centerOn.x, (self.size.width / 2.0), (_bgLayer.layerSize.width) - (self.size.width / 2.0));
_worldNode.position = CGPointMake((int)-x, _worldNode.position.y);
}
The reason for the Clamp is so the "camera" doesn't scroll beyond the bounds of the background. This is when the ball is close to either the start or end of the level.
I'm casting the position to an int because without it, small gaps sometimes occur between the tiles. I was told this was because of some inaccuracy or something. However, even without casting the position to int, it's still a bitt "laggy". But because of the gaps between the tiles, it looks even worse.
The issue was with your scrolling code.
change this line :
_worldNode.position = CGPointMake((int)-x, _worldNode.position.y);
to
_worldNode.position = CGPointMake(-x, _worldNode.position.y);
The movement is then silky smooth.
But then you do get those seams. You should solve that in the placement of those tiles. You are likely positioning your _worldNode tiles with float values.

Is there a way to make a soft body with Spritekit using SKSpriteNode and PhysicsBody parameters?

I have the following sprite that falls to the bottom of the screen:
// The View
self.physicsBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:self.frame];
self.physicsWorld.contactDelegate = self;
// The Sprite
SKSpriteNode *cube = [[SKSpriteNode alloc] initWithImageNamed:#"cube"];
[cube setPosition:CGPointMake(160,250);
[self addChild:cube];
// The Physics
cube.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:cube.frame.size];
cube.physicsBody.dynamic = YES;
cube.physicsBody.affectedByGravity = YES;
cube.physicsBody.mass = 0.02;
Is there a way to make it so its sides are bulging when it hits the bottom border of the screen? Something that would be Jelly like or a soft body that still maintains its shape to some extent but bulges out under its own weight? I hope this makes sense....
Visit the site https://gist.github.com/kazukitanaka0611/4b9d4ac9dff0cd317b6c it have explanation and source code for soft bodies (jelly) in sprite kit
quick and easy way without math:
1 use flash to tween your box warping.
2 export the tweened frames as a sprite sheet (texture atlas)
3 animate the texture atlas on contact with an edge physics body in your scene.
your box will fall and on contact animate the separate images to give the impression its warping/bulging sides.
i used this method and it works - in other words it gives the desired effect, which in my view is what is important - your gamers don't care how you did it, as long as it looks great.

How to move the PhysicsSprite in box2d

I am having a physicsSprite of kinematics body type and I want to move the body and sprite bit down and back to its position. I tried it like this Inside update method:
for (NSValue *bodyValue in [self getGoalPostBodiesList])
{
b2Body *gPBody = (b2Body *)[bodyValue pointerValue];
PhysicsSprite *pSprite =(PhysicsSprite *) gPBody->GetUserData();
NSLog(#"\n tag value of Sprite = %d",pSprite.tag);
if(pSprite == goal1)
{
pSprite.position = CGPointMake((gPBody->GetPosition().x)*32.0,(gPBody->GetPosition().y)*32.0);
float angle = gPBody->GetAngle();
pSprite.rotation = -(CC_RADIANS_TO_DEGREES(angle));
id moveDownAction = [CCMoveTo actionWithDuration:0.5 position:CGPointMake(pSprite.position.x,(pSprite.position.y )- 40)];
id moveUpAction = [CCMoveTo actionWithDuration:0.5 position:CGPointMake(pSprite.position.x,(pSprite.position.y )+ 40)];
CCSequence *seqAction = [CCSequence actions:moveDownAction,moveUpAction, nil];
[pSprite runAction:seqAction];
b2Vec2 pos = b2Vec2(pSprite.position.x/32.0, pSprite.position.y/32.0);
gPBody->SetTransform(pos, CC_DEGREES_TO_RADIANS(pSprite.rotation));
gPBody->SetLinearVelocity(b2Vec2(0.0f, 0.0f));
gPBody->SetAngularVelocity(0.0f);
}
}
Still the sprite is not changing its position.
Anyone's help will be deeply appreciated.
Thanks all,
MONISH
To summarize your code, you update the position of your sprite to reflect that of the body, start an animation, and then update the position of the body to correspond to the position of the sprite. So naturally, nothing should move here, since your CCMoveTo actions have not exerted any effect on your sprite yet.
Second, your update method may be called very often, like dozens of times per second, so the animation gets reset continously and will not make any visible progress.
To follow a consistent pattern, how about you set the velocity of your kinematic bodies. Also, update the position of your sprites to correspond to these bodies as you would do for dynamic bodies, but don't set the transformation of your bodies to correspond to their sprites.

Problem with smoke bubble in cocos2d

I am having a problem. When the smokeMoveBy action starts a small smoke bubble is spotted on the screen at other place then the moving path of the smoke.
This is only happening when I am using scaleX and scaleY.
The method smokeLoop is being called at each 1 seconds in the scheduler.
Here self is a layer.
Any solutions?
My code follows,
CGPoint dummyPosition=ccp(600, 600);
ParticleSystem *smoke = [ParticleSmoke node];
ccColor4F startColor;
startColor.r = 1.f;
startColor.g = 1.f;
startColor.b = 1.f;
startColor.a = 1.f;
[smoke setStartColor:startColor];
ccColor4F endColor;
endColor.r = 0.8f;
endColor.g = 0.8f;
endColor.b = 0.8f;
endColor.a = 1.0f;
[smoke setEndColor:endColor];
[smoke setLife:0.1f];
[smoke setScaleX:0.1f];
[smoke setScaleY:0.2f];
[smoke setStartSize:30.f];
[self addChild:smoke z:2];
[smoke setPosition:dummyPosition];
-(void)smokeLoop{
id smokeMoveBy = [MoveBy actionWithDuration:durTime position:ccp(0.f, (-1.f*480))]];
id smokeSeq=[Sequence actions:[Place actionWithPosition:smokeInitPosition], smokeMoveBy, nil];
[smoke runAction:smokeSeq];
}
Not sure if this is your issue, but I had an issue with Cocos2D, scaling and moving, which I solved with moving the anchorPoint.
What I wanted to do is zoom (scale) and move a layer. Zooming would move fine if position was {0,0} and transform point was {0.5,0.5}. But then if I'd move it, it would still transform around {0.5,0.5}, which might by then be out of screen, so it would scale really weird.
Solution was to move the transform point to the middle of the screen, every time I moved the layer's position. This was not an easy formula for me to fix, as when I moved the transform point, the scale operation would have a new center point.
The formula I ended up using was the following:
layer = self.foreground;
ccpAdd(
ccpDivide(
ccpNeg(layer.position),
(CGPoint){layer.contentSize.width, layer.contentSize.height}),
(CGPoint){0.5f,0.5f}
);
Basically: Divide the inverse of the layers position (meaning, {300,200} would become {-300,-200}) by the size of the layer {480,320}, and then add {0.5,0.5} (as I want my anchor to be always center + offset)
Anyway, you may need to work out a completely different formula, but this worked for me. I had to apply this to my anchor point every time I moved the layer.
Good luck, hope this helps!