6
votes

Looking for help on how to create a custom SKAction (sprite kit) that performs a bounce?

Basically, want to drop a sprite from the top screen to bottom (Y axis) and have it perform a quick decay bounce (up and down the Y axis only).

Note: Don't want to use physics engine.

I looked at some tween examples online (in C), but the math makes my eyeballs glaze over and to boot, its not abundantly clear how I'd integrate those functions anyway. I also experimented with SKAction sequencing, using moveTo's and moveBy's, but the effect isn't that smooth.

3

3 Answers

5
votes

You can combine several SKActions to achieve the effect.

CGFloat bounceFactor = 0.2f;
SKAction* dropAction = [SKAction moveByX:0 y:-dropHeight duration:0.3f];
SKAction* bounce = [SKAction sequence:@[[SKAction moveByX:0 y:dropHeight*bounceFactor duration:0.1f],
                                        [SKAction moveByX:0 y:-dropHeigh*bounceFactor duration:0.1f],
                                        [SKAction moveByX:0 y:dropHeight*bounceFactor/2 duration:0.1f],
                                        [SKAction moveByX:0 y:-dropHeight*bounceFactor/2 duration:0.1f]]];

[node runAction:[SKAction group:@[dropAction,bounce]]];

Also you can play around SKActionTimingMode to make bounce look realistic.

2
votes

I would do a simple velocity calculation:

In your @interface/header (to make ivars global):

CGFloat velocity; // velocity
CGFloat gravity; // force of gravity
CGFloat ballY; // the ball location
CGFloat floorY; // the floor location
CGFloat dampening; // a float 0 to 1, where 0 will mean no bounce

In your setup method (initial speeds and Ys):

velocity = <some number here>;
gravity = <another number>;
ballY = <another number>;
floorY = <another number>;
dampening = <another number>;

In the scene's -update: method (this speeds up the ball and bounces it at the bottom):

velocity += gravity; // increases velocity with gravity
ballY += velocity; // update position

if (ballY > floorY) {
  ballY = floorY; // don't let the ball past floor
  velocity *= dampening; // dampens velocity on the bounce
  velocity *= -1; // change direction
}

sprite.position = CGPointMake(0, ballY);
2
votes

I needed to do the same thing recently. I was surprised to see that Apple didn't support spring animations in SpriteKit, considering they added them in UIKit two years ago.

I saw they added a timingFunction property on SKAction in iOS 8, but that doesn't solve the issue since you need to go beyond your target if you're bouncing.

At first I just concatenated a few sub-actions with SKAction.sequence, tweaking the values and timing modes by eye, but the result was pretty lame.

I ended up doing the maths and making a set of extensions to be able to perform most SKActions with a bouncy effect. It works exactly the same way as the UIView counterpart, you just add a damping and an initial velocity to your usual SKActions, and you're done. The library replicates most factory methods of SKAction, but you can also use the low level methods to animate any CGFloat property on your SKNodes.

The code is on GitHub, feel free to use it: https://github.com/ataugeron/SpriteKit-Spring