Document stub.png This article or section may not have content matching Scratch Wiki editing standards. Please improve it according to Scratch Wiki:Guidelines and Scratch Wiki:Editing Conventions. (August 2018)
Reason: generally inaccurate, unprofessional, and potentially misleading
The act of saving data is to record a variable or a list in a Scratch project so it can be read, or used at a later time.

Saving Data in Lists

With the introduction of lists in Scratch 1.3, it is now easier to create projects that incorporate this function. When you right-click a list it gives options to import or export the list. This creates a .txt file of the list in the desired location.

Pros

The ability to save your progress in a game is an extremely useful tool for game developers. Some of the benefits are:

  • Ability to leave a game and pick up at the same point as you left off.
  • Ability to create your own game files.
  • Creators can more easily modify and upgrade their projects.
  • Players can customize certain aspects of the game.

Cons

Although saving data from the game can be very useful, there are also some problems:

  • If the scripts are not well written, the project will not perform correctly.
  • Players can easily edit the .txt file to "hack" the game.
  • Players can customize certain aspects of the game not meant to be customized.
  • Players that are not knowledgeable in Scratch might get easily confused.

How to Prevent Problems

There are several ways to try and prevent the above cons from happening:

  1. Test your save scripts multiple times. Ensure they work under all circumstances.
  2. Make sure that users download your project and not play it online. This can be done with the obsolete block.
  3. You can attempt to encrypt or code your list so that only the computer can decipher your saved data. This, however, is extremely time-consuming as well as difficult to do.
  4. Try not to label the items in your save list; labeling them makes it easier for hackers to correctly edit their saves.
  5. You can use a mathematical checker to only allow logical data.
  6. Include detailed instructions on how the game works for new players so that they can understand exactly how to play it.

Examples

Tutorial

This tutorial will go over making a simple save system which stores values in a list.

All the data will be stored in a single string which will be put back into the project at a later date to load the old data the player had.

To start, make a list called "Save Data". Next, make the following custom block which will save data:

define save (value)
add (join (value) [;]) to [Save Data v]

You can then make a script to save any variables you want:

save (x position) :: custom
save (health) :: custom
save (money) :: custom

The next step is to give the save code to the user so they can enter it in later. First, you want to make a variable called code. You might want to put when "s" key pressed save data or when space key pressed etc. The coding might look like this with the save blocks on top :

save (x position) :: custom
save (health) :: custom
save (money) :: custom
set [code v] to [] //Make sure there is nothing inside the second input
repeat until <(length of [Save Data v]) = [0]>
set [code v] to (join (code) (item (1 v) of [Save Data v]))
delete (1 v) of [Save Data v]
end
add (code) to [Save Data v]
show list [Save Data v]

The user can then export the list or copy and paste the code somewhere.

Finally, the user needs to be able to load data. Make a list called "Loaded Data" and a variable called "i", then make the following custom block:

define load data (data)
set [i v] to [1]
set [value v] to [] //Make sure the second input is blank
repeat until <(i) > (length of (data))>
repeat until <(letter (i) of (data)) = [;]>
set [value v] to (join (value) (letter (i) of (data)))
change [i v] by (1)
end
add (value) to [Loaded Data v]
change [i v] by (1)
set [value v] to [] //Make sure the second input is blank
end

Now you simply need to load the data in the order that you saved it. You first ask the player for their save code, then load the data, and then store the loaded data. So for the above example where "x position" is stored, then "health", then "money". The loading script would look like this:

ask [Save code?] and wait
load data (answer) :: custom
set x to (item (1 v) of [Loaded Data v])
set [health v] to (item (2 v) of [Loaded Data v])
set [money v] to (item (3 v) of [Loaded Data v])

If you get lost you can look here for help: https://scratch.mit.edu/projects/56698396/

Saving Data in Lists

Note Caution: This method of saving data has not been tested or confirmed. Use this method at your own risk.

This is another way for saving using lists. This method can work with projects that aren't compatible with the standard way.

Pros

  • Ability to leave a game and pick up at the same point as you left off.
  • Ability to create your own game files.
  • Creators can more easily modify and upgrade their projects.
  • Players can customize certain aspects of the game.
  • Very hard to hack.

Cons

  • If players know what to do, it can be hacked and can customize certain aspects of the game not meant to be customized.
  • Players might get easily confused.

How to Prevent Problems

There are several ways to try and prevent the above cons from happening:

  1. Test your save scripts multiple times.
  2. Include detailed instructions on how the game works for new players so that they can understand exactly how to play it.
  3. You can change it to use random numbers that the project will understand and confuse hackers.

