English French German Spain Italian Dutch Russian Portuguese Japanese Korean Arabic Chinese Simplified

20 февр. 2012 г.

Unity3d. Сохранение результата в базу данных расположенную на сервере. Часть вторая - клиент.

     И так мы создали базу данных, создали скрипт, который осуществляет соединение с базой и чтение-запись данных. Теперь нам необходимо соединиться из нашей игры с php-скриптом, и получить из него данные, которые он получает с базы данных.
    Т.к. данные которые мы будем получать из php-скрита будут в xml виде то первым делом создадим скрипт XmlParser который будет осуществлять чтение xml-данных, выбор из данных атрибутов name и score, и сохранять значения этих атрибутов в массивы name[] и score[].



using UnityEngine;
using System.Collections;
using System.Xml;

public static class XmlParser 
{
    private static XmlDocument doc;
    private static XmlNode root;
    private static string[] names; // массив имен
    private static int[] scores; // массив результатов
    private static int userLenght; // длинна массива


    public static void Parse(string xml)
    {
        doc = new XmlDocument();
        doc.LoadXml(xml);

        root = doc.LastChild;
        if (root.HasChildNodes)
        {
            userLenght = root.ChildNodes.Count;
            names = new string[userLenght];
            scores = new int[userLenght];

            for (int i = 0; i < userLenght; i++)
            {
                XmlAttribute nameAtt = root.ChildNodes[i].Attributes["name"];
                XmlAttribute scoreAtt = root.ChildNodes[i].Attributes["score"];
                names[i] = (string)nameAtt.Value;
                scores[i] = ConvertStringToInt((string)scoreAtt.Value);
            }
        }
    }

    private static int ConvertStringToInt(string s)
    {
        int j;
        bool result = System.Int32.TryParse(s, out j);
        if (result = true)
        {
            return j;
        }
        else
        {
            Debug.Log("Error convert string to int");
            return 0;
        }
    }

    public static string Name(int index)
    {
        return names[index];
    }

    public static int Score(int index)
    {
        return scores[index];
    }

    public static int UserLength()
    {
        return userLenght;
    }
}



     Теперь создадим скрипт ServerHiScore который будет осуществлять доступ к php-скрипту, получение и отправку данных из приложения на сервер.

using UnityEngine;
using System.Collections;

public class ServerHiScore : MonoBehaviour 
{
    //Set the PHP url here
    public string PHPUrl = "http://yourDomainName.byethost15.com/HiScore.php"; // адрес скрипта
    //Set the hash key id 
    public string hashKey = "BRIGHTWORLDGAMES"; // ключ для шифрования данных

    private WWWForm obj_WWW;
    private bool b_loaded;

    private delegate void LoadXmlDel(string str);

 // Use this for initialization
 void Start () 
    {

 }
 
 // Update is called once per frame
 void Update () 
    {
 
 }

  

//Отправка данных
public void SendScore( int score, string name)
{
 WWWForm w_form = new WWWForm();
 //Telling PHP that the user is submiting 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));
}

//
public IEnumerator WaitingForResponse(WWW www, System.Func callback) 
{
    yield return www; // ожидаем пока получим с сервера данные
 
 if (www.error == null) 
    {
 // Debug.Log("Successful.");
 }
    else 
    {
 // Debug.Log("Failed.");
 }
 
 if (callback != null) {
  callback(www.text);
  callback = null;
 }
 
 //Очищаем данные
 www.Dispose();
}

//Получение данных
public void GetScores() 
{
 b_loaded = false;
 WWWForm w_form = 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));
}


//Parse the XML data from the server
public bool LoadXMLData(string str)
{
 XmlParser.Parse(str);
 b_loaded = true;
    return true;
}

//Getting User length
public int GetUserLength() 
{
  return XmlParser.UserLength();
}
//Getting User Name by index
public string GetNameData(int index)
{
  return XmlParser.Name(index);
}
//Getting User Score by index
public int GetScoreData(int index)
{
  return XmlParser.Score(index);
}
//Loaded XML
public bool IsLoaded()
{
 return b_loaded;
} 

}

     При передаче данных, мы также передаем ключ в зашифрованном виде, чтобы никакие злоумышленники не могли записать свои данные на сервер, в php-скрипте мы проверяем совпадает ли ключ который храниться на сервере с ключом который мы передали, и записывает данные только если ключи совпадают. При создании аккаунта на byethost у вас автоматически создается домен с названием как выше имя, http://yourDomainName.byethost15.com/, где вместо byethost15 будет ваше название, посмотрите на панели слева в админке. Также вы всегда может создать другой домен, если этот вас не устраивает. 
     Теперь реализуем метод MD5. Создайте js-скрипт с следующим содержанием:
#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]);
}
     Т.к. это js-скрипт, а мы используем его в C# скрипте, то обязательно поместите скрипт MD5 в папку Plugins, иначе компилятров Unity3d будет выдавать вам ошибку. На этом вобщем-то всё. Теперь вы можете просто вызывать методы GetScores() и SendScores() скрипта ServerHiScore. Например у меня есть меню, в котором есть кнопка HiScore, при нажатии на которую появляется окно с результатами, тогда получать данные я буду следующим образом:

