Tutorial: Incrementing score counter

nums2
Share on Facebook0Share on Google+2Tweet about this on TwitterShare on LinkedIn0

When you complete a level in a video game, it often shows your score in an animated fashion. Sometimes this involves the numbers “spinning” in such a way that they count up from the 1s column to the 10s column and so on, like an odometer of a car but much faster.

nums

Achieving this effect in Corona begins with some simple math. Let’s jump directly into some code:

The first thing to understand is that Corona is a frame-based system. This means that the screen updates essentially at a fixed pace. By default, this pace is 30 times per second, usually referred to as 30 frames per second (“fps”). Corona can also run at 60 fps, which many developers choose for a smoother look.

At 60 fps, the screen can only update every 1/60th of a second (16.6667 milliseconds). At 30 fps, the screen can only update every 1/30th of a second (33.3333 milliseconds). Trying to force a faster update rate is an exercise in futility.

Controlling the rate

Obviously, game scores can vary greatly — one game may have a maximum score of 12 while another will have a maximum score in the millions. Thus, we don’t want our function to count up by a fixed amount like 1 on each frame update. If so, a score in the millions would take too long to update, while a score like 12 would finish far too quickly.

A better solution is to determine how long the animation should run and then calculate the amount that it should increment on each frame update. In this example, the score will have 2 seconds to spin up from 0 to the final value. For an app set to run at 30 fps, this means that there will be 60 total updates.

Determining the passes and increment

First we need to figure out how many “passes” are required. This value is simply the time in milliseconds (duration) divided by the frame rate of the app (fps).

Next, we need to determine the amount to increment the score by. This is done via a method called lerp which stands for linear interpolation. This method basically allows you to compute intermediate points between two values based on some criteria.

In our example, the lerp function is straightforward. We take the difference between the start and stop values (v1-v0) and multiply it by the fraction of the time we want to know the increment for — in this case, 1/passes since we know how many iterations we need over the span 2 seconds. Then we add that to the start value (v0).

The showScore() function

The actual showScore() function requires four arguments:

  1. The display.newText() text object that will be updated.
  2. The “final value” to show for that text object, for example, the score the player achieved.
  3. The duration of the count-up routine in milliseconds.
  4. The frame rate of the app.

Inside the function, we set a temporary value, newScore, so the score displays to zero. We also use the duration and frame rate to calculate the number of required passes. All of this is computed inside of a Runtime "enterFrame" listener that will fire every frame. Finally, we use a counter to track the number of passes.

When the loop is done incrementing, we need to adjust for any fractional remainder of the final score. This is done simply by setting the text object to the final value.

Conclusion

Hopefully this tutorial gets you started with a classic “spinning score counter” feature for your game. If so inclined, you could easily extend the showScore() function to accept both duration and fps values instead of using the static values for the timers.


Share on Facebook0Share on Google+2Tweet about this on TwitterShare on LinkedIn0
Rob Miracle

Rob Miracle creates mobile apps for his own enjoyment and the amusement of others. He serves the Corona Community in the forums, on the blog, and at local events.

This entry has 8 replies

  1. Lerg says:

    I’ve made a followup pro tip on how to use transition.to() and metatables to achieve such animation.

    http://spiralcodestudio.com/corona-sdk-pro-tip-of-the-day-34/

    • Munky says:

      Brilliant Sergey, thanks!

    • Rob Miracle says:

      I may like you’re version better than mine.

      • Lerg says:

        Thank you!

  2. ouguolin says:

    Very good tutorial!

    but I believe it’s a bug in this line:

    local passes = duration / fps

    it works if fps is 30 but wont work if fps is other values 🙂 and here is my fixing:

    local passes = duration * fps
    duration is in seconds and fps is in frames per second.

    • Kenny Tee says:

      You’re right on that Ougoulin.

      Local passes = duration * fps

      Main important thing is that duration which is 2000ms here, has to made into seconds which is 2s, otherwise, it will take forever for the increment to finish

      Overall

      local function lerp( v0, v1, t )
      return v0 + t * (v1 – v0)
      end

      local passes = duration/1000 * fps = 2000/1000 * 30 = 60

      Cheers and keep coding

  3. andrew says:

    is there anyway to make it stop counting when my restart scene comes on.

    • Rob Miracle says:

      You’re in control of when you increment the score. Its up to your code to decide how to handle that.

Leave a reply

You may use these HTML tags and attributes: <a href="" title="" rel=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">