Local rank

The Settings screen is implemented with the usage of settings from the isolated storage. However, you have not read or written any specific files inside the storage yet. In this part, you will learn how to save all results locally in the text file and read them to present in the Ranks screen. At the end of this part, you will know how to create files in the isolated storage, read them, as well as append some text to them.

Files in the isolated storage

As mentioned in the previous chapter, the isolated storage is a mechanism that allows you to store various data related to your application, including files and settings. Data stored by one application are not accessible by the others. Furthermore, the isolated storage makes it possible to place files in particular directories. As presented in the following figure, the first application contains two directories, while the second contains one directory with three files, as well as a file placed without any directory. Both applications also contain some settings.

Files in the isolated storage

Implementation

In the Space Aim 3D game you will use the isolated storage to store both settings (as described earlier) and the text file with information about results obtained in the game. In the latter scenario, you use just the plain text file and not the XML one, to learn how to support another kind of file. Each result is stored in a separate line. The player name and the score are separated by a semicolon. A simple example is presented as follows. It indicates that player Marcin obtained 10000 and 20000 points in two consecutive games:

Marcin;10000
Marcin;20000 (...)

LocalRank.cs

To perform operations on the file stored in the isolated storage, you create a new class, named LocalRank, in the .cs file inside the Models directory. The class has two methods, to add a new result, as well as to read top scores. To make maintenance of the class easier, you store the file name (where local results are saved) as the constant value named FILENAME. You also create the private field, which is an instance of the IsolatedStorageFile class. By default, you assign to it an object that represents the storage for the current application, as shown in the following code snippet:

private const string FILENAME = "Rank.txt";
private IsolatedStorageFile m_file = 
  IsolatedStorageFile.GetUserStoreForApplication();

The AddResult method adds information about the player name and the score to the file, as shown as follows:

public void AddResult(string name, int score)
{
  IsolatedStorageFileStream stream = this.m_file.OpenFile(
    FILENAME, FileMode.Append, FileAccess.Write);
  using (StreamWriter writer = new StreamWriter(stream))
  {
    writer.WriteLine("{0};{1}", name, score);
  }
}

At the beginning, you create a new IsolatedStorageFileStream instance representing the stream of the opened file. You specify that you will open the file in the Append mode (content will be added at the end of the file) for writing.

Then, you use the StreamWriter class to write the new content to the stream. You can use the WriteLine method, which puts a specific text followed by a new line.

It is worth mentioning that you use the using statement in the previous code. With it, resources required by the StreamWriter instance are released automatically when the execution exits the using statement. Thus, you can use resources more efficiently.

The ReadTopScores method parses the content of the whole file and returns an array of ten top scores:

public RankItem[] ReadTopScores()
{
  List<RankItem> items = new List<RankItem>();
  IsolatedStorageFileStream stream = this.m_file.OpenFile(
    FILENAME, FileMode.OpenOrCreate, FileAccess.Read);
  using (StreamReader reader = new StreamReader(stream))
  {
    string line;
    while ((line = reader.ReadLine()) != null)
    {
      string[] parts = line.Split(';'),
      RankItem item = new RankItem(-1, parts[0],
        int.Parse(parts[1]));
      items.Add(item);
    }
  }
  items = items.OrderByDescending(i => i.Score).Take(10).ToList();
  for (int i = 0; i < items.Count; i++)
  {
    items[i].Number = i + 1;
  }
  return items.ToArray();
}

Reading the file from the isolated storage is similar to writing. You create a new instance of the IsolatedStorageFileStream and assign to it an object returned by the OpenFile method. However, here you need to choose different values from the FileMode and FileAccess enumerations, because the file should be opened (or created, if does not exist) and you only need to read it. Then, you use the StreamReader class to read data from the file stream.

The single result is stored in a separate line. Thus, you should read all lines and then split each by semicolon to read both the player name and the score. To read the single line, the ReadLine method can be used. To read many lines, you can place this instruction inside the condition of the while loop. The line from the file is stored in the line variable.

To get the player name and the score, you use the Split method. It returns an array of string values representing particular substrings separated by the specific character or string. As an example, if you call the Split method (with a semicolon as a parameter) on the string instance equal to Marcin;10000, the returned array will contain two elements, namely Marcin and 10000.

Next, you create a new instance of the RankItem class and set values of its parameters, using the constructor. Then, you add it to the items collection.

At the end, you sort read data by the score (descending), take first ten elements, and convert them to a list. The for loop is used to set the Number properties of the top scores. The last statement just returns RankItem instances as an array.

RanksViewModel.cs

