Posting and loading high scores to the server

In this section, we will create the ServerHiScore script to post and load the high score data from the server, which we will use in the WWWForm class to communicate with the PHP file on the website, which I already set up. We will also create a hash key and encrypt it with the MD5 encryption to protect and check for the user before posting the score to the database.

Prepare for Lift Off

Before we create the ServerHiScore script, we will need to get the MD5 encryption script to encrypt our data. Let's create the new Unity JavaScript and name it MD5.js in MonoDevelop. Then, browse to the following link:

http://www.unifycommunity.com/wiki/index.php?title=MD5.

On this page, you will see the MD5 class for C# script and JavaScript that is written by Matthew Wegner. Go to JavaScript and copy the code and paste it in the MD5.js script that we just created:

#pragma strict

static function Md5Sum(strToEncrypt: String)
{
    var encoding = System.Text.UTF8Encoding();
    var bytes = encoding.GetBytes(strToEncrypt);
 
    // encrypt bytes
    var md5 = System.Security.Cryptography.MD5CryptoServiceProvider();
    var hashBytes:byte[] = md5.ComputeHash(bytes);
 
    // Convert the encrypted bytes back to a string (base 16)
    var hashString = "";
 
    for (var i = 0; i < hashBytes.Length; i++)
    {
        hashString += System.Convert.ToString(hashBytes[i], 16).PadLeft(2, "0"[0]);
    }
 
    return hashString.PadLeft(32, "0"[0]);
}

This script will allow us to encrypt our string with the MD5 encryption.

Note

We can use #pragma strict in the Unity JavaScript to tell Unity to disable the dynamics typing var name = 5 and force us to use the static typing var name : int = 5. This will also make it easy for us to debug because if we forgot to use the static typing, Unity will give us an error when the script is being compiled.

Engage Thrusters

