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

22 авг. 2014 г.

AppCent - cайт для заработка денег путем установок приложений на Android, iOS.


ссылка: AppCent
После регистрации, в личном аккаунте на вкладке "Приложения" отображается список приложений и сумма денег, которые будут зачислены на счет после установки приложения. То, что скрыто под катом Читать дальше......

7 мая 2013 г.

C# Создание Windows Service

C# Создание Windows Service
Для создания сервиса использовалась среда Visual Studio 2010.
1. Откройте студию и создайте новый проект
2. Для того чтобы службу можно было установить необходимо добавить в проект installer.
В Sulution Explorer дважды щелкните по классу "Service1.cs", в появившемся окне щелкните правой кнопкой мыши и выберите "Add Installer". Появится новый класс "ProjectInstaller.cs" с двумя компонентами: "serviceProcessInstaller" и "serviceInstaller".
Установите свойства этих компонентов как показано на рисунках:

serviceProcessInstaller

serviceInstaller 3. Откройте код файла "Service1.cs". Здесь мы видим два метода "OnStart" и "OnStop" которые срабатывают при запуске и остановке сервиса соответственно.
Допустим нам необходимо чтобы наш сервис каждую секунду записывал строку в файл.
Для этого создадим отдельный поток который будет запускаться при старте сервиса в методе "OnStart". В данном котором будем производить запись в файл:
private readonly Thread workerThread;
        public Service1()
        {
            InitializeComponent();

            workerThread = new Thread(DoWork);
            workerThread.SetApartmentState(ApartmentState.STA);
        }

В методе "DoWork" реализуем запись в файл:
  private static void DoWork()
        {
            while (true)
            {
                string fname = @"c:\temp\temp.txt";
                using (StreamWriter stream = new StreamWriter(fname, true))
                {
                   stream.WriteLine("Hello World!");
                }
                // do some work, then
                Thread.Sleep(1000);
            }
        }

Теперь при старте сервера будем запускать поток, а при остановке сервера - останавливать поток:
        protected override void OnStart(string[] args)
        {
            workerThread.Start();
        }

        protected override void OnStop()
        {
            workerThread.Abort();
        }
    }

Добавим также метод который будет записывать в лог нашего сервиса события запуска и остановки сервера:
           public void AddLog(string log)
        {
            try
            {
                if (!EventLog.SourceExists("MyExampleService"))
                {
                    EventLog.CreateEventSource("MyExampleService", "MyExampleService");
                }
                eventLog1.Source = "MyExampleService";
                eventLog1.WriteEntry(log);
            }
            catch { }
        }


И будем вызывать его при запуске и остановке сервера.
Полностью код будет выглядеть следующим образом
          
   public partial class Service1 : ServiceBase
    {
        private readonly Thread workerThread;

        public Service1()
        {
            InitializeComponent();

            workerThread = new Thread(DoWork);
            workerThread.SetApartmentState(ApartmentState.STA);
        }

        protected override void OnStart(string[] args)
        {
            
            AddLog("Service is started");
            string fname = @"c:\temp\temp.txt";
            using (StreamWriter stream = new StreamWriter(fname, true))
            {
                stream.WriteLine("Служба запущена!");
            }
            workerThread.Start();
        }

        protected override void OnStop()
        {
            AddLog("Service is stopped");
            string fname = @"c:\temp\temp.txt";
            using (StreamWriter stream = new StreamWriter(fname, true))
            {
                stream.WriteLine("Служба остановлена!");
            }
            workerThread.Abort();
        }

        public void AddLog(string log)
        {
            try
            {
                if (!EventLog.SourceExists("MyExampleService"))
                {
                    EventLog.CreateEventSource("MyExampleService", "MyExampleService");
                }
                eventLog1.Source = "MyExampleService";
                eventLog1.WriteEntry(log);
            }
            catch { }
        }


        private static void DoWork()
        {
            while (true)
            {
                string fname = @"c:\temp\temp.txt";
                using (StreamWriter stream = new StreamWriter(fname, true))
                {
                   stream.WriteLine("Hello World!");
                }
                // do some work, then
                Thread.Sleep(1000);
            }
        }
    
    }

После того как сервис создан, его необходимо установить. В этом нам поможет утилита "installutil.exe", которая распространяется вместе с фраемворком.
Создайте батник со следующим содержимым
    
C:\Windows\Microsoft.NET\Framework\v4.0.30319\installutil.exe E:\MyProjects\test\WindowsService1\WindowsService1\bin\Debug\WindowsService1.exe 
pause