The local rank should be presented just after opening the Ranks screen. Thus, you need to slightly modify the view model class for this page. In the OnNavigatedTo method, you create a new instance of the LocalRank class, call the ReadTopScores method, and assign the results to the RankLocal property. By using the data binding mechanism, the user interface will be updated automatically. The suitable part of the code is shown as follows:

public void OnNavigatedTo(NavigationEventArgs e)
{ (...)
  LocalRank localRank = new LocalRank();
  this.RankLocal = localRank.ReadTopScores();
}

Direct3DInterop.h

Other modifications are required in the Direct3DInterop class from the native part. The aim is to prepare a way of sending the current score to the managed part and indicate that it should be saved locally. You can implement it in a way similar to the one presented earlier, for indicating that the result should be sent to the web service. At the beginning, you add the SaveResultHandler delegate and the SaveResult event:

public delegate void SaveResultHandler(); (...)
event SaveResultHandler^ SaveResult;

Direct3DInterop.cpp

Apart from changes in the header file, you will also modify an implementation of the OnPointerReleased method in the Direct3DInterop.cpp file:

void Direct3DInterop::OnPointerReleased(
  DrawingSurfaceManipulationHost^ sender, PointerEventArgs^ args)
{ (...)
  if (action != SA3D_ACTION_NONE && LastScore > 0) { SaveResult(); }
}

Here, you add the conditional expression at the end of the method. When the current action is other than SA3D_ACTION_NONE and the score is greater than zero, you fire the SaveResult event. It causes that the managed part receives information that the current result should be saved locally.

GamePage.xaml.cs

Next changes required by the local rank mechanism involve the code-behind file regarding the Game screen. In the DrawingSurface_Loaded, you specify the method which is called when the SaveResult event is fired. Here, it is named Interop_SaveResult:

m_d3dInterop.SaveResult += this.Interop_SaveResult;

Inside this method, you just call the SaveResult one from the view model. You get the last score by reading the LastScore property of the m_d3dInterop field:

private void Interop_SaveResult()
{
  this.m_viewModel.SaveResult(this.m_d3dInterop.LastScore);
}

GameViewModel.cs

The last modification is necessary in the view model for the Game screen. Here, you implement the SaveResult method. Inside it, you create the new LocalRank instance and call the AddResult method, as presented in the following code:

public void SaveResult(int result)
{
  LocalRank localRank = new LocalRank();
  localRank.AddResult(Settings.Name, result);
}

Currently, you can launch your game, play for some time, navigate to the Ranks screen, and see your scores!

Isolated Storage Explorer tool

The mechanism of local rank stores the Rank.txt file in the isolated storage. The Windows Phone SDK 8.0 provides developers with an additional tool that makes it possible to see what directories and files are available in the storage for a specific application, as well as to download them (referred as taking a snapshot) and update (restoring a snapshot). In this part, you will learn how to use the Isolated Storage Explorer tool.

It is the command-line application, thus, you should open the Command Prompt (cmd) first. Then, you navigate to the directory where ISETool.exe file is located (by default: C:Program Files (x86)Microsoft SDKsWindows Phonev8.0ToolsIsolatedStorageExplorerTool) and run supported commands.

The first useful command presents a list of available Windows Phone devices, including emulators (both in 7.1 and 8.0 versions) and the phone:

ISETool.exe EnumerateDevices

The results present some useful information, including the device index, as shown in the following code. You will use the device index later while specifying which device should be used for a particular action.

Device Index    Device Name
------------    -------------------------------
 0              Device
 1              Emulator WVGA 512MB (...)

Apart from listing available devices, you can also see directories and files. To do so, you can use the command with three parameters. The first one (dir) indicates that you want to list directories and files. The second (deviceindex:3) represents the device which you want to use. It is worth mentioning that you can use deviceindex:[number] form, xd to use the first emulator, or td to use the phone. The last parameter (ProductID) is the Product ID of the application (without braces), which you can obtain from the Packaging tab in the manifest file. The command syntax is as follows:

ISETool.exe dir deviceindex:3 ProductID

The next command can be used to download the storage of specified application from the particular device into the local directory. You should choose a suitable operation (by using ts instead of dir), as well as provide a path to the directory at the end of the command:

ISETool.exe ts deviceindex:3 ProductID "C:SpaceAim3D"

The last presented command is used to upload files from your computer to the isolated storage in the emulator or the phone. You need to specify the proper command type (rs) and indicate which directory should be uploaded (for example, C:SpaceAim3DIsolatedStore), as presented in the following line:

ISETool.exe rs deviceindex:3 
  ProductID "C:SpaceAim3DIsolatedStore"

Tip

A path to the directory in case of ts and rs operations is not the same. If you want to download files, modify them, and upload, you need to indicate that you want to use the IsolatedStore subfolder during uploading.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.119.138.202