We will create the ServerHiScore script to send and load the user data to the server, which is also encrypted with the MD5.

  1. Let's go to Assets | Create | JavaScript and name it ServerHiScore. Then, we will double-click it to open MonoDevelop and add the following code:
    //Setting the PHP url here
    public var PHPUrl : String = "http://www.jatewit.com/Packt/HiScore.php";
    //Setting the hash key id 
    public var hashKey : String = "UNITYGAMEDEVELOPMENTHOTSHOT";
    
    private var obj_WWW : WWWForm;
    private var b_loaded : boolean;
    
    public function Start() : void {
      // Empty Check for Inspector values
      if( PHPUrl == "" ) {
        Debug.LogError( "PHP Url cannot be null." );
      }
      if( hashKey == "" ) {
        Debug.LogError( "Hash Key cannot be null." );
      }
    }

    In the preceding script, we created the parameter to set the PHP URL that we will be connected to (we won't see anything if we try to view the link in our browser), set the hash key to check for the user, and create the WWWFrom and boolean objects to use in this script. In the Start() function, we just checked to make sure that the PUPUrl and hashKey are not null.

  2. Then, create the SendScore(score : int, name :String) function, which will take two parameters score and name. This function will create the WWWFrom, set the parameter, and send it to the URL that we just assigned. Let's type the function as follows:
    //Creating the function to send 
    public function SendScore( score : int, name : String) : void {
      var w_form : WWWForm = new WWWForm();
      //Telling PHP that the user is submitting the data
      w_form.AddField("action", "PostScore");
      //Sending hash code key to prevent unwanted user
      w_form.AddField("hash", MD5.Md5Sum(name + "-" + score.ToString() + "-" + hashKey)); //Encrypt with MD5
      //Sending the user score
      w_form.AddField("score", score);
      //Sending the user name
      w_form.AddField("name", name);
      //Start waiting for the response back from the server
      StartCoroutine(WaitingForResponse(new WWW(PHPUrl, w_form), null));
    }
  3. Create the WaitingForResponse( www : WWW, callback : Function) : IEnumerator function as mentioned previously. Let's continue from after the SendScore() function and type it as follows:
    //Waiting for the response back from the server
    public function WaitingForResponse( www : WWW, callback : Function) : IEnumerator {
      yield www;
      
      if (www.error == null) {
        Debug.Log("Successful.");
      } else {
        Debug.Log("Failed.");
      }
      
      if (callback != null) {
        callback(www.text);
        callback = null;
      }
      
      //Clears data
      www.Dispose();
    }
  4. We already have the function to send; now we need to load the data from the server, so we will create the GetScores() function to load the user's score data from the server. Let's type it as follows:
    //Getting the score from the server
    public function GetScores() : void {
      b_loaded = false;
      var w_form : WWWForm = new WWWForm();
      //Telling PHP that the user is loading the data
      w_form.AddField("action", "GetScore");
      //Start waiting for the response back from the server
      StartCoroutine(WaitingForResponse(new WWW(PHPUrl, w_form), LoadXMLData));
    }
  5. Next, we create the LoadXMLData(string : String) function, which will parse the XML string data that returns from the server. We will type this script after the GetScores() function as follows:
    //Parse the XML data from the server
    public function LoadXMLData(string : String) : void {
      XMLParser.Parse(string);
      b_loaded = true;
      Debug.Log(string); 
    }
  6. Next, type the rest of the code as follows:
    //Getting User length
    public function GetUserLength() : int {
      if (XMLParser != null) {
        return XMLParser.UserLength();
      } else {
        return 0;
      }
    }
    //Getting User Name by index
    public function GetNameData(index : int) : String {
      if (XMLParser != null) {
        return XMLParser.Name(index);
      } else {
        return "";
      }
    }
    //Getting User Score by index
    public function GetScoreData(index : int) : int {
      if (XMLParser != null) {
        return XMLParser.Score(index);
      } else {
        return 0;
      }
    }
    //Loaded XML
    public function IsLoaded() : boolean {
      return b_loaded;
    } 

    The preceding functions get the server data from the XMLParser (where we stored users' data that returns from the server).

  7. Now, we will go back to the HiScore.js script to add some code in it and make it work. In the HiScore.js script before the Awake() function, add the highlighted code as follows:
    private var obj_localHiScore : LocalHiScore; //Creating the LocalHiScore Object
    private var obj_serverHiScore : ServerHiScore; //Creating the ServerHiScore Object
    
    public function Start() : void {
      //Initializing
  8. Go inside the Start() function and type the highlighted code:
    public function Start() : void {
      //Initializing
      e_page = Page.GAMEOVER;
      int_items = 10;
      scrollPosition = Vector2.zero;
      b_isClickRestart = false;
      b_isClickSubmit = false;
      
      //Creating a Local Hiscore Object
      obj_localHiScore = new LocalHiScore();
      //Setting the maximum scores to show on the table & loading the local high score data here
      obj_localHiScore.SetMaxUser(int_items);
      //Creating a Server Hiscore Object
      obj_serverHiScore = GetComponent.<ServerHiScore>();
    }
  9. Now we have the ServerHiScore object created, we need to go to the GameoverPage() function inside the SERVER HI-SCORE button page code, and type the following highlighted code:
    if (b_isClickSubmit == false) {
        GUI.Label(new Rect((Screen.width - 300)*0.5, (Screen.height*0.1) + 80, 300, 25), "Enter Your Name", GUI.skin.GetStyle("Text1"));
        //Creating the input text field to get the player name
        userName = GUI.TextField(new Rect((Screen.width - 240)*0.5, (Screen.height*0.1) + 120, 240, 40), userName, 8);
        //Submit button
        if (GUI.Button(new Rect((Screen.width - 240)*0.5, (Screen.height*0.1) + 200, 240, 30), "SUBMIT")) {
          b_isClickSubmit = true;
          //TODO: Submitting both local and server high score here
          obj_localHiScore.SaveGame(TimeScoreUI.int_currentScore, userName); //Submitting to the local score
          //Submitting to serverobj_serverHiScore.SendScore(TimeScoreUI.int_currentScore, userName);
        }
      }
      //Creating the Local Hi-Score page button 
      if (GUI.Button(new Rect((Screen.width - 240)*0.5, (Screen.height*0.1) + 240, 240, 30), "LOCAL HI-SCORE")) {
        e_page = Page.LOCALSCORE;
      }
      //Creating the Server Hi-Score page button 
      if (GUI.Button(new Rect((Screen.width - 240)*0.5, (Screen.height*0.1) + 280, 240, 30), "SERVER HI-SCORE")) {
        //TODO: Loading the score data from server here
        obj_serverHiScore.GetScores();
        e_page = Page.SERVERSCORE;
      } 
  10. This will submit and load the score from the server. Then, we go to the ServerScorePage() function and replace the code as follows:
    //Loading score from server
    private function ServerScorePage() : void {
      //Creating the background box
      GUI.Box(new Rect(Screen.width*0.1, Screen.height*0.1, Screen.width * 0.8, Screen.height * 0.8), "SERVER HI-SCORE", GUI.skin.GetStyle("Box2"));
      //TODO: Checking is the loader completed
      if (obj_serverHiScore.IsLoaded()) {
        var int_numUsers : int = obj_serverHiScore.GetUserLength();
        if (int_numUsers >= maxUsers) {
          int_numUsers = maxUsers;
        }
        scrollPositionS = GUI.BeginScrollView (new Rect ((Screen.width - 320)*0.5, (Screen.height*0.1) + 80, 320, 180), scrollPositionS, new Rect (0, 0, 300, 30*int_numUsers));
        for (var i: int = 0; i < int_numUsers; i++) {
          //Setting the number of the user
            GUI.Label(new Rect(0, i * 30, 35, 30), (i+1).ToString() + ".");
            //TODO: Showing the user name and score here
            GUI.Label(new Rect(35, i * 30, 120, 30), obj_serverHiScore.GetNameData(i));
            GUI.Label(new Rect(155, i * 30, 145, 30), GlobalFunction.addCommasInt(obj_serverHiScore.GetScoreData(i)), GUI.skin.GetStyle("Score"));
          }
        GUI.EndScrollView (); //End Scroll Area
      } else {
        //TODO: If the loader doesn't complete display Loading... text
        GUI.Label(new Rect((Screen.width-150)*0.5, (Screen.height*0.1)+120, 150, 50), "LOADING...", GUI.skin.GetStyle("Text1"));
      }
      if (GUI.Button(new Rect((Screen.width - 240)*0.5, (Screen.height*0.1) + 280, 240, 30), "BACK")) {
        e_page = Page.GAMEOVER;
      }
    }

    The preceding code will wait for the server to finish loading and display the users' scoreboard. If the loading didn't finish, the menu will show only the Loading... text; otherwise, it will display the users' names and scores that were returned from the server database.

  11. Finally, go back to Unity editor, click on the HiScore game object in the Hierarchy to bring up the Inspector, then drag-and-drop the ServerHiScore script in the HiScore game object and click Play. When we die or kill all the enemies in the scene, we will be able to load the SERVER HI-SCORE board by clicking on the SERVER HI-SCORE button, and the SUBMIT button will now submit the score to the server and save the score to our local machine at the same time.
    Engage Thrusters

Note

We might not get the same image as shown in the preceding screenshot because the server database will be updated with different users.

Objective Complete - Mini Debriefing

We learned how to use the WWWForm and WWW object to post and load the high score from the server. We also used the MD5 encryption to encrypt the key before posting the data to protect it from unwanted users. Then, we used the StartCoroutine() function to wait for the response from the server.

First, we created the ServerHiScore script to send and receive the user data from the server database. In the Start() function, we checked to make sure that we have the server URL and encryption key.

Next, in the SendScore() function, we first created WWWForm. Then we used AddField("action", "Posting");, which will tell PHP that we want to send the score by setting the action to Posting. (The action parameter and Posting value are set in the PHP code, which you can see in the HiScore.php that I have attached with this code). Then, we set the hash with the MD5 encryption value of hashKey, set the score, and name to the WWWForm object. In the last line, we use StartCoroutine(WaitingForResponse(new WWW(PHPUrl, w_form), null)) function to wait for the response from the server. The StartCoroutine() function basically takes the IEnumerator, which we pass to the WaitingForResponse(new WWW(PHPUrl, w_form), null) function here. This function basically creates the WWW object that sends our WWWForm object to the specific PHPUrl. It also takes the Function to callback when it is finished.

Then, we have the WaitingForResponse() function, which will wait for the response from the server, and check if the sending request succeeds. Then we check if there is any callback function to call. If there is a callback function, we will call it. Finally, we just clear all data by using www.Dispose().

Next, we created the GetScore() function, which is very similar to the SendScore() function except that we only send one parameter to PHP, which is action to tell PHP that we want GetScore. Also, in the StartCoroutine() function, we put the callback function in the WaitingForResponse() function, which is LoadXMLData. This will be called after the loading is finished.

Then, we have the LoadXMLData() function, which will call the XMLParser.Parse() function to parse the XML string data that returns from the server, then store it in the XMLParser class. We also created GetUserLength(), GetNameData(), GetScoreData(), and IsLoaded() to get the user data from index and check if the data has been loaded.

Then, we go back to the HiScore script to add the function that will save and load the user data to the server database.

Finally, we applied the ServerHiScore script to the HiScore game object in Hierarchy view to get the result we want.

Classified Intel

In this step, we use AddField("fieldname", "value"); in WWWForm to add the value and pass it to the server. In this function, the fieldname mostly depends on the PHP script on the server.

We can open the HiScore.php file that we have in this project package and take a look at the following line:

$action = $_POST[ 'action' ]; //Get request action from Unity 

We will see that the word action is the same keyword that we assigned in the AddField() function at the beginning of the SendScore() function:

w_form.AddField("action", "PostScore");

It is basically the keyword that we use to communicate the value between Unity and PHP. In this PHP file, we used MySQL to set up the database on my website, so if you have your website and the database set up with MySQL, you can adjust this PHP to point to your database and put it to your website.

Note

For more information on how to set up MySQL database on your website, you can go to the following link and download the file:

http://www.webwisesage.com/addons/free_ebook.html.

There is also a video tutorial of How to set up MySQL database, PHP, and flash, from Lee Brimelow. You can find it from the following link:

http://www.gotoandlearn.com/play.php?id=20.

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

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