здесь запускается утилита "installutil.exe", которой в качестве указывается наш сервис
запустите созданный батник из командной строки
если установка сервиса прошла успешно вы увидите сообщения:
"The Commit phase completed successfully".
"The transacted install has completed"

Теперь можно запустить наш сервер и посмотреть результат его выполнения
Зайдите в "Панель управления -> Администрирование -> Службы". Найдите установленную вами службу и запустите её
Теперь можно открыть созданный файл и посмотреть результат работы нашей службы
Как видно служба прекрасно отрабатывает
Теперь остановите службу.
Также в логе службы мы можем просмотреть когда наша служба запускалась и останавливалась
Зайдите в "Панель управления -> Администрирование -> Просмотр событий -> Журнал приложений и служб".
Здесь мы можем увидеть когда наша служба запускалась и останавливалась
Читать дальше......

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,  и установите нужные настройки в скрипте. 
                Анимация готова! Можете запустить проект и любоваться.
Читать дальше......

10 мар. 2012 г.

Blender 2.6 Hot Key (горячие клавиши).

 Горячие клавиши Blender 2.6 
     Общие:      
  1.  F12 – рендер изображения.
  2.  F1 – открыть файл.
  3.  F2 – сохранить файл.
  4.  Space – вызывает меню поиска по командам Blender.
  5.  Shift + F – режим полета камеры.
  6.  Shift + Space – полноэкранный режим просмотра.


Перемещение в пространстве:
  1. Клавиши на дополнительной цифровой клавиатуре: 1,3,7 – вид спереди, справа и сверху соответственно. 0– вид из камеры, .(точка) – сфокусироваться на объекте. 5 – переключение между ортогональным и перспективным отображением. 2,8,4,6 – вращение – вниз, вверх, влево и вправо соответственно. +, - - масштабирование. 
  2. Ctrl + 1,3,7 – вид сзади, слева, снизу. Ctrl + 2,8,4,6 – перемещение вниз, вверх, влево и вправо. Ctrl + 5 –сфокусироваться на курсоре.
  3. ЛКМ – перемещение курсора. Курсор определяет место, где будет создаваться новый объект. 
  4. ПКМ – щелчок правой кнопкой мыши объекту выделяет этот объект (в объектном режиме).
  5. Зажатое среднее колесо мыши + перемещение мыши – вращение вокруг сцены.
  6. Зажатое среднее колесо мыши + Shift + перемещение мыши – передвижение.
  7. Зажатое среднее колесо мыши + Ctrl + перемещение мыши – масштабирование.
  8. T – открытие панели инструментов.
  9. N – открытие панели трансформации.
  10. Tab – переход между объектным режимом(Object Mode) и режимом редактирования (Edit Mode).


 Объектный режим (Object Mode):
Объектный режим предназначен для изменения объекта в целом.
  1. Shift + A – вызов меню добавления объектов.
  2. Shift + S – вызов меню точного расположения курсора. (and Edit Mode)
  3. R – вращение объекта (если нажать х или у или z вращение будет происходить вокруг соответствующей оси). (and Edit Mode)
  4. G – перемещение объекта (если нажать х или у или z перемещение будет происходить относительно соответствующей оси). (and Edit Mode)
  5. S – масштабирование (если нажать х или у или z масштабирование будет происходить относительно соответствующей оси). (and Edit Mode)
  6. Shift+D – создание копии объекта.
  7. Del или X – удаление выделенного объекта.
  8. Z – переход между заполненным и каркасным видом отображения объекта (and Edit Mode).
  9. Alt + Z – переход между текстурированным и затененным видами объектов. (and Edit Mode).
  10. Ctrl + Z – отмена последнего действия.
  11. Ctrl + Shift + Z – повторить последнее отмененное действие.
  12. Ctrl+J – объединение выделенных объектов.
  13. M – перемещение выделенных объектов в другие слои.
  14. [~] – объединение всех слоев.


 Режим редактирования (Edit Mode):
 Режим редактирования предназначен для изменения формы объекта.
  1. Shift + A – вызов меню добавления объектов (добавленный объект будет объединён с текущим объектом).
  2. Shift+D – создание копии объекта (скопированный объект будет объединен с исходным).
  3. ПКМ – выделение вершин, ребер или граней.
  4. Ctrl+Tab – изменения режима выделения(вершины, грани, ребра).
  5. ПКМ + Shift – выделение нескольких вершин, граней, ребер.
  6. B – выделение прямоугольником.
  7. С – выделение окружностью. (с помощью колесика мыши или кнопок +, -, можно менять размер окружности).
  8. A – выделение всех вершин. (повторное нажатие – снятие выделения).
  9. E – экструдирование выделенных вершин, можно перемещать +G, вращать +R, масштабировать +Z.
  10. Esc – отменяет работу с текущим инструментом выделения.
  11. Del или X – вызов контекстного меню выбора удаляемых объектов.
  12. W – вызывает меню “Specials” со специфичными для данного объекта параметрами преобразования.
  13. K – инструмент разрезания граней. Щелкайте ЛКМ в нужном месте грани чтобы разрезать её. Если нажатьCtrl – курсор будет расположен по середине грани.
  14. Ctrl+R – режим разрезания граней.
  15. P – отделить выделенные вершины от остального объекта. (или объединить в один объект выделенные вершины).
  16. F – создает грань между выделенными вершинами. 
  17. Ctrl+F – открывает меню граней, для доступа к дополнительным параметрам граней.