using UnityEngine;
using System.Collections;

public class Menu : MonoBehaviour 
{
    public GUISkin customSkin;

    enum Page {MENU, HOWTOPLAY, HISCORE, HISCOREMENU, EMPTY};
    private Page page;
    private Vector2 scrollPosition = Vector2.zero;
    private int maxUsers = 10;

    private GameObject cloud;

    private ServerHiScore objServerHighScore; // объявляем экземпляр класса ServerHiScore

    void Awake()
    {
    
    }

 void Start ()  
    {
        Time.timeScale = 1f;

        objServerHighScore = this.GetComponent();
        page = Page.MENU;

        cloud = GameObject.Find("HiScoreCloud");
 }
 
 void Update () 
    {
 }

    void OnGUI()
    {
        GUI.skin = customSkin;

        switch (page) 
        {
            case Page.MENU:
                MenuPage();
                break;
            case Page.HISCORE:
                HiScorePage();
                break;
            case Page.EMPTY:
                break;
        };

    }

    private void MenuPage() 
    {
        GUI.BeginGroup(new Rect(Screen.width / 1.2f - 125, Screen.height / 1.6f - 100, 250, 200));
      
        if (GUI.Button(new Rect(25, 20, 200, 30), "Start Game", GUI.skin.GetStyle("StartButton")))
        {
            Application.LoadLevel("MainScene");
        }
        if (GUI.Button(new Rect(10, 70, 220, 30), "How to Play", GUI.skin.GetStyle("HowToButton")))
        {
            StartCoroutine(ChangePage(Page.HOWTOPLAY)); 
        }
        if (GUI.Button(new Rect(25, 120, 180, 30), "Hi-Score", GUI.skin.GetStyle("QuitButton")))
        {
            objServerHighScore.GetScores(); // если нажали кнопку Hi-Score вызываем метод для получения данных
            StartCoroutine(ChangePage(Page.HISCORE));
        }
        GUI.EndGroup();
    }

    private void HiScorePage() 
    {
        GUI.BeginGroup(new Rect(Screen.width / 2f - 300, Screen.height / 2f - 210, 600, 420));
        GUI.Label(new Rect(200, 50, 200, 50), "Top 10", GUI.skin.GetStyle("HiScoreLabelCenter"));
        if (objServerHighScore.IsLoaded()) // если данные загружены
        {
            int numUsers = objServerHighScore.GetUserLength();
            if (numUsers > maxUsers)
                numUsers = maxUsers;

            scrollPosition = GUI.BeginScrollView(new Rect(100, 110, 400, 180), scrollPosition,
                                                 new Rect(0, 0, 250, 30 * numUsers));

            for (int i = 0; i < numUsers; i++)
            {
                GUI.Label(new Rect(0, i * 30, 35, 30), (i + 1).ToString() + ". ", GUI.skin.GetStyle("HiScoreLabel"));
                GUI.Label(new Rect(35, i * 30, 220, 30), objServerHighScore.GetNameData(i), GUI.skin.GetStyle("HiScoreLabel")); // получаем имя
                GUI.Label(new Rect(255, i * 30, 145, 30), objServerHighScore.GetScoreData(i).ToString(), GUI.skin.GetStyle("HiScoreLabel")); // получаем очки
            }
            GUI.EndScrollView();
        }
        else
        {
            GUI.Label(new Rect(200, 200, 200, 30), "LOADING...", GUI.skin.GetStyle("HiScoreLabelCenter"));
        }

        if (GUI.Button(new Rect(210, 300, 180, 30), "Back", GUI.skin.GetStyle("ReplayButton"))) 
        {
            StartCoroutine(ChangePage(Page.HISCOREMENU));
        }
        GUI.EndGroup();
    }

    IEnumerator ChangePage(Page pageNum)
    {
        switch (pageNum)
        {
            case Page.HOWTOPLAY:
                page = Page.EMPTY;
                while ((transform.position - new Vector3(178f, transform.position.y, transform.position.z)).magnitude > 0.5f)
                {
                    transform.position = Vector3.Lerp(transform.position, new Vector3(178f, transform.position.y, transform.position.z), Time.deltaTime*3.0f);
                    yield return new WaitForSeconds(0.01f);
                }
                page = Page.HOWTOPLAY;
                break;
            case Page.MENU:
                page = Page.EMPTY;
                while ((transform.position - new Vector3(0f, transform.position.y, transform.position.z)).magnitude > 0.5f)
                {
                    transform.position = Vector3.Lerp(transform.position, new Vector3(0f, transform.position.y, transform.position.z), Time.deltaTime*3.0f);
                    yield return new WaitForSeconds(0.01f);
                }
                page = Page.MENU;
                break;
            case Page.HISCORE:
                page = Page.EMPTY;
                while (cloud.transform.position.y > 0.1f)
                {  
                    cloud.transform.position = Vector3.Lerp(cloud.transform.position, new Vector3(cloud.transform.position.x, 0f, cloud.transform.position.z), Time.deltaTime*3f);
                    yield return new WaitForSeconds(0.01f);
                }
                page = Page.HISCORE;
                break;
            case Page.HISCOREMENU:
                page = Page.EMPTY;
                while (cloud.transform.position.y < 87.9f)
                {
                    cloud.transform.position = Vector3.Lerp(cloud.transform.position, new Vector3(cloud.transform.position.x, 88f, cloud.transform.position.z), Time.deltaTime * 3.0f);
                    yield return new WaitForSeconds(0.01f);
                }
                page = Page.MENU;
                break;
        };
    }
}

     Если же мне нужно сохранить данные на сервер, то я делаю следующим образом:
