Saving levels (only) help!

@agramonte

why in the scene:show you use global myTable and in main you use local myTable?

I am experiencing many global and local problems with myTable, I do not understand anything …

If someone can explain to me how this work I will appreciate. It’s new for me and hard to understand.

what is the roll of (t, filename, location) in function M.saveTable(t, filename, location)

do I need to chage those values?

Sorry, both should be marked Local. I just copy and pasted from the sample in the link. The t is the table you want to save.

For example:

local t = {} t.level = "1"

filename is the name of the file to save to the file system: “pref.json” or “level.json” or “whatever.txt”

And finally, location is where you want to save that file.

t = table to save

filename = name of file to save the data to

location = folder to save the file to (optional, defaults to system.DocumentsDirectory)

I suspect that @agramonte simply left the “local” off of the myTable variable.

If you’re having trouble understanding global vs. local, getting a lot of nil variables that you think shouldn’t be or things behaving weirdly there is a good chance you need to understand “scope” better. This tutorial explains it:  http://docs.coronalabs.com/tutorial/basics/scope/index.html

It’s really a simple concept once you understand what defines a block of code. It really helps if you properly indent your code so you can easily see each block of code.

Consider:

local myFirstVariable = 1 local function myFunction( ) local mySecondVariable = 2 if mySecondVariable == 2 then local myThirdVariable = 3  print( mySecondVariable ) -- prints 2 end print( myThirdVariable ) -- prints nil end

vs

local myFirstVariable = 1 local function myFunction( ) local mySecondVariable = 2 if mySecondVariable == 2 then local myThirdVariable = 3 print( mySecondVariable ) -- prints 2 end print( myThirdVariable ) -- prints nil end

The blocks of code are identical other than some formatting, but the first block is really hard to understand where one block of code begins and ends. The indentions should show you that there actually three blocks of code. One is a “main chunk” (code lined up against the left edge, a function block named myFunction() and a “if” block.

local variables can only be seen in the block they are defined and any children blocks, for instance, the “if” block is a child of the myFunction() block. The myFunction() block is a child of the main chunk. 

This means that myThirdVariable only exists and can be seen inside the “if” block. The mySecondVariable only exists inside the function and can only be seen there. But since the “if” block is a child of the function, it can also see mySecondVariable. One the “if” block is done, myThirdVariable goes away and isn’t available to the rest of myFunction().

The indenting of the code really helps you visualize what’s going on. 

Rob

Here you go a simple example. I created this from the game template. I just copied and pasted 6 scenes. Imagine they are your 6 mini-games.  There is just one button in the middle and you click and go to the next scene. Then if using the simulator you refresh, it remembers where you left off.  I am using Rob’s library.

thanks to everyone especially @agramonte. I am studying what you upload and I am understanding much better. I believe that I will soon be able to implement it.

:) 

if I want to change the image of “play button”, or replace it with a “continue button” in my menu when a .json file it’s created, the only way is to use LFS to check if myTable.json exist? or there is another comparision I can make to achieve this task?

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: