Saving levels (only) help!

Hi guys! This time I do not have any code. I’m stuck. This is what I want to do and I do not know how to start. I want to have a menu scene where the word “play” appears the first time and when the player came back the word “continue” appears. Easy I can do this button and listener. What I do not know where to start is save current level, so the next time the player enters to play, press continue button and go to the level he left. My game is super simple, two objects, and different challenges per level, nothing more. I have read what I found in google and the Corona “higscores” guide but I can not understand how to do it so that only the level is saved, my game does not contain coins, scores, lives, nothing of that, only levels.

Thanks in advance
DoDi

Not knowing the exact state of your data during gameplay, it’s hard to give specific advice. You might want to check out this post to get some idea

My general game template in the marketplace does this for you (wink wink), but in a nutshell what I tend to do is store all of the game variables in a table, and then just write that whole table out to a save file either whenever something is updated (like the level you’re on) or manually via a save button.

The menu scene simply checks for the existence of that file and replaces your table with its data when the continue button is used, or replaces with some default values if the new button is used.

Subject to the game, it might actually be preferable to have a continue button that just returns you to the play scene without changing the data, and then a load button to do the above. Perhaps with a list of save files rather than just the one. The mechanic is the same though.

what I have has doubts to be able to start is for example:

local scores = 1000

here I have a value that I can handle in any scene, but how do I get the value of the scene completely? how I assigned to the json.encode to save the level number where the player stayed and when you press the “continue” button, take me to that scene.

My free plugin, GBC Data Cabinet, will allow you to manage and (optionally) save your game data.  

Basically, you save your data at some point (after each level, for example).

Next time, when the player starts your game, you read the data.  GBC will store all data in a table for you.

You can then determine where to continue based on value(s) of your data.

I have some examples of using GBC Data Cabinet here.

You could also look into this simple load save function made by Rob Miracle: https://github.com/robmiracle/Simple-Table-Load-Save-Functions-for-Corona-SDK.

I’ve used it, or something very similar to it, in almost every project of mine. 

I use something similar to what Rob posted in most of my games, but I have been thinking of switching to GDC Data Cabinet because it also has stacks and I use the GDC Language Cabinet in every game so far and I have never had a problem with it. 

So using the Cabinet you can make each level a cabinet and then stuff a table with all your variables into the cabinet. When I user clicks on level 5 you can just call the cabinet Level5 and pull down all the variables.

Thanks to everyone for your replies. I had thought about the GDC but as in this case the only thing I need is to return to the level where I stayed, which contains only two objects interacting with each other with physics, I do not think I should go too far in code to carry out that task. I am reading and evaluating, I would not like to add things to my code that I still do not understand.

One question: the whole “composer” scene is a variable?

--save and load last level local json = require( "json" ) M.lastLevel = {} local filePath = system.pathForFile( "levels.json", system.DocumentsDirectory ) function M.loadlevel() local file = io.open( filePath, "r" ) if file then local contents = file:read( "\*a" ) io.close( file ) M.lastLevel = json.decode( contents ) end if ( M.lastLevel == nil ) then M.lastLevel = { 0 } end end function M.saveLevel() --I'm stuck cause don't know how to store the level in the lastLevel table end

