Tutorial: How to display and save scores

Share on Facebook0Share on Google+4Tweet about this on TwitterShare on LinkedIn0

A frequently asked question in the forums, especially from those developers new to Corona and Lua, is “How do I keep score?”. Today’s tutorial will walk you through the entire process, including:

  1. Setting up a variable to hold the score.
  2. Displaying the score.
  3. Saving (and retrieving) the score for future use.

The score module

Corona does not have a built-in score module, so let’s build one which you can implement in your apps, beginning with a basic “initialization” function:

As you can see, the options we support are:

  • fontSize — The size of the displayed score text.
  • font — The font used for the displayed score text.
  • x — The x location to draw the score display.
  • y — The y location to draw the score display.
  • maxDigits — The estimated number of the max score.
  • leadingZerostrue or false: do you want leading zeros?
  • filename — The local filename to save the score to.

Most of these are straightforward, but we could extend this with alignment properties and other settings. For example, we could add options to control the anchor points for left- or right-aligned score text.

The score text uses the string.format() API call to format the number, and the string will either be prefixed by spaces or by zeros, depending on the settings. This format setting (M.format) is also saved to the module for usage in other functions. If any settings aren’t specified, then we fall back to the reasonable defaults, in this case, 24-point Helvetica, centered at the top of the screen, with a maximum of 6 digits. By default, the local save file target is scorefile.txt, but this can be changed to another file name.

Functions for “set,” “get,” and “add”

Next, let’s write some functions for settinggetting, and adding to the score:

If we set the score, the display will update and overwrite the current value with the new one. The get method simply returns the current score for some other use. Finally, the add function allows us to add to the current score and update the display. This could be extended to a “subtract” function, but it’s more efficient to just pass a negative value to the add function.

Saving and loading the score

The last thing our module needs is the ability to save and load the score to a file. This is required so that the score can be saved and retrieved between app sessions.

As seen on lines 40 and 54, the score file exists in the system.DocumentsDirectory. We cannot write it to system.ResourceDirectory since it’s read-only, and both system.TemporaryDirectory and system.CachesDirectory are prone to automatic cleanup by the system. So, logically, we create and keep this file inside the documents directory so it persists between app sessions.

Let’s quickly inspect the load() function in more depth. This function opens the file, reads the value into a local variable, and returns it. It does not, by design, update the text value on the screen. In many cases, this function will be used to load the last saved score, compare it to the current score, and check if we have a new “high score.” However, if we need to both load the score and display the last saved value, we can simply call the set() function using the value we just retrieved from the load() function.

Finally, on line 69, we return the module’s M table back to the caller, thus making the functions and data available to the caller.

Putting it to use

With our module created and the basic functions written, we can now use it within our app.

The first line is the mandatory require line which includes the module in our project, providing access to all of the functions we wrote above. The second block calls the init() function with a series of basic parameters. This creates the text display, centers it at the top of the screen, and sets it to a zero-filled seven-digit score.

From this point, the following actions can be executed with just one line:

  • score.set( value ) — sets the value.
  • local myscore = score.get() — gets the current value.
  • score.add( value ) — add value to the current score.
  • score.save() — save the score.
  • local highscore = score.load() — load the previously-saved score.

In conclusion

Hopefully this tutorial exhibits just how easy it is to work with scores in Corona, including saving and loading scores to the device for persistence between app sessions.

