English French German Spain Italian Dutch Russian Portuguese Japanese Korean Arabic Chinese Simplified
Показаны сообщения с ярлыком Unity3d. Показать все сообщения
Показаны сообщения с ярлыком Unity3d. Показать все сообщения

12 мар. 2012 г.

Unity3d + Blender + GIMP - создание анимации с помощью спрайтов.


Для создания анимации с помощью спрайтов я использовал метод создания 3d модели и рендеринга её в различных положениях. Для этого я использовал следующие программы: Blender 2.6, GIMP 2.6, плагин  для GIMP (для создания спрайтов) и Unity3d 3.5.
Blender.
                Сделаем анимацию простого куба. Запускаем Blender, создаем куб: Shift+A -> Mesh->Cube.
Настраиваем камеру чтобы она смотрела на куб. Нажимаем F12, ждем пока рисунок отрендерится, потом жмем F3. Во вкладке Save as Image выбираем PNG и RGBA (чтоб фон был прозрачным). Называем рисунок 1.png.  Потом нажимаем Esc. Поднимем немного куб, опять рендер и сохранение.  Называем рисунок 2.png. Проделайте так несколько раз.
GIMP.
                Теперь когда у нас готовы рисунки, нужно их склеить в один спрайт. Для этого сначала нужно установить плагин в GIMP. Переходим по ссылке скачиваем плагин, кладем его в директорию {GIMPHOME}\share\gimp\2.0\scripts\SpriteSheet.scm Запускаем GIMP, жмем Фильтры – Scripts-Fu – обновить сценарии. Плагин установлен. Теперь жмем Фаил – Открыть как слои, и выбираем наша рисунки, жмем Фильтры – Sprite-Sheets – Create from layers. У вас появиться спрайт. Сохраняем его, жмем в появившемся окне Фаил – Сохранить как… , открываем вкладку Выберите тип файла (по расширениею) и выбираем там PNG, жмем сохранить потом ещё раз жмем сохранить. Всё спрайт готов, осталось загрузить его в Unity3d и анимировать.
Unity3d.
                Создаем Plane. Поворачиваем его лицом к камере, не забудьте добавить источник света. Добавляем наш спрайт в проект, создаем новый материал, в качестве текстуры указываем наш спрайт. Выберите Shader: Transparent – Diffuse, чтобы фон был прозрачным. Примените данный материал к созданному Plane. Теперь осталось анимировать его, делать мы это будем с помошью вот этого скрипта  Добавьте этот скрипт к Plane,  и установите нужные настройки в скрипте. 
                Анимация готова! Можете запустить проект и любоваться.
Читать дальше......

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();
    }




Читать дальше......

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

     Всем доброго времени суток, в этом цикле статей я расскажу как создать базу данных на бесплатном интернет хостинге, и получить доступ к ней из вашей игры, сделанной на Unity3d.
Допустим вы создали онлайн игру и перед вами встала задача добавить возможность сохранения набранных очков пользователем, с возможностью вывода этих очков в HiScore. Для этого вам необходимо хранить эти очки на сервере с возможностью постоянного доступа к нему.
     Я использовал бесплатный хостингwww.byethost.com. И так регестрируемся на www.byethost.com, на почту вам должно прийти письмо с логином и паролем. Авторизуемся на сайте, потом заходим в панель управления. Выбираем MySQL Database:




     В появившемся окне в поле вводим имя вашей базы данных, и жмем Create Database. База данных создана теперь заходим в панель управления базой данных, жмем кнопку Admin. У вас должно появиться следующее окошко:




     Создадим новую таблицу в которой будем хранить имя пользователя и набранные очки. В поле «Имя» введите название таблицы, например «scores», в поле «Количество столбцов» введите «2», и нажмите «Ок». Появится окно где нужно заполнить названия столбцов и тип хранимых данных. В первом столбце будем хранить имя пользователя: поле - name, тип - varchar, длинна - 20. Второй столбец: поле – score, тип int. Нажимае «Сохранить», таблица создана. Теперь выберите созданную таблицу, у вас появится окно со структурой таблицы, и внизу будет надпись «Индекс не определен». Напротив столбца «Name» нажмите «ещё» и выберите "добавить индекс".



     База данных создана, теперь необходимо осуществить доступ к ней. Так как на сервере порт 3306 закрыт для внешнего доступа, по которому осуществляется связь с MySQL, мы не можем удаленно, из нашего приложения осуществлять доступ к базе данных. По этому мы создадим php скрипт в котором будет осуществляться доступ к нашей БД, чтение и запись данных и расположим его на сервере, а из приложения уже будем получать данные через этот скрипт.
И так создайте следующий php-скрипт:

?PHP
// Connect to Database
$link = mysql_connect( "hostname", "username", "password" ) or die( mysql_error() );
mysql_select_db( "databasename" ) or die( mysql_error() );

// Get Data
$name = $_POST['name']; //Get name from Unity
$score = $_POST['score']; //Get score from Unity
$action = $_POST[ 'action' ]; //Get request action from Unity
$unityHash = $_POST[ 'hash' ]; //Get hash key from Unity

//Секретный ключ для шифрования данных при передаче
$secretKey="BRIGHTWORLDGAMES"; 

$phpHash = md5($name."-".$score."-".$secretKey);

switch ( $action )
{
 case "GetScore":
  GetScores();
  break;
 case "PostScore":
  if( $phpHash == $unityHash ) {
   PostScore();
  }
  break;
 default:
  GetScores();
  break;
}

////////////////////////////////////////////////////////////////////////////////////////
function PostScore()
{   
 $score = $_POST[ 'score' ]; //score pass from Unity
 $name  = $_POST[ 'name' ]; //name pass from Unity
 
 //scores = имя вашей БД
 //name = Первый столбец
 //score = второй столбец
 $query = "INSERT INTO scores ( name, score ) VALUES ( '" . $name . "', '" . $score . "')";
 
 mysql_query( $query ) or die( mysql_error() );
}
////////////////////////////////////////////////////////////////////////////////////////
function GetScores()
{ 
 if( $_POST[ 'size' ] != "" ) {
  $size = $_POST[ 'size' ];
 } else {
  $size = 10;
 }

 $query = "SELECT * FROM scores ORDER BY score DESC LIMIT " . $size;
 $results = mysql_query( $query ) or die( mysql_error() );
 
 //Return XML String to Unity
 echo "\n";
 echo "\n";
 if( mysql_num_rows( $results ) > 0 )
 { 
  while( $line = mysql_fetch_array( $results ) ) {
   echo " \n";
  }
 }
 else {
  echo "No entries yet.";
 }
 echo "\n";
}
////////////////////////////////////////////////////////////////////////////////////////
// Close mySQL Connection
mysql_close($link);
?>

     Hostname вы можете посмотреть на панели слева, имя пользователя и пароль к БД должны были прийти вам на почту. Назовите данный скрипт HiScore, и залейте его на сервер через ftp (адрес ftp также можно увидеть на панели слева), в папку “htdocs”. На этом работа с сервером закончена, и можно переходить к клиентской части приложения.

Читать дальше......