Jump to content

[TOPIC: topicViewTemplate]
[GLOBAL: userSmallPhoto]
Photo

Json trouble saving highscore
Started by Davy1222 Sep 27 2019 05:39 PM

13 replies to this topic
[TOPIC CONTROLS]
[/TOPIC CONTROLS]
[modOptionsDropdown]
[/modOptionsDropdown]
[reputationFilter]
[TOPIC: post.html]
#1

Davy1222

[GLOBAL: userInfoPane.html]
Davy1222
  • Enthusiast

  • 38 posts
  • Corona SDK

So after reviewing https://docs.coronalabs.com/tutorial/data/jsonSaveLoad/index.html#savingloading-tables-to-json for awhile in order to come up with a way to save high score I came up with this code.

local newScore = {
	score
	}


loadsave.saveTable( newScore, "NewScore.json" )		


local scoreTable = {
	score
	}


loadsave.saveTable( scoreTable, "scoreTable.json" )

local newScore2 = {
	score 
	}


if( loadsave.loadTable( scoreTable, "scoreTable.json" ) > loadsave.loadTable( newScore, "NewScore.json" )) then

	loadsave.saveTable( newScore2, "NewScore2.json" )		
end


In this, scoretable is essentially going to be the score, newscore = the previous score, and newscore2 = the final score.

The issue with this code is I cannot save a high score (newscore2) unless I compare scoretable (the score) to newscore (the previous score), but that brings me to the error "cannot compare two nil values."

 

I've learned on here that to be nil means to not exist, but I am not sure how they don't exist thus I am not sure how to make them exist.

 

I tried adding

local saveTable = loadsave.saveTable()
local loadTable = loadsave.loadTable()

to the beginning of my game.lua, but to no avail.

 

And I also tried comparing them solely as

if( scoreTable >  newScore ) then

	loadsave.saveTable( newScore2, "NewScore2.json" )		
end

but that gives me the error "attempt to compare two table values."

 

So essentially my question is, am I going about saving my high score in the right way?

And how would I compare scoreTable and newScore?



[TOPIC: post.html]
#2

sporkfin

[GLOBAL: userInfoPane.html]
sporkfin
  • Contributor

  • 596 posts
  • Corona SDK

Hi @ Davy1222, I think the first thing to address is your table structure.

 

It should look more like this

local newScore = {
     score = 0
}

just "score" by itself doesn't mean anything.  For a proper table you need a key ("score") and a value ( 0 ).



[TOPIC: post.html]
#3

sporkfin

[GLOBAL: userInfoPane.html]
sporkfin
  • Contributor

  • 596 posts
  • Corona SDK

The error you received is because you have asked for a comparison of two tables instead of the values inside the tables.

 

newScore should be a local value not a stored table value - I'm going to call it currentScore

-- create and save your initial high score which which is inside scoreTable
local scoreTable = {
     highScore = 0
}
-- save scoreTable to JSON as scoreTable.json
loadsave.saveTable( scoreTable, "scoreTable.json" )
 
-- create a current score variable
local currentScore = 0 -- adjust this as it changes during the game
 
-- load your saved scoreTable into a local table called "scores"
local scores = loadsave.loadTable( "scoreTable.json")
 
-- make your comparison - currentScore vs. the highScore which is inside the scores table (which was loaded from scoreTable.json)
if currentScore > scores.highScore then
    scores.highScore = currentScore
    -- save scores to JSON as scoreTable.json
    loadsave.saveTable( scores, "scoreTable.json" )
end
-- so your saved scores will always be in "scoreTable.json" but when we load them locally they are called scores
 

 

Give this a try, forgive any typos.



[TOPIC: post.html]
#4

Davy1222

[GLOBAL: userInfoPane.html]
Davy1222
  • Enthusiast

  • 38 posts
  • Corona SDK

The error you received is because you have asked for a comparison of two tables instead of the values inside the tables.

 

newScore should be a local value not a stored table value - I'm going to call it currentScore

-- create and save your initial high score which which is inside scoreTable
local scoreTable = {
     highScore = 0
}
-- save scoreTable to JSON as scoreTable.json
loadsave.saveTable( scoreTable, "scoreTable.json" )
 
-- create a current score variable
local currentScore = 0 -- adjust this as it changes during the game
 
-- load your saved scoreTable into a local table called "scores"
local scores = loadsave.loadTable( "scoreTable.json")
 
-- make your comparison - currentScore vs. the highScore which is inside the scores table (which was loaded from scoreTable.json)
if currentScore > scores.highScore then
    scores.highScore = currentScore
    -- save scores to JSON as scoreTable.json
    loadsave.saveTable( scores, "scoreTable.json" )
end
-- so your saved scores will always be in "scoreTable.json" but when we load them locally they are called scores
 

 

Give this a try, forgive any typos.

I tried this, and it does work. However it only works if I manually change the value of currentscore which does not update on its own.

The next step may be to make my score value not nil and use that instead of curentscore but I'm not sure how to do that when I've already defined it.