private void SubmitDialog() 
    {
        GUI.BeginGroup(new Rect(Screen.width / 2 - 150, Screen.height / 2 - 140, 300, 280));
        GUI.Box(new Rect(0, 0, 300, 280), "", GUI.skin.GetStyle("PauseBox"));
        GUI.Label(new Rect(25, 10, 250, 50), "Submit Results", GUI.skin.GetStyle("LevelCompleteLabel"));
        GUI.Label(new Rect(25, 60, 250, 50), "Your score: " + totalScore.ToString(), GUI.skin.GetStyle("LabelMidCenter"));
        GUI.Label(new Rect(25, 90, 250, 50), "Enter your name:");
        userName = GUI.TextField(new Rect(25, 140, 250, 45), userName, 20);
        if (GUI.Button(new Rect(105, 200, 80, 24), "Submit", GUI.skin.GetStyle("NextLevelButton")))
        {
            submitResult = true;
            //сохранение результата на сервер
            objServerHighScore.SendScore(totalScore, userName);
            dialog = previousDialog;

        }
        if (GUI.Button(new Rect(105, 235, 80, 24), "Back", GUI.skin.GetStyle("NextLevelButton")))
        {
            dialog = previousDialog;
        }
        GUI.EndGroup();
    }




8 комментариев:

  1. А можно приложить проект юнити рабочий потому что половина скриптов и ошибками как и PHP файл.. наверно сайт подпортил все :(

    ОтветитьУдалить
  2. Анонимный29 июня 2012 г., 23:48

    я тоже поипался с этим кодом, в итоге придется писать свое...
    ошибки...
    зря потраченое время

    ОтветитьУдалить
  3. или удали эту тему или исправь ошибки, заебал

    ОтветитьУдалить
  4. Этот комментарий был удален автором.

    ОтветитьУдалить
  5. Анонимный25 июня 2013 г., 14:16

    в этом скрипте ошибка




    using UnityEngine;
    using System.Collections;

    public class ServerHiScore : MonoBehaviour
    {
    //Set the PHP url here
    public string PHPUrl = "http://yourDomainName.byethost15.com/HiScore.php"; // адрес скрипта
    //Set the hash key id
    public string hashKey = "BRIGHTWORLDGAMES"; // ключ для шифрования данных

    private WWWForm obj_WWW;
    private bool b_loaded;

    private delegate void LoadXmlDel(string str);

    // Use this for initialization
    void Start ()
    {

    }

    // Update is called once per frame
    void Update ()
    {

    }



    //Отправка данных
    public void SendScore( int score, string name)
    {
    WWWForm w_form = new WWWForm();
    //Telling PHP that the user is submiting 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));
    }

    //
    public IEnumerator WaitingForResponse(WWW www, System.Func callback)
    {
    yield return www; // ожидаем пока получим с сервера данные

    if (www.error == null)
    {
    // Debug.Log("Successful.");
    }
    else
    {
    // Debug.Log("Failed.");
    }

    if (callback != null) {
    callback(www.text);
    callback = null;
    }

    //Очищаем данные
    www.Dispose();
    }

    //Получение данных
    public void GetScores()
    {
    b_loaded = false;
    WWWForm w_form = 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));
    }


    //Parse the XML data from the server
    public bool LoadXMLData(string str)
    {
    XmlParser.Parse(str);
    b_loaded = true;
    return true;
    }

    //Getting User length
    public int GetUserLength()
    {
    return XmlParser.UserLength();
    }
    //Getting User Name by index
    public string GetNameData(int index)
    {
    return XmlParser.Name(index);
    }
    //Getting User Score by index
    public int GetScoreData(int index)
    {
    return XmlParser.Score(index);
    }
    //Loaded XML
    public bool IsLoaded()
    {
    return b_loaded;
    }

    }

    ОтветитьУдалить
  6. хотя бы рабочие скрипты залили...

    ОтветитьУдалить
  7. Исправте ктонить скрипты и на 5 юньку

    ОтветитьУдалить
  8. Большое спасибо за статью!
    Наконец нашел интересный пример шифрования при передаче данных на сервер.

    ОтветитьУдалить