Share on Facebook0Share on Google+4Tweet 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 54 replies

  1. Jen Looper says:

    Very nice! Another good solution particularly suited for keeping scores is Scoreoid, it works really well.

  2. Is there a way for Corona to hook into the NSUserDefaults? I’d like to update my game Geared to the corona engine but I saved all of my players data using NSUserDefaults. This was a silly mistake (I was pretty new to game development when I started that game in 2009), but the data was also super simple. (A level is either completed or its not).

    • Rob Miracle says:

      As of right now, we don’t support NSUserDefaults. You can enter a feature request for it (or vote up one if it’s already there — and I think it is) at http://feedback.coronalabs.com


  3. helios says:

    cant see the save button. just the load button

    • Rob Miracle says:

      I’m not sure what you’re asking Helios. Please post a request in the forums with the code you are trying to use.


  4. Joel says:

    Hi Corona,

    Thanks for the article..

    Say in my game , I save the user data like currentLevel, currentScore etc .. when I want the users to update to a new version – will this data be erased ?.. how is this handled in Corona SDK , for Android ..


    • Rob Miracle says:

      When people upgrade, IOS and Android preserve the app’s sandbox files ( system.DocumentsDirectory, system.CachesDirectory and probably system.TemporaryDirectory). The only thing that gets replaced is the app’s bundle itself, so your data files are protected unless they delete the app. If they delete the app, the data goes away too.

      But the upgrade process is non-destructive.

  5. Arun says:

    I have used the code in this tutorial and it works great!

    But how do I show the highscore? When i put the highscore code in, it doesn’t come up with an error, but it doesn’t seem to do anything! How can I show the highscore on screen?


    • Rob Miracle says:

      You would need to create a new display.newText() object and use the value as the text to show.


      • Arun says:

        I know how to make a text object but how would I use the value as the text to show?

        Sorry to be awkward!

        • Rob Miracle says:

          Lets say your text object is named “highScoreText” then you would do:

          local highscore = score.load()
          highScoreText.text = highscore

  6. Marco says:

    And how can I show the High Score?

    • Rob Miracle says:


      • Kamil says:

        function saveHighScore()
        scoreload = score.load()
        myscore = score.get()
        if (myscore > scoreload) then
        print( “NOWY HIGH!” )
        print( myscore )
        print( scoreload )
        print( “SLABO!” )
        print( myscore )
        print( scoreload )

        • Rob Miracle says:

          Hi Kamil. I’m not sure if you have a question here or not, but comments doesn’t format code well. If you have a question, please ask it in the forums.


  7. lORI says:

    I am a “Newbie” to programming and I am having trouble saving my score. Initially I set it up using the widget buttons and I was able to make it work; I’ve now removed the buttons. I’ve structured my game using Composer and I am using the code from the tutorial “How to Display and Save Scores posted on December 10, 2013. I’ve written the first level and the actual game works fine but I am having trouble saving the score. I am able to display the final game score which is the current game score plus a calculated bonus score; however, I am not able to save the score and then retrieve it in future sessions to determine if the current score is higher than the previous score and therefore should overwrite the previous score. Below is the code related to the scoring that I am using; I only included the line adding the score with the bonus score as everythng is working. Every time I load the previous score, the code converts the “nil” to zero which I assume means I am not writing the score to the file correctly. I would really appreciate some guidance on what I am doing wrong. Ultimate goal: save the score for the first game and then overwrite the saved score for that level if the score is surpassed in future attempts. Thanks!


    local score = require (“score”)

    local gameScore = 0

    local scoreText = score.init({
    fontSize = 50,
    font = “Helvetica”,
    x = display.contentCenterX,
    y = 820,
    maxDigits = 7,
    leadingZeros = true,
    filename = “scorefile.txt”,

    –Calculates the current Game Score
    function currentGameScoreCalc()

    print (“function currentGameScoreCalc”)

    gameScore = solidTotal + bonusScore — this total appears on the screen so I can see that it is being calculated correctly

    print (“—————————“)
    print (“……..Current Game Score………. = “..gameScore) — the gameScore prints on the scoreen
    print (“—————————“)



    function loadHighScore()
    score = tonumber(score)
    if score == nil then score = 0 end
    print (“The score loaded = “..score) — it always prints zero so I assume that means that I am not writing the final score to the table in the code below
    highScore = score

    function compareScore()

    if gameScore > highScore then
    highScore = gameScore
    print (“the new high score = “..highScore)


    print (“Game Score is NEW HIGH SCORE = “..gameScore)
    print (“The High Score = “..highScore)


    — Score Module

    local M = {} — create our local M

    M.score = 0

    function M.init( options )
    local customOptions = options or {}
    local opt = {}
    opt.fontSize = customOptions.fontSize or 50
    opt.font = customOptions.font or native.systemFontBold
    opt.x = customOptions.x or display.contentCenterX
    opt.y = customOptions.y or opt.fontSize * 0.5
    opt.maxDigits = customOptions.maxDigits or 6
    opt.leadingZeros = customOptions.leadingZeros or false
    M.filename = customOptions.filename or “scorefile.txt”

    local prefix = “”
    if opt.leadingZeros then
    prefix = “0”
    M.format = “%” .. prefix .. opt.maxDigits .. “d”

    M.scoreText = display.newText(string.format(M.format, 0), opt.x, opt.y, opt.font, opt.fontSize)
    return M.scoreText
    function M.set()
    M.score = value
    M.scoreText.text = string.format(M.format, M.score)


    function M.get()
    return M.score
    function M.add()
    M.score = M.score + highScore
    M.scoreText.text = string.format(M.format, M.score)

    function M.save()
    local path = system.pathForFile( M.filename, system.DocumentsDirectory)
    local file = io.open(path, “w”) — io.open opens a file at path. returns nil if no file found
    if file then
    local contents = tostring( M.score )
    file:write( contents ) — write game score to the text file
    io.close( file )
    return true
    print(“Error: could not read “, M.filename, “.”)
    return false

    function M.load()
    local path = system.pathForFile( M.filename, system.DocumentsDirectory)
    local contents = “”
    local file = io.open( path, “r” )
    if file then
    — read all contents of file into a string
    local contents = file:read( “*a” )
    local score = tonumber(contents);
    io.close( file )
    return score

    file = io.open (path, “w”)
    return “0”
    print(“Could not read scores from “, M.filename, “.”)
    return nil


    return M

    • Rob Miracle says:

      Hi IORI. The blog comments are not a good place to show code and get answers. Please ask this question in the forums.


      • Lori says:

        OK. Will do. Have a great day.

  8. prabu says:

    please tell me is there a way to increase scored based on time

    • Rob Miracle says:

      You can increase the score any way you feel like. Scores don’t have to go up, they could go down (think Golf, Trivia games where you start at 1500 points and loose 100 points per second in the 15 seconds you have to answer). What value you use for the score and how you calculate it are all up to you. This module only deals with giving you a display object to show the score and a way to save it.

  9. ToeKnee says:

    I’m new to modules.

    local scoreText = score.init({…..})

    So this creates a local “name” attached to the result of the function running within the module.
    Now when used within composer and the scene. Can we just…

    sceneGroup:insert( scoreText )

    to add it to the scene – or because it was created ( display.newText(…) ) in the score module does it need to be handled a different way when combined with composer/storyboard??


    • Rob Miracle says:

      The function returns the display.newText() that holds the score, so you can insert it directly into a group.


  10. balla says:

    How can I reset the high score when I use this in the Corona simulator?

    • Rob Miracle says:

      I hate answering a question with a question, but do you want the player to be able to resent the high score or you do want to just for testing purposes?

      If you want the player to, you will have to give them some kind of button that executes some code to set the score to 0. These two lines should do the reset. You of course will need to provide the button and the handler function.

      score.set( 0 )

      Now if you want to just reset things to test, from the Corona Simulator menu at the top, do: File->Show Project Sandbox and open the highlighted folder. Go into the Documents folder there and delete your scores.json file. Relaunch the simulator.


      • balla says:

        I just wanted to reset things to test. Thank you!

      • David says:

        I tried score.set(0) but I got an error, I don’t understand, is there something I’m missing, I have the require line for score, please help

  11. Semir says:

    This seems nice. When I get a high score it saves it and displays it like it’s suppose to. However, when I exit the app and open it another time, the high scores are not there anymore. Can you please tell me why it does that and how I can fix this problem?

    • Rob Miracle says:

      Are you calling score.load() in your main.lua to fetch the saved version of the score?

  12. Hello,

    Thank you for this fine tutorial, Rob. I got a lot out of it. I’m trying to modify this module to save a separate score for each level. My efforts so far havebeen to change the initial variable assignment from

    M.score = 0


    M.score = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24}.

    So that each entry in the table represents the current high score for that level Then, every time a score module is called, I also pass an additional parameter, currentLevel. Such as,

    score.add(1, currentLevel)

    Of course, I’ve adjusted every instance of “score” in the module to “score[currentLevel]”. The add module appears to be working, but the “get” module does not. I’m sure I’m missing something simple to make this work properly.

    Thanks again,


    • Rob Miracle says:

      Jeff, can I get you to ask this over in the forums. The comments munge up code displays, so posting code here isn’t very good. Also, very few people look at the comments. You will have the whole community be able to offer you suggestions in the forums.


  13. David says:


    thank you for posting this tutorial. I am having major problems getting it to work though;
    I can’t seem to pass any values to “score,” so my question is what kind of value does it take: string, int, etc.
    and also, what can I use to pass values to “score”? I see you used score.add() but whenever I tried to use that or score.set() I get incorrect format errors saying it expected a string, and I’ve tried passing it string values but it still didn’t work. Sorry, I don’t know how to explain it any better, but please help.

    Thanks again.

  14. Jason Stahl says:

    Hi, thanks for making this tutorial. I got the code to save and load, but I have one small problem: I start with a main.lua file which almost immediately goes to a level1.lua file, which is where I modify the score, however, I need to be able to view the value of score from level1.lua in main.lua, so I tried loading the score in main.lua but I got a nil value. Is there anything that I can do to change this. Thanks again, any help is appreciated.

    • Rob Miracle says:

      Main.lua should always be a starting point for your app. Any display objects created there are always on top of any storyboard or composer scene. If you’re using the module to set the score, it should update its display object for you, so you shouldn’t need to reference the display object. Just make sure to require the score module in every scene.

  15. Lori says:

    If I wanted to use this module to save the score for multiple levels, do I replicate the set up for each level? or is there a shorter way to do this?

  16. tony says:


    I am knew to Corona SDK. First off thank you! this is a great explanation and has helped me understand a lot about saving into system.DocumentsDirectory, why it is done, and how it works.

    However I was hoping you could help me with the save Function. I would like the save function to only save the score if it is higher than what it previously was. In other words, I don’t want the score to be overwritten if it is a lower than previous score.

    no matter how i word the if statement I can’t come up with anything that works. Any help would be appreciated.

    • Rob Miracle says:

      Assuming the current score is being set into the score module:

      local highScore = score.load()
      if score.get() > highScore then

      Or something like that.

  17. Noah says:

    Hi I was wondering if anyone else has been experiencing some problems with this particular codes while building for Android? when I test build my game for Android and run It on my HTC One M8 I receive nothing on the screen,no Audio,no crashes just nothing. I’ve tried troubleshooting this issue by commenting out different parts of your code and seeing if it would work. I have come to a conclusion that these is a problem with reading a file in Documents Directory when the file to be read has not been created.

    I hope I have made my problem clear and if anyone can help that would be great!


  18. zvdvfb says:

    main.lua:160 ” expected near ‘local’
    what should I do to fix this problem??? Thank you

  19. zvdvfb says:

    line 160 is the local score = require ( “score” )

    • Rob Miracle says:

      Do you have score.lua in with your main.lua that you downloaded from this tutorial?

  20. James O leary says:


    I’ve used the above code as is in a project that I just released on the App Store. Some users are finding a glitch where the high score is not saved.

    Is there any possible reason for this ?

    Thank you

    • Rob Miracle says:

      It’s hard to tell. You need to see if you can reproduce the error on a test device and get the console log from it and see what errors you’re getting, perhaps build a test version with some prints to find out what’s going on.


  21. gmplayer says:

    I’m having some problem with this code now that I’m testing my game on the Google Play Store.

    If I directly load my .apk onto an Android device, the code works fine.

    If the Google Play store downloads and installs it, my game hangs when I use your “Load” function for the first time.

    Do I have to do something differently the first time the game is played to create the save file?


  22. Rob Miracle says:

    What does your console log have to say?


  23. vitor says:

    Is there a way or a pugln where we can use google services for game saved, instead pf store data locally? I’m already start the leaderboard and achievement but i’m found any sample for using game saved

    • Rob Miracle says:

      There are some 3rd party solutions like parse.com and coronium.io (the latter created by a Corona SDK user).


  24. Marco Anderson says:

    Hi Rob, I’m a newbie to programming. May I ask, the codes you’ve written above, do I put them on separate lua files or just put it in one file, namely “score.lua”?

    And what code should I use if I will press a button, it would add the score and display a new one?

    Thank you and God blessed you.

    • Rob Miracle says:

      Everything above “Putting it to use” goes in score.lua, the rest is examples you would use throughout your app.


  25. Mehdia Mahmood says:

    Hi Rob,
    I have tried the above code, it went well except that its adding some points in the end when nothing is happening. In my code I have added 10 points when ‘apple’ touches to ‘basket’ but when all falling fruits(apples too) are ended it is automatically adding 20 – 40 points..

    Any help would be appreciated.

    • Rob Miracle says:

      To help you, we are likely going to need to see some of your code. Code doesn’t post well here. It will be best to ask this in the forums.


  26. Banhbao says:

    Thank you for this tutorial, I’m a newbie so it’s a little hard for me to use this code. Now my problem is scoreText overlapping after the game restarts for next level. I don’t know how to remove it since I can’t add it to sceneGroup or use the removeSelf function… Could you help me about this?

  27. sdktester15 says:

    I am trying to use score.get(), but it is not working, do I have to insert a variable into the parenthesis?

    • Rob Miracle says:

      You don’t need to pass anything to score.get(). It should return the current value for the score assuming you have set the score previously. It will return nil if there isn’t a score.