SSK2: Coin counting issue

(Note this problem is not about SSK2, it is just a warning that there will be SSK2 calls)

Hello, everyone. I am currently working on having my character collect coins and save the data to the phone. However, I have come across an issue, it seems as if an incorrect number of coins is being saved to the phone. I tested this by adding a print statement and found that the number of coins printed in the console and saved to the text file is different. The picture is posted below.

Here is the code:

 function coin:collision(event) if event.phase == "began" then if event.other.name == "character" then display.remove(self) print("coin collected") coinCount = coinCount + 1 coinText.text = coinCount if io.exists("coin.txt") then local coinCountInt = tonumber(io.readFile("coin.txt")) + 1 local coinCountString = tostring(coinCountInt) io.writeFile(coinCountString, "coin.txt") print(coinCountString) else local coinCountString = tostring(coinCount) io.writeFile(coinCountString, "coin.txt") print(coinCountString) end end end end coin:addEventListener("collision")

It might be something with how I am counting my coins, but the variable being saved to the file is the same one being printed in the console, so I don’t know why the difference occurs.

That looks like a lot of file operations during a short period (within a second) and I guess there might be some overlapping save attempts - while the file is locked by the previous operation or something like that.

If you have lots of coins close to each other, it’s probably a better idea to save the coins count periodically(at checkpoints) or at certain thresholds (like every 10/20/50 coins).

You want to avoid reading from and writing to persistent memory (the disk) that often.

Aside from possible corruption/data loss you will deplete the battery quickly and needlessly.

Here is an alternate solution to minimize actual i/o traffic.

-- Save mechanism with deferment that cancels last outstanding save local lastSave local function saveCoinCount( count ) count = tonumber(count) or 0 if( lastSave ) then timer.cancel(lastSave) end lastSave = timer.performWithDelay( 100, function() lastSave = nil io.writeFile(count,"coin.txt") end ) end

Next, don’t read the coin count AT ALL in the listener.  You should only read that at the beginning of the game and then keep track of it in memory.

Finally, do this in your listener:

 function coin:collision(event) if event.phase == "began" then if event.other.name == "character" then display.remove(self) print("coin collected") coinCount = coinCount + 1 coinText.text = coinCount io.writeFile(coinCountString, "coin.txt") print(coinCountString) saveCoinCount(coinCountString) end end end end coin:addEventListener("collision")

What do you mean by saving the file’s read in memory, like in a runtime listener? because right now, this is not working what so ever. (I know I am doing something wrong)

local currentCoinCount if io.exists("coin.txt") then currentCoinCount = tonumber(io.readFile("coin.txt")) else currentCoinCount = 0 end local lastSave local function saveCoinCount( count ) count = tonumber(count) or 0 if( lastSave ) then timer.cancel(lastSave) end lastSave = timer.performWithDelay( 100, function() lastSave = nil io.writeFile(count, "coin.txt") end ) end function M.create(parent, parent2) --coin creation code function coin:collision(event) if event.phase == "began" then if event.other.name == "character" then display.remove(self) print("coin collected") coinCount = coinCount + 1 coinText.text = coinCount local coinCountInt = currentCoinCount + 1 local coinCountString = tostring(coinCountInt) saveCoinCount(coinCountString) end end end coin:addEventListener("collision") end

What happens is that the number from the previous save is written to the file. So, if the previous save is 14, and I delete the file, as soon as I collect a coin the next time, the save will say 15, and won’t change.

If I change this:

local coinCountInt = currentCoinCount + 1

to this:

local coinCountInt = currentCoinCount + coinCount

It works fine, except for the fact that when the first coin is collected, it starts at 16, or whatever number the previous save was.

Actually, it works well. I just realized there would be no previous save for people if they played it in the beginning. :stuck_out_tongue:

Nevermind and thanks!

That looks like a lot of file operations during a short period (within a second) and I guess there might be some overlapping save attempts - while the file is locked by the previous operation or something like that.

If you have lots of coins close to each other, it’s probably a better idea to save the coins count periodically(at checkpoints) or at certain thresholds (like every 10/20/50 coins).

You want to avoid reading from and writing to persistent memory (the disk) that often.

Aside from possible corruption/data loss you will deplete the battery quickly and needlessly.

Here is an alternate solution to minimize actual i/o traffic.

-- Save mechanism with deferment that cancels last outstanding save local lastSave local function saveCoinCount( count ) count = tonumber(count) or 0 if( lastSave ) then timer.cancel(lastSave) end lastSave = timer.performWithDelay( 100, function() lastSave = nil io.writeFile(count,"coin.txt") end ) end

Next, don’t read the coin count AT ALL in the listener.  You should only read that at the beginning of the game and then keep track of it in memory.

Finally, do this in your listener:

 function coin:collision(event) if event.phase == "began" then if event.other.name == "character" then display.remove(self) print("coin collected") coinCount = coinCount + 1 coinText.text = coinCount io.writeFile(coinCountString, "coin.txt") print(coinCountString) saveCoinCount(coinCountString) end end end end coin:addEventListener("collision")

What do you mean by saving the file’s read in memory, like in a runtime listener? because right now, this is not working what so ever. (I know I am doing something wrong)

local currentCoinCount if io.exists("coin.txt") then currentCoinCount = tonumber(io.readFile("coin.txt")) else currentCoinCount = 0 end local lastSave local function saveCoinCount( count ) count = tonumber(count) or 0 if( lastSave ) then timer.cancel(lastSave) end lastSave = timer.performWithDelay( 100, function() lastSave = nil io.writeFile(count, "coin.txt") end ) end function M.create(parent, parent2) --coin creation code function coin:collision(event) if event.phase == "began" then if event.other.name == "character" then display.remove(self) print("coin collected") coinCount = coinCount + 1 coinText.text = coinCount local coinCountInt = currentCoinCount + 1 local coinCountString = tostring(coinCountInt) saveCoinCount(coinCountString) end end end coin:addEventListener("collision") end

What happens is that the number from the previous save is written to the file. So, if the previous save is 14, and I delete the file, as soon as I collect a coin the next time, the save will say 15, and won’t change.

If I change this:

local coinCountInt = currentCoinCount + 1

to this:

local coinCountInt = currentCoinCount + coinCount

It works fine, except for the fact that when the first coin is collected, it starts at 16, or whatever number the previous save was.

Actually, it works well. I just realized there would be no previous save for people if they played it in the beginning. :stuck_out_tongue:

Nevermind and thanks!