A SWF file can save data (variables as well as array, XML, and other data objects) to a user's hard drive using shared objects similar to but more powerful than the cookies used by Web browsers: You can use them to store information generated by the user while viewing your movie (name, last frame visited, music preference, and more). Shared objects can be used by movies played in a Web browser, as well as those turned into stand-alone projectors. NOTE You can also use shared objects with Flash Application Services provided by Macromedia (visit macromedia.com for details on Flash Application Services). Here's an example of a script you might use to create a shared object: myObject = SharedObject.getLocal("stuff_I_saved"); If the shared object "stuff_I_saved " already exists on the user's hard drive, its data is loaded instantly into myObject. If "stuff_I_saved" does not yet exist, it is created and still referenced by myObject. In the latter case, myObject would be empty that is, it would contain no data. NOTE To clarify, as used above, the getLocal() method will either create a shared object (if one doesn't exist) or retrieve data from an existing shared object. As you can see from the above syntax, the shared object's name is actually "stuff_I_saved". However, in ActionScript you can't reference the shared object directly using that name; thus, a reference to the shared object is created using myObject. This means that whenever you reference myObject in a script, you're actually referencing the shared object named "stuff_I_saved" a tricky concept but essential to understanding how ActionScript deals with shared objects. Data is saved to a shared object using the data property. Take a look at the following example: myObject.data.userName = userName.text; This would save the userName variable (and its value, the text in the userName text field) in the shared object. You can save entire objects as well. For example, if you wanted to save an array contained by your project, you would use the following syntax: myObject.data.savedArray = nameOfArray; A single shared object can contain multiple bits of data simultaneously: myObject.data.savedArray = nameOfArrayObject; myObject.data.savedXML = nameOfXMLObject; myObject.data.userName = userName.text; A particular piece of data can be erased from a shared object using null , as in the following example: myObject.data.userName = null; If userName were a piece of data in the shared object, the above script would delete it. Extracting data from a shared object is similar to creating data in one: userName.text = myObject.data.userName; The above script will display, in the userName text field, the value of userName in the shared object. If this variable doesn't exist in the shared object, the value displayed in the text field will be "undefined." When the SWF session ends (that is, the movie is closed or exited), all the information under the data property of your shared object is automatically written to the shared object file, ready to be retrieved using the getLocal() method described earlier. You can force a shared object to be written and saved at any time by using the flush() method. For example: myObject.flush(); The above line of ActionScript forces your shared object and all the data it contains to be saved. Since myObject references the shared object named "stuff_I_saved", this is the object that will actually be saved. Flash stores all shared objects in a central location on the user's hard drive the exact location will depend on where the movie that created them resides (more on this in a moment). On Windows, all shared objects are stored in the following general directory: Windows\Application Data\Macromedia\Flash Player\ On a Mac, the location is: System Folder\Preferences\Macromedia\Flash Player\ These are both general paths that is, when a movie creates a shared object, a new subdirectory is created at one of the above locations. For example, if you were to view a movie at the following URL: http://www.electrotank.com/fun/games/MiniGolf.swf Any shared object created by this movie would, by default, be saved at the following path on a Windows machine: Windows\Application Data\Macromedia\Flash Player\electrotank.com\fun\games\MiniGolf Notice how this subdirectory's path structure matches that of the URL. Because movies played locally (such as projectors) don't exist at a URL, Flash will save shared objects that they create to a localhost directory: Windows\Application Data\Macromedia\Flash Player\localhost All these directory paths are default paths where shared object data is stored. You actually have a lot of latitude as to where a shared object is stored or retrieved from within the general directory. Using the previous example, imagine playing a movie at the following URL: http://www.electrotank.com/fun/games/MiniGolf.swf This movie has the following shared object: myScores = SharedObject.getLocal("scoreData"); When this shared object is saved, it is saved at the following path in Windows: Windows\Application Data\Macromedia\Flash Player\electrotank.com\fun\games\MiniGolf\scoreData.sol Flash will look for this same location again when the movie is played from that URL. However, the getLocal() method lets you add an optional directory path where the shared object should be saved and looked for. Assuming the movie at the aforementioned URL has a shared object declaration of the following: myScores = SharedObject.getLocal("scoreData", "/fun"); The shared object would be saved to (and looked for) at the following path: Windows\Application Data\Macromedia\Flash Player\electrotank.com\fun\scoreData.sol Armed with this knowledge, you can create movies at different locations that use the same shared object useful if you want all of the movies on your site to reference a "master" shared object containing information about the user. Simply save a shared object in the main directory ("/"). NOTE Be careful when using a single shared object across movies: Any one of the shared objects has the potential of overwriting the data it contains with new data. A single movie can create, save, and load multiple shared objects simultaneously. TIP You can configure the amount of data that a given URL can store by using the Flash player. If you right-click on the window of an open SWF and select Settings, you will see the Local Storage controls. You can block any site from storing information on your machine. NOTE A bonus file called highscorelist.fla has been included on the CD-ROM in the folder for this lesson. It offers a complex but useful way to store game scores locally and by so doing enables multiple users of the same computer to have their scores saved and then returned in order. You can use the custom-created highScoreList object defined in this file to control the list. Among other things, you can sort the list by ascending or descending scores, delete the list, edit a score, start a new list, or add a score to the list. In this exercise, you'll create a journal that saves text entries in an array as a shared object. -
Open journal1.fla in the Lesson11/Assets folder on your CD-ROM. You will notice one frame with four layers, which are named according to their contents. The stage contains two text fields that will be used to display information. The large one in the center, journalBody, will be used for journal entries. The smaller text field at the bottom of the screen, entryNumber, will be used to display the current journal entry number. The Buttons layer contains Prev, Next, New, and Save buttons. This application will allow you to start a new journal entry, save it, and browse through the entries you've created. -
With the Actions panel open, select Frame 1 in the Actions layer and add this script: myJournal = SharedObject.getLocal("JournalObject"); This line of ActionScript creates a reference to the shared object JournalObject . This object can be read and modified using the myJournal reference set up here. Thus, in the following scripts, when using myJournal , we're actually working with the shared object named JournalObject . -
Add this conditional statement just below the line of script you added in the previous step: if (myJournal.data.journal == undefined) { myJournal.data.journal = []; } This statement looks in the shared object for an array named journal . If it doesn't find one (undefined ), the action within the statement creates it. NOTE If an array is created, it automatically becomes part of the shared object when the movie is exited or the shared object is saved. The journal array will only appear undefined the first time the movie is played. Each subsequent time the movie is played, the array will exist and thus this action will be ignored. TIP It's a good idea to check for undefined data values in a shared object, as shown above. This allows you to assign default values the first time a movie is played by the user. -
Add this function definition at the end of the current script: function displayEntry(num) { _root.entryNumber.text = num; _root.journalBody.text = myJournal.data.journal[num - 1]; } This function does two things: It sets the value of two text fields on the stage entryNumber and journalBody based on the value of num . For example, if num had a value of 1 when the function was called, "1" would appear as the current entry number in the entryNumber text field. The second line in the function uses the value of num to determine which entry in the journal array (of the shared object) to display in the journalBody text field. Still assuming that num has a value of 1, this line of script could be broken down to read as follows: _root.journalBody.text = myJournal.data.journal[1 - 1]; or _root.journalBody.text = myJournal.data.journal[0]; The reason for subtracting 1 from the value of num in this expression is because what is shown as entry "1" in the entryNumber text field is actually the 0th element in the journal array. Thus, the conversion is necessary to keep the two elements in sync. We could have just made the first entry "0", but that doesn't make sense. With this in mind, it's important to understand that other entry numbers and array elements follow the same sequence (entry "3" is array element 2, and so on). Several of the scripts that follow employ similar logic. -
Add this function call to the end of the current script: displayEntry(myJournal.data.journal.length); Since this function call exists on Frame 1, it's executed as soon as the movie plays. The displayEntry() function (which we defined in the previous step) is called and passed a value based on the length value of the journal array in the shared object. This will display the final entry the user made before exiting the movie. For example, if the journal array has three entries, the displayEntry() function is passed a value of 3 and the third journal entry is displayed. If the journal array has just been created (as described in Step 3), it will contain a single, empty element thus, a length of 1 gets sent to the function. -
Next, add the following function definition to handle saving data: function save() { var num = Number(_root.entryNumber.text) - 1; myJournal.data.journal[num] = _root.journalBody.text; myJournal.data.flush(); } As mentioned earlier, data is automatically saved to a shared object when a movie is exited. By using the flush() method, as shown here, you can save data at any time while the movie is playing. This function will be called when the Save button is pressed (see Step 11). Let's take a look at how this function works. The first line in the function creates a variable named num . The value of this variable is set to the current value displayed in the entryNumber text field, minus one. The Number() function is used to make sure num contains a numerical value. The num value will be used in the next line of the function to reference the appropriate array index of the current journal entry as it relates to the current entry number. As mentioned in Step 4, the number displayed in the entryNumber text field is actually one more than the associated array index it references which is why one is subtracted from the current entry value in the first line of script. (Keep reading: This will make more sense in a moment!) The next line in this function definition uses the value of num to update the journal array with the text displayed in the entryNumber text field. As always, the best way to understand this is by using a sample scenario. Imagine that the current entry number displayed in the entryNumber text field is 9. When this function is called, num would be set to a value of 8 (nine minus one). The second line in the function would be evaluated as follows: myJournal.data.journal[8] = _root.journalBody.text; This will place the text in the journalBody text field into Index 8 of the journal array. Note once again that the current entry number is 9, but the currently referenced index number of the array is 8 (see Step 4 for more on this). This line of script can affect the data in the array in two ways: If Index 8 was previously empty (undefined ), it will now contain text; if it previously included text, that text will be overwritten. The last action in the function uses the flush() method to force the data and shared object to be saved to the user's hard drive for our project, that will include all of the entries that exist in the journal array. -
Now add this function definition to create a new journal entry: function newEntry() { _root.entryNumber.text = myJournal.data.journal.length + 1; _root.journalBody.text = undefined; Selection.setFocus("_root.journalBody"); } The first action in this function sets the current journal entry number (entryNumber text field) to the length of the journal array, plus one. Thus, if the journal array has two entries, it has a length of 2. Adding one will cause "3" to appear in the entryNumber text field. This action causes all new entries to be inserted at the end of the array. The last two actions in this definition are used to empty the journalBody text field, and then to give it focus, so that the user can immediately begin typing his or her entry. To better understand this, let's take a look at how this function works in harmony with the save() function discussed in the previous step. Assume there are two entries in the journal array. This means that the array has entries at index positions 0 and 1 (important to remember), and that it has a length of 2. When the above function is executed, the entryNumber text field will display "3" (the length of the journal array plus one) and the journalBody text field will be emptied. The user now types text into this text field and presses the Save button, which will call the save() function defined in the previous step. At that point, the save() function will subtract one from whatever is displayed in the entryNumber text field, which will in turn save the current text in the journalBody text field to index position 2 of the journal array. The journal array would now contain three entries at index positions 0, 1, and 2, and its length would be 3. If the above function were called again, the process would begin again. -
Next, add the following function definition, which will be used to display the next entry in the journal: function nextEntry () { var num = Number(_root.entryNumber.text) + 1; if (num > myJournal.data.journal.length) { num = myJournal.data.journal.length; } displayEntry(num); } When executed, this function displays the next journal entry in the array. It does this by first assigning a value to num , based on the current numerical value displayed in the entryNumber text field, plus one. This value represents the next journal entry to be displayed. To prevent our application from displaying an entry that does not exist, the value of num is compared against the total number of entries in the journal array (the length property of journal ). If the value of num is greater (as the if statement asks), you're attempting to display a nonexistent entry. In that case, the action within the if statement will reset the value of num to the length property value of the journal array in effect causing the last entry in the array to be displayed instead. The final action in this function calls the displayEntry() function and passes it the value of num , enabling it to display the appropriate journal entry. -
Create the following function, which will be used to display previous journal entries: function previousEntry() { var num = Number(_root.entryNumber.text) - 1; if (num < 1) { num = 1; } displayEntry(num); } This function works similarly to the function described in the last step. First, num is given a value representing the current entry number minus one. The if statement is used to prevent our application from displaying anything beyond journal entry 1. Here's how it works. Suppose the user is currently viewing entry number 6. When this function is called, num would be assigned a value of 5 (six minus one) and that value would be checked to make sure it's not less than 1. Since it's not, the action within the if statement is ignored and the displayEntry() function is called and passed a value of 5, displaying journal entry 5. If the user were viewing entry 1 when this function was called, num would initially be assigned a value of 0. The if statement would determine that this value is indeed less than 1 and thus change its value to 1. The displayEntry() function would then be passed a value of 1. Since entry 1 is already being displayed, it will appear as if nothing has changed on screen. As mentioned, this mechanism prevents browsing past entry 1, since no entries exist at entry number 0 or less. -
With the Actions panel open, select the New button and add this function call: on (release) { newEntry(); } When the user presses this button, the newEntry() function is called, advancing the current entry number by one and clearing the journalBody field so that new text can be entered. -
With the Actions panel open, select the Save button and add this ActionScript to it: on (release) { save(); } When the user clicks this button, the save() function will be executed at which point the current text in the journalBody field either replaces an existing entry or is added as a new entry in the journal array (as described in Step 6). -
With the Actions panel open, select the Prev button and add this ActionScript: on (release) { previousEntry(); } The call to the previousEntry() function changes the display to show the journal entry created before the current one displayed. -
Finally, select the Next button and add this script: on (release) { nextEntry(); } This ActionScript simply calls the nextEntry() function when the button is clicked. The screen is then updated to display the next entry in the list of journal entries. -
Choose Control > Test Movie to test your work. Enter some text as a journal entry. Press the Save button to save the entry, then the New button to create a new journal entry. Press the Save button and then restart the movie. When you restart your movie, the shared object will be loaded (as described in Steps 2 and 3) and any data previously saved can be browsed using the Prev and Next buttons. -
Close the test movie and save your work as journal2.fla. In this lesson you have learned the basics of creating, retrieving, and saving shared objects. You can also use shared objects to save any of the following: User's name Last frame visited User's music preference Date of user's last visit User's ordering preferences Scores (for games) Appointments, addresses, lists Property values (x, y, alpha, rotation) of elements More… |