Or maybe theres a way to update the currentscore alongside the score without making it nil?

 

I have this at the top of game.lua

local score = 0

local score = require( "score" )

local scoreText = score.init(
{
    fontSize = 40,
    x = 130,
    y = 130,
    maxDigits = 7,
    leadingZeros = false
})




[TOPIC: post.html]
#5

sporkfin

[GLOBAL: userInfoPane.html]
sporkfin
  • Contributor

  • 596 posts
  • Corona SDK

Yes, you would have to update the currentScore value in your game logic - which is normal.

 

I'm not sure what this is about (see below)

You are requiring a module called "score" but what does that do.  Please show the code for the score module

 
local score = require( "score" )
 
local scoreText = score.init(
{
    fontSize = 40,
    x = 130,
    y = 130,
    maxDigits = 7,
    leadingZeros = false
})
 

 

 



[TOPIC: post.html]
#6

sporkfin

[GLOBAL: userInfoPane.html]
sporkfin
  • Contributor

  • 596 posts
  • Corona SDK

Whatever variable you are using to track the score would be the currentScore or to update the currentScore variable in the sample I used, just add currentScore = score (score being whatever variable you use to track the current score) before you compare the currentScore to the high score

currentScore = score -- score being whatever variable you are using to track the current score
 
if currentScore > scores.highScore then
    scores.highScore = currentScore
    -- save scores to JSON as scoreTable.json
    loadsave.saveTable( scores, "scoreTable.json" )
end

 

 



[TOPIC: post.html]
#7

sporkfin

[GLOBAL: userInfoPane.html]
sporkfin
  • Contributor

  • 596 posts
  • Corona SDK

@ davy1222, Hey I think you should spend some time analyzing lua tables so you understand their structure more completely.  I think that would solve a bunch of your issues and also help you understand what is going on when you store lua tables as json files.

 

Try lua tables on lua.org

or

lua table in Corona Docs



[TOPIC: post.html]
#8

Davy1222

[GLOBAL: userInfoPane.html]
Davy1222
  • Enthusiast

  • 38 posts
  • Corona SDK

@ davy1222, Hey I think you should spend some time analyzing lua tables so you understand their structure more completely.  I think that would solve a bunch of your issues and also help you understand what is going on when you store lua tables as json files.

 

Try lua tables on lua.org

or

lua table in Corona Docs

 

I understand the tables better now and I've figured out where I went wrong.

