Score saved and loaded on death

Hey thanks for that spot! i glazed over that! i’ve changed it and the errors have gone, but however when the player dies and it then launches the main menu , the score there isn’t loading the supposedly saved score?

Main Menu Script:

local text_nodes = {"score", "score_text"}

function init(self)
	msg.post(".", "acquire_input_focus")

	-- load saved score??
	
	local save_state = sys.load(sys.get_save_file("TestGame", "save_state"))
	if not next(save_state) then
		self.score = 0
	else
		self.score = save_state.score	
	end
	
	
	--- write score into the score text area?
	
	local s = gui.get_node("score")
	gui.set_text(s, self.score) --- your fix you pointed out :) 
	
end

Debug it step-by-step. Before you save it, pprint() the table to make sure it contains what you think it does. Then put in another print to make sure it saved correctly. Then do the same when you load it. Figure it which step is failing.

1 Like

So add in

pprint(self.score)

?.. if so the response i’ve got is DEBUG:SCRIPT: nil DEBUG:SCRIPT: 0
[ sorry if i sound dense, it’s been a bit of a nightmare changing over from unity which i managed to program my head around and it seemed a bit more user-friendly (dummy friendly)

And an example as well: https://defold.com/examples/file/sys_save_load/

Well after using Defold for a while I tried a bit of Unity, and it seemed very user-unfriendly to me! So I guess we’re even, haha.

OK, I think you’ve still got issues with things named incorrectly or trying to access them from the wrong place.

In one of your posts you’re using “scores” and in the other you’re using “score”. Make sure those are consistent.

Next, you’re trying to get the loaded score from “self”, which is not right. Self properties are what you would call “Instance Variables” in Unity/C# I believe? They are specific to each instance of the script that exists when your game is running. The “self” of your main menu script is totally separate from the “self” of your hero script. You’re loading the save score from the main menu script, and you never set 'self.score' to anything in that script, so of course it’s going to be nil.

-- You're loading it into the local variable "save_state". 
local save_state = sys.load(sys.get_save_file("TestGame", "save_state"))

-- So you would access it like this:
print(save_state.score)

pprint(save_state) -- doing this...
-- ...should give you something like this:

DEBUG:SCRIPT: 
{ --[[00000000020DADD0]]
 score = 1
}

Make sure you read the “Lua Programming in Defold” manual (again). Defold will definitely not be user-friendly if you don’t know the basics.

3 Likes

ah ok I get what you mean, this is going to take a lot of re-thinking processes. I figured “self” was like the player prefs… i’ll have to attempt some more reading of the the lua programming… in regards to the place where to save the score, could I maybe make a collection called score manager with a gui in there which saves the score? but then would that have to go in the loader proxy or would that never be loaded in the first place? or would I load it but just not have it visible on screen?.. thank you so much by the way - when (if) I figure this all out I totally need to make a tutorial and quote all you guys

You want a Lua module for that.

1 Like

Riiiight! gotcha! and does it matter where that module is saved/folder structure or is it just directly within the project folder? and does it matter what it’s called? something like ScoreModule? …. just managed to find this… is it pretty much this?

Yeah, you can store it anywhere, but mind you that you need to write out this path when you’re requiring it in a script.

For what you need (though I admit I only skimmed the full thread) just this would suffice:

local M = {score = 0}
return M

Then you can require the module in any script that needs access to the score value:

local m = require("main/modules/ScoreModule")

This is the only place where the name and path of the module matters.

Once you do this, you can access the score value as m.score

2 Likes

thank you so much, my lord ! the shroud has cleared and I can see clearly now the rain has gone! lol feeling hopeful! I cant wait to actually get the main framework of the game sorted so I can start on the fun bit which is the designing :smiley: … one last question… would I need to amend this in any way for facebook leaderboard to read this or would this module be enough for facebook to read the players score and post it to their leaderboard? (need to add in the competitive nature of a leaderboard )

So I think this is what I’ve gathered from all the information:

--- Name tag for lua module
--- “shared_data.module”

local M = {
player  = {
    highscore = 0, 
    score = 0
}
}
return M

and then Score save/load added to loader script


---loader script name 
---loader 

function save_gamedata(self)
-- reset player score
shared_data.player.score = 0
-- save gamedata
if not  sys.save(save_file, shared_data) then
    pprint(“gamedata not saved.”)
end
end

function load_gamedata(self)
    -- load game data
    local gamedata = sys.load(save_file)
    if not next(gamedata) then
        pprint(“gamedata empty”)
    else
        pprint(gamedata)
        Shared_data.player.highscore = gamedata.player.highscore
    end
end

function init(self)
    msg.post(“.”, “acquire_input_focus”)
    load_gamedata(self)
    load_menu(self)
end

function on_message(self, message_id, message, sender)
…
elseif message_id == hash(“game_over”) then
    unload_main(self)
    load_menu(self)
    save_gamedata(self)
msg.post(“/mainmenu#gui”, “update_score”, { score = gamedata.player.highscore }
elseif...
end
end

and finally add a script to the main menu gui script to post the score to the main menu score screen which is where the best score or high score will be shown

function on_message(self, message_id, message, sender)
if message_id == hash(“update_score”) then
-- set the score counter to new score
local score_node = gui.get_node(“score”)
gui.set_text(score_node, “SCORE: “.. message.score)
end
end

…fingers crossed this works (will have to try when i get home)

Backend systems such as Facebook Instant Games, PlayFab etc are very specific about how they read and store data on their servers and what API functions you use to send the data to their servers.

Start with what you have now and you’ll be able to adapt it once you add the backend integration. Don’t try to do everything at once. It will be overwhelming.

1 Like

We should create some super basic tutorials/manuals explaining these kind of things.

  • How do I save a high score between play sessions?
  • How do I save player settings?
  • How do I transition between multiple screens in my game?
  • How do I pause my game?

What else? Please provide ideas of things that you need help understanding!

6 Likes
  • maybe an inventory tutorial? though I guess that’s sort of similar to how scoring is done.
  • Character selection/customisation?
  • maybe an options pause menu where you can adjust things like voume, input options(inverted controls, etc)
  • mini map and pause menu large map with character tracking?
  • Checkpoints?
  • dare i say it …fast travel …though i feel this spoils some gameplay and makes it too easy
1 Like

I guess it’s not super basic, but this problem seems to show up on the forums perhaps more often than anything else.

Just when i think i’m close… :roll_eyes: lol… Seem to be getting this error message on the main menu script: any clues?
Compilation failed: function arguments expected near '…'


function on_message(self, message_id, message, sender)
	if message_id == hash(“update_score”) then
		-- set the score counter to new score
		local score_node = gui.get_node(“score”)
		gui.set_text(score_node, “SCORE: “.. message.score)
	end
end

function on_input(self, action_id, action)
	if(action_id == hash("click") and action.released == true) then
		local textBegin = gui.get_node("textBeginGame")
		if(gui.pick_node(textBegin,action.x,action.y)) then
			msg.post("loader:/go#loader", "start_game")
		end
	end
	if(action_id == hash("click") and action.released == true) then
		local textExit = gui.get_node("textExitGame")
		if(gui.pick_node(textExit,action.x,action.y)) then
			msg.post("@system:", "exit", {code = 0})
		end
	end	

	

end

and this error message on the loader script:

Compilation failed: ‘)’ expected near the ‘#’

function save_gamedata(self)
	-- reset player score
	shared_data.player.score = 0
	-- save gamedata
	if not sys.save("save.txt", shared_data) then
		print("Gamedata not saved")
	end
end
function init(self)
	msg.post(".", "acquire_input_focus")
	load_gamedata(self)
	load_menu(self)
end
function on_message(self, message_id, message, sender)
	if message_id == hash("start_game") then
		unload_menu(self)
		load_main(self)
	end
	if message_id == hash(“game_over”) then
		unload_main(self)
		load_menu(self)
		save_gamedata(self)
		msg.post(“/mainmenu#gui”, “update_score”, { score = gamedata.player.highscore }
	elseif...
end
end

end

I don’t see the source of the first error (there should be line number in the error message) but you’re missing a closing bracket in the second script:

msg.post(“/mainmenu#gui”, “update_score”, { score = gamedata.player.highscore })
1 Like

The first one - It mentions the line at the top where “SCORE:” is … good spot on the main menu code ta! I should have known coming from unity which needs endless amounts of brackets … whoops!

Managed to solve the issue now :slight_smile: …though now for some reason when I load the loader script as the first window, I cant seem to click on any of my buttons, there is no error message showing, but the start game and exit game buttons don’t want to work now, it doesn’t register any clicks…the only message I get on the console is the "pprint(“gamedata empty”) so unless that has anything to do with it…but it’s not coming up as an error?

Did you acquire input focus in the loader as well? If the other screens are loaded via collection proxies their “parent” also needs input focus.

1 Like