Tutorial

This tutorial will go over making a simple save system which stores values in a list.

All the data will be stored in a single string which will be put back into the project at a later date to load the old data the player had.

Saving Data

First Make a 2 lists called Save Data and Load Data. Make it so when an event occurs it shows the list:

when [p v] key pressed
show list [Save Data v]

Assemble the blocks to add the data:

when [p v] key pressed
show list [Save Data v]
insert (Levels Completed) at (1 v) of [Save Data v]

To prevent persons from changing the program, you can add a set of numbers to encrypt the data.

when [p v] key pressed
show list [Save Data v]
insert ((Levels Completed) * (6524353128471)) at (1 v) of [Save Data v] // this can be any number of your choice.
insert ((Item 1) * (6524353128471)) at (2 v) of [Save Data v]

Now to finish of saving we will ask if they have finished saving:

when [p v] key pressed
show list [Save Data v]
insert ((Levels Completed) * (6524353128471)) at (1 v) of [Save Data v]
insert ((Item 1) * (6524353128471)) at (2 v) of [Save Data v]
 ask [Done saving?] and wait
  if <<(answer) = [Yes]> or <(answer) = [Y]>> then
    hide list [Save Data v]
end

Loading Data

Ask the person to see if they would like to load their saved game.

if <<(answer) = [Yes]> or <(answer) = [Y]>> then
  show list [Load Data v]
wait (4) secs
  ask [Done loading?] and wait
  if <<(answer) = [Yes]> or <(answer) = [Y]>> then
    hide list [Load Data v]
end


If the user confirms, then have the data load.

if <<(answer) = [Yes]> or <(answer) = [Y]>> then
  show list [Load Data v]
 wait (4) secs
  ask [Done loading?] and wait
  if <<(answer) = [Yes]> or <(answer) = [Y]>> then
    hide list [Load Data v]
set [Levels Completed v] to ((item (1 v) of [Load Data v] :: list) / (6524353128471)) // Make sure to have this number exactly the same in the previous scripts.
    set [Item 1 v] to ((item (2 v) of [Load Data v] :: list) / (6524353128471))
    broadcast [Game Start v]
end

Saving Data with Encryption

Another method for saving data in Scratch is through the use of encryption. With this method, the user is prompted to enter a code when the game starts and is given a new code when they wish to leave. These codes can be used to determine where in the game players left off. For example, let's say that you were playing a scrolling game and you had 2 lives left and 5 cash. When you saved the game, you would get a code of 25. When you resumed the game, it would set your lives to the first letter of the code and set your cash to the second letter.

Pros

This method of saving your game can be just as effective, if not more effective than the first method listed. Here are some benefits of this method as compared to it:

  • It works online and offline.
  • Codes can be used on any computer.
  • The scripts are simpler.

Cons

Although this method is a great way to save games, it does have quite a few cons:

  • The player has to remember or write down the code. This can be very annoying for the player as some advanced games could involve codes with as many as 20-30 characters!
  • Unless you have great experience with encrypting and decrypting files, your codes may be very easy to crack. This can allow players to modify their saves with ease.
  • Players may share "cracked" codes with other players, allowing others to cheat on your game.
  • This method is difficult to use in situations involving numbers with a wide range. A player's money could reach heights of millions, so programming a script that would understand how to deal with any value for these numbers could be very tedious and time consuming.

How to Prevent Problems

  1. Try to make codes as short as possible or show the code in a list so users can copy and paste the code.
  2. Leave instructions on how to use the code in the project notes.
  3. Encrypt your codes.
  4. Have all valid codes fall under a single mathematical equation and all codes checked with it - some false codes may go against the equation and will therefore not be accepted.
  5. Have a number form of the user's username who saved it added to the front of the code so that when a user loads it, it will decrypt the code to see if it matches with username, therefore, having it almost impossible to trade codes with other players.
  6. Make sure that your scripts will work for very long codes with a range of values.

Examples

Saving Data in Variables

Another method to save data is through variables. When you save your project, all the current variable values are saved. This is one of the most popular methods as it is easy and straight forward. It is easy for the player to save their progress. The project creator although, has to create a way to initiate the saved variables when the game starts.

Pros

This method is most commonly used because:

  • It is quick and easy for the player.
  • It is easy for the Scratcher to do, even with little knowledge.

Cons

Despite how easy it might seem, this method has a con: It cannot be used on online project players.

