Posted on by

Today’s guest tutorial is the second from Omid Ahourai, an indie game developer who goes by the alias “ArdentKid.” Over the past two years, Omid has risen to become an experienced Corona developer, and is working to release his first highly-anticipated Corona game, “Balloon Bazooka.” He also offers Corona tutoring for programmers of all levels. Check out his work and blog at www.ardentkid.com.

Optimizing Transitions

In an effort to boost the performance of my upcoming game, I decided that I needed a more efficient way to use transitions with my game sprites. I have found a couple of libraries like the one by TimeSpaceMagic which also incorporates pause and time-warping. However, all of them calculate the transition properties at Runtime, which can become pretty taxing on the processor. This is unnecessary if the transition will always be the same.

That’s why I have created “AK-Tween”, a library for predetermining transitions and manually applying them at Runtime. I’ve benchmarked it with results up to 20% faster than other Runtime transition approaches, the most efficient method I had found previously. The alpha version of the library is built with easing equations based on GTween for AS3, so it will yield a nearly identical result compared to Corona’s transition easing. There’s a link available at the end of this tutorial to download AK-Tween, along with a benchmarking tool (see iPhone4 test results below).

The Core Idea

“AK-Tween” calculates all of the transitions at load time (not during Runtime) by storing the values in tables/arrays. We then iterate through them using custom Runtime functions when they’re needed. Here’s a glance at a piece of the tween calculation code which returns the array of values:

--AKtween.lua
local function tweenCalc( config, anim )

  local time = config.time or 1000
  local ease = config.ease
  local totFrames = 0.06 * time  --frames at 60FPS

  local step = 1/totFrames

  if ( ease == "outQuad" ) then

    for i=1,totFrames do
      pos = pos + step
      local index = i +startArr
      local ratio = -pos * (pos-2) arr[index] = from + (ratio * delta)
    end

  elseif ( tween == "inQuad" ) then
    ...

  end

  return arr
end

And here’s the code to actually set up a tween (we’ll use a bouncing ball as an example):

--CREATE TWEEN FOR BALL BOUNCE
local AKtween = require( "AKtween" )

local ball = display.newImage( "ball.png" )

local bounceTween = AKtween:newTween( {time=400, y=-120, ease="outQuad"} )
--bounceTween.yArr = [-4.79, -4.58, -4.37, -4.16, -3.95 ... -0.83, -0.625, -0.416, -0.20, 0]
--#bounceTween.yArr = 24

bounceTween:append( {time=400, y=0, "inQuad"} )
--bounceTween.yArr = [-4.79, -4.58, -4.37, ... -0.416, -0.20, 0, 0.20, 0.416 ... 4.37, 4.58, 4.79]
--#bounceTween.yArr = 48

ball.yBounceArr = bounceTween.yArr     --JUST GET THE Y-VALUES,
--bounceTween:apply( ball, "bounce" )  --OR ALLOW AKTWEEN TO HANDLE THE WHOLE ANIMATION

This allows our ball to bounce from y=0 to y=-120 and fall back down, with a natural-feeling quadratic ease. It will take 400ms each way (24 frames at 60 fps). We could just call the :apply() function in the last line and use ball:playTween(“bounce”) to have our tween be completely handled by AKtween. For the sake of this tutorial, however, we’re going to do the same thing manually and only use the y-value array created from the library.

So, with the predetermined y-values stored in ball.yBounceArr, we can set up our Runtime ball:bounce() script:

function ball:bounce()

  local yVals = self.yBounceArr
  local totFrames = #yVals
  local curFrame = 1

  --RUNTIME SCRIPT, OCCURS ON EVERY FRAME
  local function frameCount()
    if ( curFrame <= totFrames ) then
      self:translate( 0, yVals[curFrame] )
      curFrame = curFrame+1
    else
      curFrame = 1
    end
  end

  --SAVE REFERENCE TO RUNTIME FUNCTION, AND BEGIN
  self.bounceFC = frameCount
  Runtime:addEventListener( "enterFrame", frameCount )

end


We call ball:bounce() whenever we want to start bouncing the ball. It sets up a local Runtime script called frameCount, which will set a new y-position for our ball on every frame of the game. We also saved a reference to this function in ball.bounceFC, which means we can pause, resume, or stop the bounce like this:

The “manual way” is harder to implement than a regular transition, but it allows us to customize precisely what we do with our animation properties. It’s extremely efficient from a performance standpoint and it’s also pause-enabled. In combination with my dynamic sprites implementation, the game should run very smoothly.

Benchmark Results

Here are the benchmark results using this method. Both manual and AKtween play functions yield nearly identical results.

In summary, we’ve defined an underlying alternate method for transitioning our objects. These benchmarks prove that the method is very efficient! We simply read values from an array and apply them to the correct object property. We can apply play functionality by passing objects to the AKtween juggler, or we can achieve total control over animations by adding and removing local runtime scripts. Either way, you may want to check out AKtween and see if its methods can benefit your app.


Posted by . Thanks for reading...

6 Responses to “Tutorial: Predetermined Transitions & Manual Animation”

  1. Thy Toeung

    Wonderful to see this, and thanks for sharing if with the community. Sometimes wisdom is just seeing things from a different perspective, and this is definitely finding that space between corona transitions and moving items at runtime.

    Excellent work, and looking forward to using this methodology in the game I’m developing now!

    Reply
  2. Chris Leyton

    Hey Omid – quick question. Just read your blog post from where this stems and how you’re trying to optimise transitions as a result of Corona re-rendering every display object. Do you have to use transitions, could you not get away with object:translate()? I’m imagining that would be a performance gain – but perhaps you can’t get away with using that?

    Reply
    • Omid Ahourai

      Thanks guys!
      Chris- I do use :translate() in the above examples, which allows the movement to be done relatively (so we can stack movement if needed). I’m not completely clear on whether it’s much better for the renderer than changing the .x or .y property though. From my testing, it doesn’t seem to matter much. But it would be cool to have a Corona engineer specify that here (or in the docs).

      Reply
  3. Krystian

    I would like an option to change the speed of the transition at the runtime.
    This is something I do very often [animation speedup/slowdown] and the amount of speedup/slowdown is calculated at runtime so I can’t define separate tweens and reuse them.

    Reply
    • Omid Ahourai

      Predetermining transitions using AK-Tween doesn’t really allow for time change at runtime because the calculations are fixed, unless you manually create an array of these transitions at the speeds you’d like at load-time. It’s possible to add a “timeRange” function to the library that does this, but using it for this purpose specifically may cause load-time to take too long (due to massive amounts of calculations).

      Reply

Leave a Reply

  • (Will Not Be Published)