I was supposed to set local currentScore = score.get() instead of just score, which is from my score.lua.(https://docs.coronalabs.com/tutorial/games/keepScores/index.html)

 

But the only problem is now is that the currentScore is saved no matter what instead of remaining the higher number.



[TOPIC: post.html]
#9

sporkfin

[GLOBAL: userInfoPane.html]
sporkfin
  • Contributor

  • 596 posts
  • Corona SDK

You might be comparing the currentScore to something that is nil or not indexed correctly or a table instead of a value.  Can you show us the code?



[TOPIC: post.html]
#10

Davy1222

[GLOBAL: userInfoPane.html]
Davy1222
  • Enthusiast

  • 38 posts
  • Corona SDK

You might be comparing the currentScore to something that is nil or not indexed correctly or a table instead of a value.  Can you show us the code?

in game.lua i have 

local composer = require( "composer" )
local loadsave = require( "loadsave" )
local score = require( "score" )

-- here you declare all your local variables:

local score = 0
local highscore = 0

local scoreText = score.init(
{
    fontSize = 40,
    x = 130,
    y = 130,
    maxDigits = 7,
    leadingZeros = false
})


local function onCollision(event)
	if event.phase == "began" then
		print "collision happened"
		
		composer.gotoScene( "gameover",{ time=400, params=score } )
		
		score.save()
end


-- here i have your code

local scoreTable = {
     highScore = 0
}

loadsave.saveTable( scoreTable, "scoreTable.json" )
 


local currentScore = score.get()


	
local scorer = loadsave.loadTable( "scoreTable.json")


if currentScore > scorer.highScore then

    scorer.highScore = currentScore
   
    loadsave.saveTable( scorer, "scoreTable.json" )
    

end

and in score.lua i have

local M = {}
 
M.score = 0  -- Set the score to 0 initially
 
function M.init( options )
 
    local customOptions = options or {}
    local opt = {}
    opt.fontSize = customOptions.fontSize or 24
    opt.font = customOptions.font or native.systemFont
    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
 
    local prefix = ""
    if ( opt.leadingZeros ) then
        prefix = "0"
    end
    M.format = "%" .. prefix .. opt.maxDigits .. "d"
 
    -- Create the score display object
    M.scoreText = display.newText( string.format( M.format, 0 ), opt.x, opt.y, opt.font, opt.fontSize )
 
    return M.scoreText

end
 
-- return M

function M.set( value )

	M.score = tonumber(value)
	M.scoreText.text = string.format( M.format, M.score )

end
 
function M.get()
 
    return M.score
end
 
function M.add( amount )
 
    M.score = M.score + tonumber(amount)
    M.scoreText.text = string.format( M.format, M.score )
end
 
-- return M

function M.save()
 
    local saved = system.setPreferences( "app", { currentScore=M.score } )
    if ( saved == false ) then
        print( "ERROR: could not save score" )
    end
end
 
function M.load()
 
    local score = system.getPreference( "app", "currentScore", "number" )
 
    if ( score ) then
        return tonumber(score)
    else
        print( "ERROR: could not load score (score may not exist in storage)" )
    end
end
 
return M

Could this may be because i have all this happening before scene:create,show,hide and destroy?

 

New Discovery: After tweaking a little, I find that moving your entire code before the collision  loads the previous value in the scoreTable.json. So what I've tried now is making your code into 3 parts.

 -- so here i have what saves the previous score
local scoreTable1 = {
     Score = 0
}

loadsave.saveTable( scoreTable1, "scoreTable1.json" )
 

local currentScore = score.get()


local scorer1 = loadsave.loadTable( "scoreTable1.json")


if currentScore > scorer1.Score then

    scorer1.Score = currentScore
    	loadsave.saveTable( scorer1, "scoreTable1.json" )
    	

end



local function onCollision(event)
	if event.phase == "began" then
                print "collision happened"

		composer.gotoScene( "gameover",{ time=400, params=score } )

		
		score.save()
end


-- here I have what saves the current score
local scoreTable2 = {
     Score = 0
}

loadsave.saveTable( scoreTable2, "scoreTable2.json" )
 

local currentScore = score.get()

	

local scorer2 = loadsave.loadTable( "scoreTable2.json")


if currentScore  > scorer2.Score then

    scorer2.Score = currentScore
    -- save scores to JSON as scoreTable.json
    loadsave.saveTable( scorer2, "scoreTable2.json" )	
    	

end



-- here is what determines the high score
local scoreTable3 = {
     highScore = 0
}

loadsave.saveTable( scoreTable3, "scoreTable3.json" )
 

local currentScore = score.get()


	
local scorer3 = loadsave.loadTable( "scoreTable3.json")


if scorer2.Score  > scorer1.Score then

    scorer3.highScore = scorer2.Score
    loadsave.saveTable( scorer3, "scoreTable3.json" )	

elseif scorer2.Score  < scorer1.Score then
    	
    scorer3.highScore = scorer1.Score
    loadsave.saveTable( scorer3, "scoreTable3.json" )	
end



So this works but it only works for a few tries.

Say the score reads 3 first, then these will read

scorer1 = 0

scorer2 = 3

highscore = 3

 

now if I play again and the score reads 1

scorer1 = 3

scorer2 = 1

highscore = 3

 

now again and the score reads 2

scorer1 = 1

scorer2 = 2

highscore = 2

 

So should I try this method and it probably has something more that's needed or needed to be taken away, or will it only ever be efficient for the first 2 games?



[TOPIC: post.html]
#11

sporkfin

[GLOBAL: userInfoPane.html]
sporkfin
  • Contributor

  • 596 posts
  • Corona SDK

try checking the values to see what comes back

print("current score = "..currentScore, "highScore = "..scorer.highScore)

try it in several places to find out what values you are getting



[TOPIC: post.html]
#12

Davy1222

[GLOBAL: userInfoPane.html]
Davy1222
  • Enthusiast

  • 38 posts
  • Corona SDK

try checking the values to see what comes back

print("current score = "..currentScore, "highScore = "..scorer.highScore)

try it in several places to find out what values you are getting

current score doesn't print and highscore only prints every once in awhile



[TOPIC: post.html]
#13

sporkfin

[GLOBAL: userInfoPane.html]
sporkfin
  • Contributor

  • 596 posts
  • Corona SDK

You overwrote your score variable

local score = require( "score" )
-- score can't equal both the score module and your score
 
local score = 0
-- now score = 0 so when you try score.get( ) there is no method to call on.

 

I think you should save everything in one table

 

local scoreTable = {
     player1 = { highScore = 0, currentScore = 0 },
     player2 = { highScore = 0, currentScore = 0 },
     player3 = { highScore = 0, currentScore = 0 }
}

 

Keep all your scores local and only save them to the JSON file periodically instead of all the time.

Make all of your game logic and score comparisons local.  Get that working first, then add on the JSON storage.

 

Everything you are trying to achieve is doable, it's just going to take some time to sort in all out and you'll learn a lot on the way.



[TOPIC: post.html]
#14

sporkfin

[GLOBAL: userInfoPane.html]
sporkfin
  • Contributor

  • 596 posts
  • Corona SDK

Also, in the beginning, use very descriptive variables like 

local player1_HighScore = 0
local player1_CurrentScore = 0
local player2_HighScore = 0
local player2_CurrentScore = 0
local player3_HighScore = 0
local player3_CurrentScore = 0

later on, you can replace them with shorter variables but for now, they will help keep you on track




[topic_controls]
[/topic_controls]