Читать дальше......

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”. На этом работа с сервером закончена, и можно переходить к клиентской части приложения.

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

6 окт. 2010 г.

Использование Google Maps в Android

   Google Maps API позволяет добавлять в Android приложения возможность работы с картами Google. Чтобы подключить карты к вашему проекту, вам необходимо выполнить следующие шаги:
  1. Создать новый проект Android на базе библиотек Google API;
  2. Создать новый Android Virtual Device - c возможностью работы с Google API;
  3. Получить Map API Key;
  4. Подключить к проекту необходимые библиотеки и использовать классы Google Maps.


Шаг первый:

   Запустите Eclipse, создайте новый Android Project, можете назвать его HelloMap, и в поле Build Target  выберете Google APIs. Если у вас в Build Target нет Google APIs, значит у вас не установлен пакет с данным API. Пройдите Windows->Android SDK and AVD Manager->Installed Pakages, нажмите Update All... и установите пакет с Google API.

Шаг второй:

   Теперь нужно создать Android Virtual Device который имеет возможность работы с Google API. Пройдите Windows->Android SDK and AVD Manager->Virtual Devices. Нажмите New и в поле Target выберете Google APIs. Теперь можете запустите созданный эмулятор.

Шаг третий:

  Получение Map API Key. Для того чтобы иметь возможность отображать Google карты, вам необходимо использовать бесплатный Google Map API Key. Чтобы получить ключ необходимо выполнить следующие шаги:
  1. Найдите файл debug.keystore, он располагается в папке "C:\Documents and Settings\<User Name>\.android". Скопируйте данный файл в папку C:\(к примеру можете создать папку Android "C:\Android").
  2. Из данного keystore необходимо получить MD5 код. Для этого используйте утилиту keytool.exe которая поставляется вместе с JDK и располагается в папке "C:\Program Files\Java\<jdk using version>\bin".
  3. Запустите командную строку Пуск->Все программы->стандартные->командная строка. Перейдите в папку с keytool ("cd C:\Program Files\Java\<jdk uses version>\bin") и выполните следующую команду:
  4. keytool.exe -list -alias androiddebugkey -keystore "C:\android\debug.keystore" -storepass android -keypass android
    
    После выполнения данный команды вы должны увидеть на экране свой MD5 код.
  5. Скопируйте полученный MD5 и пройдите по ссылке http://code.google.com/intl/ru-RU/android/maps-api-signup.html. Следуйте инструкциям и получите свой API Key.



Шаг четвёртый:

   Для того чтобы использовать Google Maps API необходимо подключить библиотеку для работы с картами <uses-library android:name="com.google.android.maps"> и так как наше приложение будет загружать карты через интернет нужно позволить ему работать с интернетом INTERNET permission
   Откройте AndroidManifest.xml и добавьте в него <uses-library> и INTERNET permission:

    
        
            
                
                
            
        
 
 
    
      
    
    

 

Отображение карты.
   для того чтобы отобразить карты измените main.xml из папке res\layout. Вы должны использовать <com.google.android.maps.MapView> элемент, чтобы отобразить карту в вашем Activity.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="fill_parent" 
    android:layout_height="fill_parent">
 
    <com.google.android.maps.MapView 
        android:id="@+id/mapView"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:enabled="true"
        android:clickable="true"
        android:apiKey="Ваш API Key"
        />
 
</RelativeLayout>


   Теперь откройте HelloMap.Activity, данный класс должен быть унаследован от MapActivity. При наследовании от класса MapActivity необходимо переопределить метод isRoyteDisplayed():


package com.alukardev.hellomap2;

import com.google.android.maps.MapActivity;
import com.google.android.maps.MapView;
import android.os.Bundle;

public class HelloMapActivity extends MapActivity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }

 @Override
 protected boolean isRouteDisplayed() {
  // TODO Auto-generated method stub
  return false;
 }
}


   Всё готово! Теперь можете запустить проект и посмотреть результат.


Масштабирование.
   Добавим в наш проект возможность масштабировать карту.
   Откройте main.xml и добавьте в него <LinearLayout>:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="fill_parent" 
    android:layout_height="fill_parent">
 
    <com.google.android.maps.MapView 
        android:id="@+id/mapView"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:enabled="true"
        android:clickable="true"
        android:apiKey="0oJHawmPUco4Y2eJDV8r5cKv4kUseLVglm4-e0g"
        />
        
        <LinearLayout android:id="@+id/zoom" 
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content" 
        android:layout_alignParentBottom="true" 
        android:layout_centerHorizontal="true" 
        /> 
 
</RelativeLayout>
<LinearLayout> элемент нужен чтобы отобразить на нем кнопки масштабирования.

   Теперь откройте  HelloMapActivity.java. Импортируйте следующие библиотеки:

import com.google.android.maps.MapView.LayoutParams;  
import android.view.View;
import android.widget.LinearLayout;
   Добавьте следующий код после строчки  setContentView(R.layout.main);

mapView = (MapView) findViewById(R.id.mapView);
        LinearLayout zoomLayout = (LinearLayout)findViewById(R.id.zoom);  
        View zoomView = mapView.getZoomControls(); 
 
        zoomLayout.addView(zoomView, 
            new LinearLayout.LayoutParams(
                LayoutParams.WRAP_CONTENT, 
                LayoutParams.WRAP_CONTENT)); 
        mapView.displayZoomControls(true);

   Файл HelloMapActivity.java полностью:

package com.alukardev.hellomap2;

import com.google.android.maps.MapActivity;
import com.google.android.maps.MapView;
import android.os.Bundle;
import com.google.android.maps.MapView.LayoutParams;  
import android.view.View;
import android.widget.LinearLayout;

public class HelloMapActivity extends MapActivity 
{
 MapView mapView; 
 
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        mapView = (MapView) findViewById(R.id.mapView);
        LinearLayout zoomLayout = (LinearLayout)findViewById(R.id.zoom);  
        View zoomView = mapView.getZoomControls(); 
 
        zoomLayout.addView(zoomView, 
            new LinearLayout.LayoutParams(
                LayoutParams.WRAP_CONTENT, 
                LayoutParams.WRAP_CONTENT)); 
        mapView.displayZoomControls(true);
    }

 @Override
 protected boolean isRouteDisplayed() {
  // TODO Auto-generated method stub
  return false;
 }
}

   Теперь можете запустить проект и посмотреть результат.


  В качестве альтернативного решения можно использовать клавиши для масштабирования, для этого нужно вызывать методы zoomIn() и zoouOut() класса MapController:
package com.alukardev.hellomap2;

import com.google.android.maps.MapActivity;
import com.google.android.maps.MapController;
import com.google.android.maps.MapView;
import android.os.Bundle;
import com.google.android.maps.MapView.LayoutParams;  

import android.view.KeyEvent;
import android.view.View;
import android.widget.LinearLayout;

public class HelloMapActivity extends MapActivity 
{
 MapView mapView;
 
  public boolean onKeyDown(int keyCode, KeyEvent event) 
     {
         MapController mc = mapView.getController(); 
         switch (keyCode) 
         {
             case KeyEvent.KEYCODE_3:
                 mc.zoomIn();
                 break;
             case KeyEvent.KEYCODE_1:
                 mc.zoomOut();
                 break;
         }
         return super.onKeyDown(keyCode, event);
     }    
 
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        mapView = (MapView) findViewById(R.id.mapView);
        LinearLayout zoomLayout = (LinearLayout)findViewById(R.id.zoom);  
        View zoomView = mapView.getZoomControls(); 
 
        zoomLayout.addView(zoomView, 
            new LinearLayout.LayoutParams(
                LayoutParams.WRAP_CONTENT, 
                LayoutParams.WRAP_CONTENT)); 
        mapView.displayZoomControls(true);
    }

 @Override
 protected boolean isRouteDisplayed() {
  // TODO Auto-generated method stub
  return false;
 }
}


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