save and load levels in the Sticker-Knight game

Hi, greetings to all, I am new to the forum and crown sdk, I am setting up a platform based game, like the one of Sticker-Knight and I use the same code. I was wondering if anyone has discovered any way to save the levels of the game, I do it between scenes .lua but not with .json, you know: sandbox.json, sandbox1.json, sandbox2.json

Can someone help me? Thanks

All games where you can save the state of the world are similar at the highest-level.  There are essentially three categories of content:
(Note: The terms I use in the following list are non-standard.  i.e. I am making them up for the purpose of this discussion).

  • Static Content ( SC )- This is content that never changes and cannot be affected.  Thus it doesn’t need to be tracked by your save system.
  • Dynamic Content ( DC ) - This content would include things like (may or may not apply in all games):
    • player (location, hit-points, … )
    • various game metrics (current level, coins, …)
    • Changeable aspects of levels (Is a door open or closed, was  puzzle solved or not, …)
    • Environment states (is snowing, is it dark, …)
    • … and so on.
  • Non-Critical Dynamic Content ( NCDC ) - This is content that can be changed, but doesn’t need to be saved.  For example, if your game has a weather system you may want to save the the fact that it is dark and raining, but you don’t need to save the position of each raindrop.  It is OK for those to be in different positions when you restore later.

So, how does this apply to your question?  Well, you need to identify the content from your changed version of Sticker Knights that is in each of these categories.

  • SC - In the original version of the Sticker Knight game.  Almost all content is essentially static.  Specifically the level layout.
  • DC - Looking at the game, I can see this content that is dynamic and has critical states:
    • current level
    • player position
    • player health (lives count)
    • gems - were they picked up or not
    • score
    • position of purple blocks (You may actually want to consider these NCDC and reset on each restore)
    • enemies - alive or dead  (You may actually want to consider these NCDC and reset on each restore)
  • NCDC - This would be … nothing unless you take my suggestions above.

Now that you have identified the DC elements, you need to collect the state of each DC element and place that status into a single table for each save (JSON encode the table and save it to ‘disk’). 
 
Then, later, restore by reading the JSON encoded table from ‘disk’, decoding it, and the for each element in the table, find the particular object in the level and update it.  As well, update all the state data and GUI elements.  Violla!  Done.
 
 
Sure, this is not telling you HOW to do this, but this is essentially the what of game saves and restores.

Update:

The way I would approach this, is:

  1. Look at com/ponywolf/ponytiled.lua and add some code to identify DC objects as they are created, then track all of these elements in a single table( see step #2 below).  You will probably need to tag these object and add some code to them in order to simplify save and restore steps.)

  2. Add some code somewhere else (maybe in main.lua) to:

  • create a blank table (before loading the level).  This is the table where all DC object are tracked on a per-level basis.  You iterate over this table when saving to create a ‘save table’.  You do not directly save this as it has references to objects and display objects cannot be serialized.
  • load the level (this code already exists; this code will then use your mods to populate the table of DC content)
  • load the restore file (if it exists, which it won’t on the initial run)
  • apply the restore deltas.
  1. Also add code to:
  • Create a save table and write it to disk at times you find useful (time based, or at restore points, or at end/start of level, or some combination of all of these)

You may need to modify the objects in the original level file, by tagging them in tiled, but I think you can actually avoid that with a little cleverness.  I say this, because you will know the starting position and type of every DC element, so you can save that as a attribute to help you later identify elements during the restore.

I’d estimate the code needed to add a save/restore system to the base Sticker Knight game to be between 100 and 200 lines of code (or substantially less if you use SSK or other solutions to implement the table save/restore code.)

Amendment to instructions.  

I forgot ponytiled supplies the map:findObject() method.  You could simply add a new method similar to it called findObjects(), then you could do this to find the hero and all gems:

local hero = map:findObject( "hero" ) local gems = map:findObjects( "coin" ) -- I believe the gems use the 'coin' type.

This would make the process even easier.

The code change for ponytiled.lua would look something like this:

-- return all display objects with name -- Optionally pass in an existing table to add the objects to function map:findObjects(name,ret) ret = ret or {} for layers = self.numChildren,1,-1 do local layer = self[layers] if layer.numChildren then for i = layer.numChildren,1,-1 do if layer[i].name == name then ret[#ret+1] = layer[i] end end end end return ret end

hello roaminggamer, thanks for answering my post.

The score I am already saving it like this:

 scene.score:add( 100 )--I'm adding points in each scene --and at the exit, when I collide with the door, I keep them in a json local s = {} s.score = scene.score:get() loadsave.saveTable(s, "score.json", system.DocumentsDirectory)

What I want is to do the same as the score but keeping in a json table the name of the screen I finished, for example: sandbox2.json and then when another day the game starts, I continue it in sandbox2.json:

Something like that but connecting with the table to load sandbox2.json:

 local s = {} s = loadsave.loadTable("game.json", system.DocumentsDirectory) local sandbox = "scene/game/map/game.json" local filename = event.params.map or sandbox local mapData = json.decodeFile( system.pathForFile( filename ) ) map = tiled.new( mapData, "scene/game/map" )

how do you want to make quinohp:

https://forums.coronalabs.com/topic/74368-load-tiled-map-from-a-json-table/

Sorry.  I don’t really understand your question.  

Whatever the case  you’re not going to be modifying the base JSON file.

You’ll make state changes after or while you load the content represented by that file.

Sorry, in the Sticker-Knight game, in exit.lua, this is how you keep the map:

local s = {} s.map = self.map loadsave.saveTable(s, "game.json", system.DocumentsDirectory)

game.json:

{"map":"scene/game/map/sandbox2.json"}

How can I load it later from game.lua?

This is how I load game.lua the map:

local filename = event.params.map or "scene/game/map/sandbox.json" local mapData = json.decodeFile( system.pathForFile( filename, system.ResourceDirectory ) ) map = tiled.new( mapData, "scene/game/map" )

How do I call map from the game.json table so that I can load the sandbox2.json map?

Sorry boss.   Without looking at the game I don’t know.  

Keep digging for now and if I have time I’ll take another look. 

I’m pretty busy however. So, I can’t dig into the code right now.

Ok, thanks roaminggamer

Hello kaylabrownph22! your topic is solved, thanks for your idea:

https://forums.coronalabs.com/topic/74368-load-tiled-map-from-a-json-table/#entry392260

Hello quinohp, you’re welcome, thanks to you. :slight_smile:

All games where you can save the state of the world are similar at the highest-level.  There are essentially three categories of content:
(Note: The terms I use in the following list are non-standard.  i.e. I am making them up for the purpose of this discussion).

  • Static Content ( SC )- This is content that never changes and cannot be affected.  Thus it doesn’t need to be tracked by your save system.
  • Dynamic Content ( DC ) - This content would include things like (may or may not apply in all games):
    • player (location, hit-points, … )
    • various game metrics (current level, coins, …)
    • Changeable aspects of levels (Is a door open or closed, was  puzzle solved or not, …)
    • Environment states (is snowing, is it dark, …)
    • … and so on.
  • Non-Critical Dynamic Content ( NCDC ) - This is content that can be changed, but doesn’t need to be saved.  For example, if your game has a weather system you may want to save the the fact that it is dark and raining, but you don’t need to save the position of each raindrop.  It is OK for those to be in different positions when you restore later.

So, how does this apply to your question?  Well, you need to identify the content from your changed version of Sticker Knights that is in each of these categories.

  • SC - In the original version of the Sticker Knight game.  Almost all content is essentially static.  Specifically the level layout.
  • DC - Looking at the game, I can see this content that is dynamic and has critical states:
    • current level
    • player position
    • player health (lives count)
    • gems - were they picked up or not
    • score
    • position of purple blocks (You may actually want to consider these NCDC and reset on each restore)
    • enemies - alive or dead  (You may actually want to consider these NCDC and reset on each restore)
  • NCDC - This would be … nothing unless you take my suggestions above.

Now that you have identified the DC elements, you need to collect the state of each DC element and place that status into a single table for each save (JSON encode the table and save it to ‘disk’). 
 
Then, later, restore by reading the JSON encoded table from ‘disk’, decoding it, and the for each element in the table, find the particular object in the level and update it.  As well, update all the state data and GUI elements.  Violla!  Done.
 
 
Sure, this is not telling you HOW to do this, but this is essentially the what of game saves and restores.

Update:

The way I would approach this, is:

  1. Look at com/ponywolf/ponytiled.lua and add some code to identify DC objects as they are created, then track all of these elements in a single table( see step #2 below).  You will probably need to tag these object and add some code to them in order to simplify save and restore steps.)

  2. Add some code somewhere else (maybe in main.lua) to:

  • create a blank table (before loading the level).  This is the table where all DC object are tracked on a per-level basis.  You iterate over this table when saving to create a ‘save table’.  You do not directly save this as it has references to objects and display objects cannot be serialized.
  • load the level (this code already exists; this code will then use your mods to populate the table of DC content)
  • load the restore file (if it exists, which it won’t on the initial run)
  • apply the restore deltas.
  1. Also add code to:
  • Create a save table and write it to disk at times you find useful (time based, or at restore points, or at end/start of level, or some combination of all of these)

You may need to modify the objects in the original level file, by tagging them in tiled, but I think you can actually avoid that with a little cleverness.  I say this, because you will know the starting position and type of every DC element, so you can save that as a attribute to help you later identify elements during the restore.

I’d estimate the code needed to add a save/restore system to the base Sticker Knight game to be between 100 and 200 lines of code (or substantially less if you use SSK or other solutions to implement the table save/restore code.)

Amendment to instructions.  

I forgot ponytiled supplies the map:findObject() method.  You could simply add a new method similar to it called findObjects(), then you could do this to find the hero and all gems:

local hero = map:findObject( "hero" ) local gems = map:findObjects( "coin" ) -- I believe the gems use the 'coin' type.

This would make the process even easier.

The code change for ponytiled.lua would look something like this:

-- return all display objects with name -- Optionally pass in an existing table to add the objects to function map:findObjects(name,ret) ret = ret or {} for layers = self.numChildren,1,-1 do local layer = self[layers] if layer.numChildren then for i = layer.numChildren,1,-1 do if layer[i].name == name then ret[#ret+1] = layer[i] end end end end return ret end

hello roaminggamer, thanks for answering my post.

The score I am already saving it like this:

 scene.score:add( 100 )--I'm adding points in each scene --and at the exit, when I collide with the door, I keep them in a json local s = {} s.score = scene.score:get() loadsave.saveTable(s, "score.json", system.DocumentsDirectory)

What I want is to do the same as the score but keeping in a json table the name of the screen I finished, for example: sandbox2.json and then when another day the game starts, I continue it in sandbox2.json:

Something like that but connecting with the table to load sandbox2.json:

 local s = {} s = loadsave.loadTable("game.json", system.DocumentsDirectory) local sandbox = "scene/game/map/game.json" local filename = event.params.map or sandbox local mapData = json.decodeFile( system.pathForFile( filename ) ) map = tiled.new( mapData, "scene/game/map" )

how do you want to make quinohp:

https://forums.coronalabs.com/topic/74368-load-tiled-map-from-a-json-table/

Sorry.  I don’t really understand your question.  

Whatever the case  you’re not going to be modifying the base JSON file.

You’ll make state changes after or while you load the content represented by that file.

Sorry, in the Sticker-Knight game, in exit.lua, this is how you keep the map:

local s = {} s.map = self.map loadsave.saveTable(s, "game.json", system.DocumentsDirectory)

game.json:

{"map":"scene/game/map/sandbox2.json"}

How can I load it later from game.lua?

This is how I load game.lua the map:

local filename = event.params.map or "scene/game/map/sandbox.json" local mapData = json.decodeFile( system.pathForFile( filename, system.ResourceDirectory ) ) map = tiled.new( mapData, "scene/game/map" )

How do I call map from the game.json table so that I can load the sandbox2.json map?

Sorry boss.   Without looking at the game I don’t know.  

Keep digging for now and if I have time I’ll take another look. 

I’m pretty busy however. So, I can’t dig into the code right now.

Ok, thanks roaminggamer

Hello kaylabrownph22! your topic is solved, thanks for your idea:

https://forums.coronalabs.com/topic/74368-load-tiled-map-from-a-json-table/#entry392260

Hello quinohp, you’re welcome, thanks to you. :slight_smile: