На главную
ПРАВИЛА FAQ Помощь Участники Календарь Избранное DigiMania RSS
msm.ru
! Предназначение данного раздела
Данный раздел предназначен для публикации уроков и примеров по разработке компьютерных игр любого сорта, в том числе авторских проектов участников нашего форума. Главное условие публикации: необходимо не только выложить свое творение, но и подробно описать процесс его создания, подводные камни и прочие, интересные для собрата-разработчика, вкусности.

Если вы желаете выложить свой проект - пишите в Общеорганизационную тему. Есть какие-то другие вопросы по делу - туда же.

Модераторы: Da$aD
  
> [MMORPG своими руками] Часть X.2, Взаимодействие Unity клиента с сервером
    Взаимодействие Unity клиента с сервером

    Каждый уважающий себя клиент должен уметь общаться с сервером. Иначе, что это тогда за клиент? :)
    Вот и мы попробуем научить Unity работать с сервером. Практика показывает, что наиболее эффективным
    размещением клиента является браузерное. Так можно завлечь больше людей, которые не очень то хотят качать и устанавливать обычный клиент. Для взаимодействия клиента с сервером обычно используется протокол
    HTTP, он наиболее незаметен для различных злобных админов, которые любят перекрывать все и вся :)

    Итак, имеется Unity клиент, втроенный в браузер, и HTTP сервер (например, php или JEE). Научим их общаться.

    Во-первых, стоит еще раз упомянуть о куках. (Это важно для сессии). Если Unity клиент встроен в браузер, по при отправке запросов, браузер сам прицепит к запросу нужные куки, а также поймает и сохранит отправляемые сервером куки.

    Для отправки запроса сначала необходимо создать объект класса WWW.
    ExpandedWrap disabled
      var link : WWW =new  WWW (url); // для отправки GET запроса
       
      var form : WWWForm = new WWWForm();
      form.AddField("arg","5");
      var link2 : WWW =new  WWW (url,form); // для отправки POST запроса


    Далее, в одном из компонетов, в котором должен обрабатываться ответ, надо в метод Update или OnGUI
    добавить следующий код
    ExpandedWrap disabled
      if(link.isDone){ // ответ пришел?
      if(link.error != null){
          // случилась какая то ошибка, ее текст записан в error
              // однако ошибки, которые выдаются сервером ввиде страничек,
              // таким образом не поймаются
      } else {
          // можем прочитать ответ
              link.data // текст ответа, если ожидается текстовый ответ
              link.bytes  // бинарный вид ответа
          link.texture //если в качестве ответа ожидается картинка
          link.audioClip // если в качестве ответа ожидается звуковой клип
      }}


    Для своего движка я сделал вот такой вот компонент, который будет отвечать за связь с сервером.
    HttpConnector.js
    Скрытый текст
    ExpandedWrap disabled
      var mHostName : String;
      var mErrorCallback;        
      var mRequests : Array = new Array();
      var DELIMITER : char = "#"[0];
       
      /**
          @param url относительный URL обработчика запроса
          @param args аргументы для post запроса, если это post запрос
          @param callback обработчик ответа от сервера
          @param parse необходимо ли парсить ответ в соотвествии с протоколом
                          (true только для текстовых ответов)
      */
      function Request(url : String, args : WWWForm,callback, parse : boolean){
          var request : Array = new Array();
          url = mHostName + url;
          var link : WWW = (args == null)?(new  WWW (url)):(new  WWW (url,args));
          request.Push(link);       // 0
          request.Push(callback); // 1
          request.Push(parse);    // 2
          mRequests.Push(request);
      }
       
      /**
          Текстовый протокол ответа предполагает такой формат
          answer: field+ ;
          field: size '#' body ;
          size: ('0'..'9')+ ;
          
          @return массив текстовых полей
      */
      function ParseResponse(response : String){
          var result : Array = new Array();
          var buffer : String = "";
          var header : boolean = true;
          var field_size : int = 0;
          
          for(var i : int = 0; i < response.Length; i++) {
              var cur : char = response[i];
              
              if(header){
              
                  if(cur == DELIMITER){
                      field_size = int.Parse(buffer);
                      header = false;
                      buffer = "";
                  } else {
                      buffer += cur;
                  }
                  
              } else {
                  buffer += cur;
                  field_size--;
                  
                  if(field_size == 0){
                      result.Push(buffer);
                      buffer = "";
                      header = true;
                  }
              }
          }
          return result;
      }
       
      function Update () {
          for(var i : int = 0 ; i < mRequests.length ; i++){
              var request : Array = mRequests[i];
              var link : WWW = request[0];
              
              if(link.isDone){
                  mRequests.RemoveAt(i);
                  
                  if(link.error != null){
                      mErrorCallback.NetworkError(link.url,link.error);
                  } else {
                  
                      if(request[2]){
                          request[1].ProcessResponse(ParseResponse(link.data));
                      } else {
                          request[1].ProcessResponse(link);
                      }
                  }
              }
          }
      }


    В качестве примера использования могу предложить код юнит теста
    HttpTest.js
    Скрытый текст
    ExpandedWrap disabled
      var mHttpConnector : HttpConnector;
      var mTexture : Texture;
       
      function Start(){
          mHttpConnector.mErrorCallback = this;
      }
       
      function NetworkError(url : String, err : String){
          print("Error for "+url);
          print("because: " + err);
      }
       
      function ProcessResponse(anwer : Array){
          print(anwer);
      }
       
      function ProcessResponse(link : WWW){
          mTexture = link.texture;
      }
       
      function OnGUI () {
          
          if(mTexture != null){
              GUI.DrawTexture(Rect(150,5,80,20),mTexture);
          }
          
          if(GUI.Button(Rect(5,5,100,30),"Test 1")){
              mHttpConnector.Request("test.php",null,this,true);
          }
          
          if(GUI.Button(Rect(5,40,100,30),"Test 2")){
              var form : WWWForm = new WWWForm();
              form.AddField("arg","5");
              mHttpConnector.Request("test2.php",form,this,true);
          }
          
          if(GUI.Button(Rect(5,75,100,30),"Test 3")){
              mHttpConnector.Request("test3.php",null,this,false);
          }
      }

    текст php скриптов
    test.php
    Скрытый текст
    ExpandedWrap disabled
      <?php
      session_start();
      $_SESSION['x'] = 1;
      print "5#Hello5#World6#Its me";
      ?>

    test2.php
    Скрытый текст
    ExpandedWrap disabled
      <?php
      session_start();
      $_SESSION[x] = $_SESSION[x] + 1;
      $arg = $_POST['arg'] + $_SESSION[x];
      if($arg<=9){
          print "1#".$arg;
      } else if($arg<=99){
          print "2#".$arg;
      } else {
          print "3#".$arg;
      }
      ?>

    test3.php
    Скрытый текст
    ExpandedWrap disabled
      <?php
      $im = @imagecreate (80, 20);
      $bg = imagecolorallocate ($im, 232, 238, 247);
      $char = "1234";
      for ($i=0; $i<=128; $i++){
          $color = imagecolorallocate ($im, rand(0,255), rand(0,255), rand(0,255));
          imagesetpixel($im, rand(2,80), rand(2,20), $color);
      }
      for ($i = 0; $i < strlen($char); $i++){
          $color = imagecolorallocate ($im, rand(0,255), rand(0,128), rand(0,255));
          $x = 5 + $i * 20;
          $y = rand(1, 6);
          imagechar ($im, 5, $x, $y, $char[$i], $color);
      }
      header("Content-type: image/jpeg");
      imagejpeg($im);
      imagedestroy ($im);
      ?>


    В аттаче результаты выполнение тестового скрипта (правда в дебаг режиме, без браузера)
    Сообщение отредактировано: impik777 -

    Прикреплённая картинка
    Прикреплённая картинка
      А не проще и оптимальней было бы использовать yield вместо перебора всех запросов в апдейте и проверки IsDone?
        0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
        0 пользователей:


        Рейтинг@Mail.ru
        [ Script Execution time: 0,1142 ]   [ 18 queries used ]   [ Generated: 21.11.18, 16:08 GMT ]