How to Prevent Problems

  1. Try to "hide" your variables so people will not try and change them
  2. Use a mathematical checker so that people do not change the variables.
  3. Make sure that your project calls on the variables before the game starts so that the data is properly restored.
  4. Test the project to ensure that this method works with your project and the code works to restore a saved game.

Example

SynOS 7: Purple Crystal by 08jackt

Saving Data in the Cloud

Main article: Cloud Data
See also: Global High Scores

Cloud data is stored in the "cloud", or on the Scratch server, meaning it is stored on the web. Cloud data does not reset when you view a project; it gets globally updated by anyone changing the cloud variable. For example, if User A views a project and changes the variable from "1" to "2" when User B views the project, the variable will stay as "2". The variables globally update, with the speed of typically 2 seconds with a Firewall on to update the value. Storing data on the cloud is difficult, as Scratch 2.0 has disabled strings to be saved on cloud temporarily.

This is typically accomplished by creating two cloud lists. The first is a list of users who have stored data. The second is a list with the saved data, corresponding to the users in list number 1.

Pros

  • No need to remember or write down any codes or encrypted text.
  • Data can be loaded back after clicking the green flag.
  • Data can be stored separately for each individual Scratcher

Cons

  • If cloud data were to be lost in any way, all saves would be gone.
  • There is a limit of how many people can use it
  • Cloud data can be confusing to use

How to Prevent Problems

  1. Test out the cloud data system, before publishing a project with cloud saving in it.
  2. Include a backup variable to store information on.

Saving an Inventory

Inventories can be a crucial part in any game (A game which has an inventory, of course) and saving/loading scripts are a bit tricky for new scratchers with limited knowledge. Here you will see a way you can implement inventories into your games.

Note Note: There are numerous ways to implement inventories - this article just demonstrates one way.

Getting Started

First, you need a list to save a player's inventory data. You can create a list called 'Inventory' or 'Inv' or anything you like. This list will store the 'Item Id's' that are used to identify certain items.

For example:

switch costume to (item (current_itemID_looking_at_in_the_list) of [inventory v])
stamp

You will also need a variable that contains a certain code that a script will read and divide into separate item id's to add to your inventory. Name this variable something like 'InventorySaveCode' or just 'InvSav'. Finally, create a variable called 'ItemCount' or anything similar.

Saving Your Inventory

In this step, you will learn how to take all the item id's from the list and make it into a single variable. First, we want to know how many items we have in the inventory list to determine how many time we will take a certain number from that list and add it to the inventory save variable. To do this, simply add the code:

repeat (length of [inventory v])

This will repeat the action of adding the item id's from the list to the inventory save variable (we will put that code in later) the number of items there is in the inventory list. Now, let's add the code that adds the item id from the list to the inventory save variable. To do so add this code in the repeat block we've just added.

set [inventory_save_variable v] to (item (1 v) of [inventory v])

So all the code should look like:

repeat (length of [inventory v])
set [inventory_save_variable v] to (item (1 v) of [inventory v]) 

If you had not noticed, something's wrong with this code. The repeat block repeats adding item 1 of the inventory, and none of the other items. To fix this, we need to use the 'ItemCount' variable we created earlier. The first code we will put in is setting the item count to 1 before we start repeating to add the items from the inventory list. This simply makes it so the code will review the first item in the inventory list first. For example:

set [item_count v] to [1]
repeat (length of [inventory v])
set [inventory_save_variable v] to (item (1 v) of [inventory v]) 

We also need to make it so it actually reviews the value of 'item count', so change the 'set inventory save variable to item 1 of inventory' code to 'set inventory to save variable to item item_count of inventory'. Then, add a join block after the 'set inventory save variable to' so its 'set inventory save variable to join [] ['item item_count of inventory']