It’s all about newbie scope. I think I’m going to use the composer.setVariable() and composer.getVariable() with an if/then to check if level(whatever#) exist and then go to the level. 

thanks

DoDi

You need to save a data state.  

Every non-static item in your level that can change state and that needs to be saved/restored must have state data.

The first time your game runs, you use default values for those states.  

As your game progresses, you extract that state from the identified objects and save it in your ‘save table’.

Later when you restore you game, you re-build the level, but check the previously saved and not reloaded ‘save table’ for state data which applies to the current object you’re building.

For a player, state data might be:

  • current <x,y>
  • current vx, vy
  • current rotation
  • current hit points
  • current score

I answered a similar question in July 2015 and made an example of ‘persisting’ info about two objects and restoring them on reload.

https://github.com/roaminggamer/RG_FreeStuff/raw/master/AskEd/2015/07/persistingData.zip

This is the basic principle.

How you save, when you save, that depends on your needs.  

In my example I save as soon as the object moves.  That is overkill for most games.  Just save a set times or places.

One more note.  My code is super basic and does not incorporate the concept of a id.  It depends on the creation order always being the same which is unreasonable for large data sets.

It is better to save the data for each object based on an ID.  

Always create your objects’ data with IDs and restore by looking up those IDs.

Finally, I could make you a demo and helper module as a Level-1 hit if you’re interested.

https://sellfy.com/p/sank/

thanks @roaminggamer but I only need to save the level, when the user open the game appears a “play” button, when the user left the game and came back appears a “continue” button to take him to the last level he played. No scores, no lives, no position, no hit points, no sounds, nothing, just the level the player left.

this is what nI have:

--------------------------------------------------------- --save and load last level local M = {} local composer = require( "composer" ) local json = require( "json" ) local lastLevel = composer.getVariable( "level" ) local filePath = system.pathForFile( "levels.json", system.DocumentsDirectory ) function M.saveLevel() if filePath then local contents = json.encode(lastLevel) file:write( contents ) io.close( filePath ) return true else return false end function M.loadlevel() local file = io.open( filePath, "r" ) if file then -- read all contents of file into a string local contents = file:read( "\*a" ) lastLevel = json.decode(contents); io.close( file ) return lastLevel end return nil end return M

but know I can’t test it cause I don’t know how to call the loadLevel function in my play/continue listener to show the “play” or “continue” word and go to last level

in every level I use 

--level-1 composer.setVariable( "level", 1 ) --level-2 composer.setVariable( "level", 2 ) --etc, to level 10 for now

Am I doing things right for the task I want to carry out?

That isn’t how I would do it, so… I’ll say it isn’t ideal.

It sounds like you’re not tracking state at all, which makes my answers a waste of time.

I thought you wanted to create a game where you loaded a prior level and restored the state of the level.  My bad.

  1. I don’t know why you’re making those compose calls.  I do not see a purpose for them.

  2. Just do this.

A. In main.lua load a table, if not found give it default values:

-- using SSK, not your code: -- https://roaminggamer.github.io/RGDocs/pages/SSK2/extensions/#saving-loading-tables -- Load existing saved data or make new table. \_G.curLevelData = table.load("levelData.json") or { curLevel = 0 } -- 0 not started yet -- save immediately table.save( \_G.curLevelData, "levelData.json" )

B. Whenever you need to load the last loaded level, just refer to the table:

if( \_G.curLevelData.curLevel == 1 ) then ... -- whatever

C. Whenver you load a new level change the ‘curLevel’ value and save

-- just got done loading level 2 or about to load level 2 -- whatever makes sense for you \_G.curLevelData.curLevel = 2 table.save( \_G.curLevelData, "levelData.json" )

PS -

In your main menu, just check the ‘curLevel’ and if it is > 0, show a ‘continue’ button.

It makes sense to me if my game had a common “game.lua” where I substitute values, but my game is so simple, just a few lines of code, I decided that each level is a game, in which, when losing, the composer scene is restored and if you win you go to the next “level # .lua” where the same thing happens but with a different scenario. Every level is a different mini-game.  What I need to understand is how I call composer.gotoScene() from menu to level-1 but when I pass to other levels there is no way to go back to the previous level, if the player closes the app I would like the menu, instead of show the word “play” show the word “continue”, and when the player press that button takes me to the last level played, which is a different composer scene at any level, is another lua file.

In other words. First time, menu takes me to level-1, in any other time menu takes me to the last level played. But I need to save those values for when the player closes the game or decides to turn off or restart his phone and decides to play again can go to the last level where he stayed.

I thank everyone for their time and all the help they have given me

DoDi

I try to do the best I can using what “Corona SDK” gives us, that’s why I’m using composer. I understand that the only way to go to a next level is using composer.gotoScene() but I do not know how to tell composer.gotoScene() to go to the scene that contains the value that identifies the last level played which I must save in a .json file.

:wacko:  :wacko:  :wacko: 

[lua]

composer.gotoScene(mySceneNameVariableFromJson)

[/lua]

There are many approaches to communicating the level to play to a scene:

  1. You can use a non-global data table that’s required in each module and scene (which is a module): http://docs.coronalabs.com/tutorial/basics/globals/index.html (which I know you’re familiar with). Simply set a table member to have the value the level to play:

    myData.currentLevel = 3

for instance.

  1. Composer has a set of API calls that performs a similar function to the non-global data table. After all when you require composer you are getting a Lua data table that’s included in your scenes. We added a .setVariable() and .getVariable() API for this:

In your scene where you select the level:

composer.setVariable("currentLevel", 3)

in the scene where you need the information:

local currentLevel&nbsp;= composer.getVariable("currentLevel")
  1. Composer allows you to pass parameters on the gotoScene() call:

    composer.gotoScene(“game”, { params = { currentLevel = 3 }, effect = “crossFade”, time = 500 } )

then in your scene, during the scene:create() and scene:show() events, you will have a populated table:

function scene:create( event ) &nbsp; &nbsp; local params = event.params &nbsp; &nbsp; local currentLevel = 1 &nbsp; &nbsp; if params and params.currentLevel then &nbsp; &nbsp; &nbsp; &nbsp; currentLevel&nbsp;= params.currentLevel &nbsp; &nbsp; end &nbsp; &nbsp; ... end

I’m sure there are other techniques as well.

Rob

thanks for your help.

I do not have a common game.lua module in wich I replace values in each level, NO.
I have 10 different modules and I’m getting errors in the composer.gotoScene()

I have a progress module:

---------------------progress.lua------------------------- --save and load last level local M = {} local composer = require( "composer" ) local json = require( "json" ) local lastLevel = composer.getVariable( "level" ) local filePath = system.pathForFile( "levels.json", &nbsp; system.DocumentsDirectory ) function M.saveLevel() &nbsp; if filePath then &nbsp;&nbsp;&nbsp; local contents = json.encode(lastLevel) &nbsp;&nbsp;&nbsp; file:write( contents ) &nbsp;&nbsp;&nbsp; io.close( filePath ) &nbsp;&nbsp;&nbsp; return true &nbsp; else &nbsp;&nbsp;&nbsp; return false end function M.loadLevel() &nbsp; local file = io.open( filePath, "r" ) &nbsp; if file then &nbsp;&nbsp;&nbsp; -- read all contents of file into a string &nbsp;&nbsp;&nbsp; local contents = file:read( "\*a" ) &nbsp;&nbsp;&nbsp; lastLevel = json.decode(contents); &nbsp;&nbsp;&nbsp; io.close( file ) &nbsp;&nbsp;&nbsp; return lastLevel &nbsp; end &nbsp; return nil end return M

ok, now in every scene at top I require the progress module and
set the “level” variable to level # in this example 3, but it’s
the same in level 1 and level 2.

---------------------level\_3.lua-------------------------- local progress = require( "progress" ) local physics = require( "physics" ) physics.start() composer.setVariable( "level", 3 )

I call the M.loadLevel() function in every levels#.lua scene “create”
and the M.saveLevel() function in every levels#.lua scene “show”

-- create() function scene:create( event ) &nbsp;&nbsp; progress.loadLevel() end -- show() function scene:show( event ) &nbsp;&nbsp; progress.saveLevel() end

ok, and in menu.lua following @nick said

local function gotolastLevel() &nbsp;composer.gotoScene( progress.lastLevel ) end

but I’, getting this error

I am going to give it a hack since I think I understand what you want, but I am probably also wrong. 

  1. In main.lua retrieve the level from json from a file (from what I am reading I think you have that down if not you can use what Rob originally posted).

  2. From what I am also reading you have a bunch of levels called something like level1.lua, level2.lua, level3.lua. I am guessing you have a folder called levels. So from main I would call:

    local level = 2 – You would replace this with whatever code to retrieve the level from a file. composer.gotoScene(“levels.level”…level)

Just read your last post you are almost there. Use Rob’s library it won’t get any easier and the code is there.

https://github.com/robmiracle/Simple-Table-Load-Save-Functions-for-Corona-SDK

In every level scene as the scene:show save the scene number. You already know it since you are creating 1 scene per level:

local loadsave = require("loadsave") myTable = {} myTable.sceneNumber = "1" -- This would be for level 1 loadsave.saveTable(myTable, "myTable.json")

Then when you launch the app do what I did above but retrieve the scene using Rob’s library:

local loadsave = require("loadsave") local myTable = loadsave.loadTable("myTable.json") local level = (myTable.sceneNumber or 1) composer.gotoScene("levels.level"..level)