1.9 saving data to a file and reading data from the file
You need to implement the SAVE Function in the game. Although the SAVE Function is usually the last step in creating a game, you must implement this function in the game. First, xNa uses the default. Net file I/O function, which means it is easy to create, open, and delete files. Then, the xmlserializer class can easily save the data to a file and load the data later.
The only problem is that you can find a location that can be saved on both the PC and xbox360 platforms. To solve this problem, you can use storagedevice, which must be created first.
Note:Creating a storagedevice may be complicated, but don't be intimidated, because the rest of this tutorial (from "saving data to disk") is very simple and effective, this method is not limited to xNa, because it uses the default one.. net.
Working Principle
Before saving data to a disk, you need to write data in an available location. This can be achieved by creating a storagedevice. storagedevice will ask the users on the xbox360 platform where to save the data.
Creates a storagedevice asynchronously.
In this process, the Xbox guide is opened and terminated.ProgramUntil the user closes the guide. To solve this problem, let the process be processed asynchronously. The principles are explained in 8-5 of the tutorial.
Guide needs to add gamerservicescomponent to the game (see tutorial 8-1 ).CodeAdd to game1 constructor:
Public game1 () {graphics = new graphicsdevicemanager (this); content. rootdirectory = "content"; components. Add (New gamerservicescomponent (this ));}
Next, when you call the update method, you will check whether the user wants to save the data. If so, call guide. beginshowstoragedeviceselector, which opens a dialog box asking the user to choose where to save the data. The program will not be terminated here, but the program will be paused until the user closes the dialog box. The Guide. beginshowstoragedeviceselector method requires you to specify another findstoragedevice method as the first parameter. Once you close the dialog box, this method will be called:
Keyboardstate keystate = keyboard. getstate (); If (! Guide. isvisible) if (keystate. iskeydown (Keys. s) Guide. beginshowstoragedeviceselector (findstoragedevice, null );
If you press the s key, the dialog box is opened, but the code is not terminated until the user closes the dialog box.
When the dialog box is displayed on the screen, your program is still running. Once you select and close the dialog box, the findstoragedevice method, which is the first parameter, will be called, this means you should define this method in advance, otherwise the compiler will report an error:
Private void findstoragedevice (iasyncresult result) {storagedevice = guide. endshowstoragedeviceselector (result); If (storagedevice! = NULL) savegame (storagedevice );}
The beginshowstoragedeviceselector output is used as a parameter for this method. If you pass the result to the Guide. endshowstoragedeviceselector method, you can obtain data storage. However, if you cancel the operation, the result will be null, so you should check in advance. If storagedevice is available, you can pass it to the savegame method, which will be defined later.
However, if you allow the user to perform the second operation when specifying the data location, for example, loading data, you need to define the second method, for example, findstoragedeviceforloading. However, the clear method is to specify an identifier, which can be checked in the findstoragedevice method. Your update method should contain the following code blocks:
Keyboardstate keystate = keyboard. getstate (); If (! Guide. isvisible) {If (keystate. iskeydown (keys. s) Guide. beginshowstoragedeviceselector (findstoragedevice, "saverequest"); If (keystate. iskeydown (keys. l) Guide. beginshowstoragedeviceselector (findstoragedevice, "loadrequest ");}
As you can see, the dialog box is displayed in both cases. When the dialog box is closed, the findstoragedevice method is called. However, the difference this time is that you have specified an identifier and checked the identifier in the findstoragedevice method:
Private void findstoragedevice (iasyn, cresult result) {storagedevice = guide. endshowstoragedeviceselector (result); If (storagedevice! = NULL) {If (result. asyncstate = "saverequest") savegame (storagedevice); else if (result. asyncstate = "loadrequest") loadgame (storagedevice );}}
Based on the specified identity, you will call the savegame or loadgame method.
Save data to disk
Once you have a correct storagedevice, you can easily specify a name for the file that writes data:
Private void savegame (storagedevice) {storagecontainer Container = storagedevice. opencontainer ("bookcodewin"); string filename = path. combine (container. path, "save0001.sav"); filestream SaveFile = file. open (filename, filemode. create );}
This will create a file named save0001. sav if the file already exists, it will be overwritten.
Note:On the PC, this file will be created in the My Documents \ savedgames folder.
Once you have the correct file name and open the file, you can use the default. Net Method to save the file. Assume that you have the following data structure:
Public struct gamedata {public int activeplayers; public float time ;}
You need to create an xmlserializer that can convert your data into XML and save it to the disk:
Xmlserializer = new xmlserializer (typeof (gamedata); xmlserializer. serialize (SaveFile, gamedata); SaveFile. Close ();
Xmlserializer can serialize the gamedata object, and then use a command to write the data stream of the gamedata object to the file. Do not forget to close the file stream. Otherwise, the program will lock the file stream.
To add the system. Io and system. xml. serialization namespaces, you only need to add the following code at the top of the Code:
Using system. IO; using system. xml. serialization;
The last line of code requires you to add a reference to system. xml. To add this reference, open the project menu, select Add reference, select system. XML, as shown in 1-5, and click OK.
Figure 1-5 Add a reference to system. xml
Load data from disk
The method for loading data is the same as that for storing data, and the order is the opposite. Check whether the file exists. Open it if it exists. You still need to create an xmlserializer, but this time you use xmlserializer to deserialize the gamedata object from the file stream. The following code loads all the data from the file and converts the data to the gamedata object:
Private void loadgame (storagedevice) {storagecontainer Container = storagedevice. opencontainer ("bookcodewin"); string filename = path. combine (container. path, "save0001.sav"); If (file. exists (filename) {filestream SaveFile = file. open (filename, filemode. open); xmlserializer = new xmlserializer (typeof (gamedata); gamedata = (gamedata) xmlserializer. deserialize (SaveFile); SaveFile. close ();}}
Code
The update method checks whether the user wants to save or load the file and opens the dialog box:
Protected override void Update (gametime) {gamepadstate = gamepad. getstate (playerindex. one); If (gamepadstate. buttons. back = buttonstate. pressed) This. exit (); keyboardstate keystate = keyboard. getstate (); If (! Guide. isvisible) {If (keystate. iskeydown (keys. s) Guide. beginshowstoragedeviceselector (findstoragedevice, "saverequest"); If (keystate. iskeydown (keys. l) Guide. beginshowstoragedeviceselector (findstoragedevice, "loadrequest");} gamedata. time + = (float) gametime. elapsedgametime. totalseconds; base. update (gametime );}
When the user closes the guide, the findstoragedevice method is called. This method calls the savedata or loaddata method based on the identity that is asynchronously called. You can see the entire findstoragedevice method in the previous Code, only the savegame method is missing:
Private void savegame (storagedevice) {storagecontainer Container = storagedevice. opencontainer ("bookcodewin"); string filename = path. combine (container. path, "save0001.sav"); filestream SaveFile = file. open (filename, filemode. create); xmlserializer = new xmlserializer (typeof (gamedata); xmlserializer. serialize (SaveFile, gamedata); SaveFile. close (); log. add ("game data SA Ved! ");}