set [inventory_save_variable v] to (join [] (item (item_count) of [inventory v])

Finally, put the inventory save varible in the empty space of the join block.

set [inventory_save_variable v] to (join (inventory_save_variable) (item (item_count) of [inventory v])

Next, to make the piece of code review the next item, add this piece of code after the 'set inventory save variable to item item_count of inventory' block.

change [item_count v] by (1)

Altogether: you should have this code:

set [item_count v] to [1]
repeat (length of [inventory v])
set [inventory_save_variable v] to (join (inevntory_save_variable) (item (item_count) of [inventory v])
change [item_count v] by (1)

As you can see, the script adds all item id's to the inventory save variable, but one problem is that the id's are all connected together so its just one big string of numbers and there is nothing to identify any single id. to stop this, simply place this block in above the 'change item count' block. Also, add a block underneath the 'set item count' block to clear the save data before it loads (so you do not have a huge string of different saves)

set [item_count v] to [1]
set [inventory_save_variable v] to []
repeat (length of [inventory v])
set [inventory_save_variable v] to (join (inevntory_save_variable) (item (item_count) of [inventory v])
set [inventory_save_variable v] to (join (inventory_save_variable) [:]
change [item_count v] by (1)

This piece of code separates each item id with a colon so you can load the save data.

Now, your final saving code should look like this:

set [item_count v] to [1]
set [inventory_save_variable v] to []
repeat (length of [inventory v])
set [inventory_save_variable v] to (join (inevntory_save_variable) (item (item_count) of [inventory v])
set [inventory_save_variable v] to (join (inventory_save_variable) [:]
change [item_count v] by (1)

Loading Your Inventory

This bit will be a bit more tricky, but eventually, we will have a working saving and loading system! First, we will start out by clearing the inventory and setting the item count to one. Simply put this code in:

delete (all v) of [inv_ v]
set [inv_scan/read_count v] to [1]

Now, let's add the repeat block. This time we will repeat the length of the save because that's where we're getting out data from.

repeat (length of (inv_datasave))

Next, Lets add a chunk of code that will determine what the item before the one were viewing is. This will determine whether the item id has two digits or one.

if <(letter (inv_scan/read_count) of (inv_datasave)) = [:]> then
change [inv_scan/read_count v] by (1)
else
change [inv_scan/read_count v] by (1)
if <(letter (inv_scan/read_count) of (inv_datasave)) = [:]> then
change [inv_scan/read_count v] by (-1)
else
change [inv_scan/read_count v] by (-1) 

This code checks if the id is two digits or one and whether the digit its looking at is a colon or number. Next, lets add the pieces of code which add the item id's to the inventory list and the move on to the next digit after.

if <(letter (item_count) of (inventory_save_variable)) = [:]> then
                change [item_count v] by (1)
            else
                change [item_count v] by (1)
                if <(letter (item_count) of (inventory_save_variable)) = [:]> then
                    change [item_count v] by (-1)
                    add (letter (item_count) of (inventory_save_variable)) to [inv_ v]
                    change [item_count v] by (1)
                else
                    change [item_count v] by (-1)
                    add (join (letter (item_count) of (inventory_save_variable)) (letter ((item_count) + (1)) of (inventory_save_variable))) to [inventory v]
                    change [item_count v] by (2)

Finally, add this code which cleans up all errors after the loading of the inventory

if <(letter (item_count) of (inventory_save_variable)) = [:]> then
                change [item_count v] by (1)
            else
                change [item_count v] by (1)
                if <(letter (item_count) of (inventory_save_variable)) = [:]> then
                    change [item_count v] by (-1)
                    add (letter (item_count) of (inventory_save_variable)) to [inv_ v]
                    change [item_count v] by (1)
                else
                    change [item_count v] by (-1)
                    add (join (letter (item_count) of (inventory_save_variable)) (letter ((item_count) + (1)) of (inventory_save_variable))) to [inventory v]
                    change [item_count v] by (2)
if <(length of [inv_ v]) > [10]> then
                        repeat ((length of [inv_ v]) - (10))
                            delete (last v) of [inv_ v]

Saving Final Code

set [item_count v] to [1]
set [inventory_save_variable v] to []
repeat (length of [inventory v])
set [inventory_save_variable v] to (join (inevntory_save_variable) (item (item_count) of [inventory v])
set [inventory_save_variable v] to (join (inventory_save_variable) [:]
change [item_count v] by (1)

Loading Final Code

repeat (length of (inventory_save_variable))
if <(letter (item_count) of (inventory_save_variable)) = [:]> then
                change [item_count v] by (1)
            else
                change [item_count v] by (1)
                if <(letter (item_count) of (inventory_save_variable)) = [:]> then
                    change [item_count v] by (-1)
                    add (letter (item_count) of (inventory_save_variable)) to [inv_ v]
                    change [item_count v] by (1)
                else
                    change [item_count v] by (-1)
                    add (join (letter (item_count) of (inventory_save_variable)) (letter ((item_count) + (1)) of (inventory_save_variable))) to [inventory v]
                    change [item_count v] by (2)
if <(length of [inv_ v]) > [10]> then
                        repeat ((length of [inv_ v]) - (10))
                            delete (last v) of [inv_ v]