SKActionTimingFunction should allow values to go outside of the 0.0-1.0 range.

Number:rdar://17588949 Date Originated:2014-07-08
Status:Open Resolved:
Product:iOS SDK Product Version:iOS 8 beta 3
Classification:Serious Bug Reproducible:Always
iOS 8 beta 3 introduces the new SKActionTimingFunction type and the corresponding timingFunction property on SKAction. Great, I've wished for that since the first beta of iOS 7 and Sprite Kit. So thanks for that! :-)

However, the current implementation is severely limited. According to the comments in the header:

"Input time will be linear 0.0-1.0 over the duration of the action. Return values must be 0.0-1.0 and increasing and the function must return 1.0 when the input time reaches 1.0."

That makes these timing functions unusable for anything but the simplest of timing curves.

1) It does not allow overshoot or undershoot because that requires that the intermediate timing values can become less than 0.0 or greater than 1.0.

2) Having the requirement that the values are always increasing prevents bouncing effects.

To overcome the absence of custom timing functions in iOS 7's Sprite Kit, I had to create my own classes that basically replicate what SKAction does, but allowed for custom timing. That's a bit silly but the only usable solution for now. You can see that work here:

I'd love to delete my own classes, but I can't do that until SKActionTimingFunction drops these restrictions.

Steps to Reproduce:
This is a very common timing function:

func backEaseIn(t: Float) -> Float {
  let s: Float = 1.70158
  return ((s + 1.0) * t - s) * t * t

If you plot this curve, it drops briefly below 0.0 and then climbs up towards 1.0.

Try to use it like this:

let action = SKAction.rotateByAngle(CGFloat(M_PI), duration:1)
action.timingFunction = backEaseIn

Expected Results:
Before the sprite rotates 180 degrees counterclockwise, it first rotates clockwise, as if it is gearing up for the big movement. This is anticipation, one of the 12 basic principles of animation.

Actual Results:
The sprite sits still while the output of the backEaseIn() function is less than 0.0 and only moves as soon as it becomes greater than 0. There is no sense of anticipation.


Please note: Reports posted here will not necessarily be seen by Apple. All problems should be submitted at before they are posted here. Please only post information for Radars that you have filed yourself, and please do not include Apple confidential information in your posts. Thank you!