整合營(yíng)銷服務(wù)商

          電腦端+手機(jī)端+微信端=數(shù)據(jù)同步管理

          免費(fèi)咨詢熱線:

          Unity游戲教程初步(五):Resources與U

          Unity游戲教程初步(五):Resources與UI

          在上一節(jié)中我們給球體添加了紋理,并且為場(chǎng)景設(shè)置了一個(gè)目的區(qū)域。當(dāng)球體處于目的區(qū)域內(nèi)時(shí),其將變色。在這一節(jié)里,我們將完善球體在到達(dá)目的區(qū)域時(shí)游戲的反饋,增加音樂和UI顯示。

          項(xiàng)目需求

          增加小球進(jìn)入目的區(qū)域的音效。

          增加計(jì)分的UI界面。

          增加音效

          -本節(jié)相關(guān)內(nèi)容請(qǐng)讀者參考:

          -https://docs.unity.cn/cn/current/ScriptReference/Resources.html,《Resources》

          -https://docs.unity.cn/cn/current/Manual/class-AudioSource.html,《音頻源》

          我們可以用兩個(gè)方法將音效素材導(dǎo)入到游戲。第一個(gè)就是按照上一節(jié)綁定變量的方法,將音效素材作為JudgeController的屬性綁定到類中;第二個(gè)是使用Resources文件夾。同時(shí),為了讓JudgeController可以播放音樂,我們需要為其添加一個(gè)Audio Source組件。

          Resources文件夾是一類文件夾,其文件夾名為Resources,位于工程目錄下的Assets文件夾內(nèi)(不需要位于根目錄下,比如Assets\a\Resources也有效)。我們可以在腳本中使用Resources.Load來訪問Resources文件夾下的文件。

          第一種方法因?yàn)橐呀?jīng)在前面使用過了,所以在這里我們不多贅述,來看第二種方法。由于unity預(yù)設(shè)建立的項(xiàng)目中沒有Resources文件夾,我們先在Assets文件夾下建立一個(gè)Resources文件夾,然后將音效文件放進(jìn)去。

          然后碼代碼:

          using System.Collections;
          
          using System.Collections.Generic;
          
          using UnityEngine;
          
          public class JudgeController : MonoBehaviour
          
          {
          
              public GameObject sphere; //球體的引用
          
              //近點(diǎn)和遠(yuǎn)點(diǎn)分別是目的區(qū)域離原點(diǎn)最近和最遠(yuǎn)的點(diǎn)
          
              public Vector3 nearP=new Vector3(2.5f,0,2.5f); //近點(diǎn)
          
              public Vector3 farP=new Vector3(5,0,5); //遠(yuǎn)點(diǎn)
          
              private AudioClip m; 
          
              bool hasClip=false; //標(biāo)志,球體在一次進(jìn)出是否播放過音效
          
              // Start is called before the first frame update
          
              void Start()
          
              {
          
                  m=Resources.Load<AudioClip>("001"); //加載Assets/.../Resources/001.*
          
              }
          
              // Update is called once per frame
          
              void Update()
          
              {
          
                  Vector3 p=sphere.GetComponent<Transform>().position; //位置
          
                  if(p.x>nearP.x && p.x<farP.x && p.z>nearP.z &&p.z<farP.z){
          
                      //小球中心點(diǎn)在目的區(qū)域內(nèi)
          
                      GetComponent<AudioSource>().clip=m;
          
                      if(!hasClip){
          
                          GetComponent<AudioSource>().Play(); //播放
          
                          hasClip=true;
          
                      }
          
                      sphere.GetComponent<Sphere>().changeMaterial(true);  //調(diào)用Sphere的函數(shù)
          
                  }else{
          
                      //不在區(qū)域內(nèi),變回來
          
                      hasClip=false;
          
                      sphere.GetComponent<Sphere>().changeMaterial(false);
          
                  }
          
              }
          
          }

          增加UI

          -本節(jié)相關(guān)內(nèi)容請(qǐng)讀者參考:

          -https://docs.unity.cn/cn/current/Manual/UISystem.html,《UI》

          -https://docs.unity.cn/cn/current/Manual/UICanvas.html,《畫布》

          UI是User Interface(用戶界面)的縮寫。大多數(shù)游戲都會(huì)有UI,用于記錄游戲的得分情況等信息。在unity中,UI必須作為Canvas(畫布)的子項(xiàng)存在。如果直接創(chuàng)建UI,unity會(huì)在此之前自動(dòng)創(chuàng)建一個(gè)Canvas并將被創(chuàng)建的UI作為子項(xiàng)。

          Hierarchy->UI->Text,創(chuàng)建一個(gè)TextUI,我們命名為Bonus。設(shè)定初始分?jǐn)?shù)為0,球體進(jìn)入目的區(qū)域時(shí)分?jǐn)?shù)加1。改寫JudgeController的代碼:

          using System.Collections;
          
          using System.Collections.Generic;
          
          using UnityEngine;
          
          using UnityEngine.UI;
          
          public class JudgeController : MonoBehaviour
          
          {
          
              public GameObject sphere; //球體的引用
          
              public GameObject bonusUI; //顯示分?jǐn)?shù)的UI
          
              //近點(diǎn)和遠(yuǎn)點(diǎn)分別是目的區(qū)域離原點(diǎn)最近和最遠(yuǎn)的點(diǎn)
          
              public Vector3 nearP=new Vector3(2.5f,0,2.5f); //近點(diǎn)
          
              public Vector3 farP=new Vector3(5,0,5); //遠(yuǎn)點(diǎn)
          
              private AudioClip m; //音效文件
          
              private int bonus; //分?jǐn)?shù)
          
              bool hasClip=false; //標(biāo)志,球體在一次進(jìn)出是否播放過音效
          
              // Start is called before the first frame update
          
              void Start()
          
              {
          
                  bonus=0;
          
                  m=Resources.Load<AudioClip>("001"); //加載Assets/.../Resources/001.*
          
              }
          
              // Update is called once per frame
          
              void Update()
          
              {
          
                  Vector3 p=sphere.GetComponent<Transform>().position; //位置
          
                  if(p.x>nearP.x && p.x<farP.x && p.z>nearP.z &&p.z<farP.z){
          
                      //小球中心點(diǎn)在目的區(qū)域內(nèi)
          
                      GetComponent<AudioSource>().clip=m;
          
                      if(!hasClip){
          
                          bonus++;
          
                          bonusUI.GetComponent<Text>().text=bonus.ToString(); //更新分?jǐn)?shù)
          
                          GetComponent<AudioSource>().Play(); //播放
          
                          hasClip=true;
          
                      }
          
                      sphere.GetComponent<Sphere>().changeMaterial(true);  //調(diào)用Sphere的函數(shù)
          
                  }else{
          
                      //不在區(qū)域內(nèi),變回來
          
                      hasClip=false;
          
                      sphere.GetComponent<Sphere>().changeMaterial(false);
          
                  }
          
              }
          
          }

          可以看到我們?cè)黾恿艘粋€(gè)引用bonusUI,將這個(gè)變量與Bonus綁定。然后調(diào)整Bonus的大小和其Text的內(nèi)容(由于后續(xù)內(nèi)容由JudgeController控制,這里只需要將Text置為0即可)。

          # TextMeshPro-Text

          同樣是UI,TextMeshPro可以被看做是Text的升級(jí)版。因?yàn)槲臋n里沒有與其相關(guān)的資料,所以在這里筆者會(huì)簡(jiǎn)單描述一下與它有關(guān)的信息。

          TextMeshPro又稱為TMP,一開始是一個(gè)外部插件,在最近的版本中才被包含進(jìn)unity本體中。TMP采用了SDF文字渲染技術(shù),相比原生的Text組件它能保證文字在縮放數(shù)倍后仍然保持平滑(其實(shí)就是矢量繪圖)。

          但是保持文字的平滑自然需要代價(jià),TMP會(huì)為字體創(chuàng)建一個(gè)紋理集,而此紋理集在字體所屬語言為中文的情況下會(huì)占用較大的空間。

          而TMP也不只有這一個(gè)長(zhǎng)處,TMP還可以設(shè)置文字的描邊顏色漸變等,并且可以圖文混用。

          增加得分點(diǎn)

          -本節(jié)相關(guān)內(nèi)容請(qǐng)讀者參考:

          -https://docs.unity.cn/cn/current/ScriptReference/Random.html,《Random》

          既然已經(jīng)有了一套基礎(chǔ)的得分系統(tǒng),不妨在之前的基礎(chǔ)上增加一個(gè)得分點(diǎn),比如說,讓平面上的正方體在進(jìn)入得分區(qū)域時(shí)重置位置并且得分。

          按照之前的思路,修改JudgeController,并給Cube添加腳本:

          JudgeController.cs(注:前文中對(duì)于近點(diǎn)/遠(yuǎn)點(diǎn)的定義有誤,在這里更正)

          using System.Collections;
          
          using System.Collections.Generic;
          
          using UnityEngine;
          
          using UnityEngine.UI;
          
          public class JudgeController : MonoBehaviour
          
          {
          
              public GameObject sphere; //球體的引用
          
              public GameObject bonusUI; //顯示分?jǐn)?shù)的UI
          
              public GameObject cube; //正方體的引用
          
              //近點(diǎn)和遠(yuǎn)點(diǎn)分別是目的區(qū)域離xy最大的點(diǎn)和xy最小的點(diǎn)
          
              public Vector3 nearP=new Vector3(2.5f,0,2.5f); //近點(diǎn)
          
              public Vector3 farP=new Vector3(5,0,5); //遠(yuǎn)點(diǎn)
          
              private AudioClip m; //音效文件
          
              private int bonus; //分?jǐn)?shù)
          
              bool hasClip=false; //標(biāo)志,球體在一次進(jìn)出是否播放過音效
          
              // Start is called before the first frame update
          
              void Start()
          
              {
          
                  bonus=0;
          
                  m=Resources.Load<AudioClip>("001"); //加載Assets/.../Resources/001.*
          
              }
          
              bool comPosition(Vector3 p)
          
              { //比較傳入點(diǎn)與近點(diǎn)/遠(yuǎn)點(diǎn)的相對(duì)位置,內(nèi)部函數(shù)
          
                  if(p.x>nearP.x && p.x<farP.x && p.z>nearP.z &&p.z<farP.z){
          
                      return true;
          
                  }else{
          
                      return false;
          
                  }
          
              }
          
              // Update is called once per frame
          
              void Update()
          
              {
          
                  Vector3 p=sphere.GetComponent<Transform>().position; //位置
          
                  if(this.comPosition(p)){
          
                      //小球中心點(diǎn)在目的區(qū)域內(nèi)
          
                      GetComponent<AudioSource>().clip=m;
          
                      if(!hasClip){
          
                          bonus++;
          
                          bonusUI.GetComponent<Text>().text=bonus.ToString(); //更新分?jǐn)?shù)
          
                          GetComponent<AudioSource>().Play(); //播放
          
                          hasClip=true;
          
                      }
          
                      sphere.GetComponent<Sphere>().changeMaterial(true);  //調(diào)用Sphere的函數(shù)
          
                  }
          
                  else{
          
                      //不在區(qū)域內(nèi),變回來
          
                      hasClip=false;
          
                      sphere.GetComponent<Sphere>().changeMaterial(false);
          
                  }
          
                  Vector3 c=cube.GetComponent<Transform>().position;
          
                  if(this.comPosition(c)){
          
                      //一旦抵達(dá)目標(biāo)地點(diǎn),就開始傳送,所以不需要額外標(biāo)志,也沒有else
          
                      cube.GetComponent<Cube>().transmit(nearP,farP);
          
                      bonus+=2;
          
                      bonusUI.GetComponent<Text>().text=bonus.ToString(); //更新分?jǐn)?shù)
          
                  }
          
              }
          
          }

          Cube.cs

          using System.Collections;
          
          using System.Collections.Generic;
          
          using UnityEngine;
          
          using Random=UnityEngine.Random;
          
          public class Cube : MonoBehaviour
          
          {
          
              public GameObject plane; //平臺(tái),用于計(jì)算區(qū)域長(zhǎng)度
          
              // Start is called before the first frame update
          
              void Start()
          
              {
          
              }
          
              // Update is called once per frame
          
              void Update()
          
              {
          
              }
          
              float comVxy(float far,float near,float width){ //封裝內(nèi)部函數(shù)
          
                  if(far<width){ //換成near>-width也是一樣的,因?yàn)槟康膮^(qū)域必然不大于整個(gè)區(qū)域,所以只要比較一個(gè)
          
                      if(Random.value>0.5){
          
                          return Random.Range(far,width);
          
                      }
          
                      else{
          
                          return Random.Range(-1*width,near);
          
                      }
          
                  }
          
                  else{
          
                      return Random.Range(-1*width,near);
          
                  }
          
              }
          
              public void transmit(Vector3 near,Vector3 far){ 
          
                  //以0,0,0為中心的情況下,給出:整個(gè)區(qū)域長(zhǎng)度、目的區(qū)域近點(diǎn)和遠(yuǎn)點(diǎn) 將正方體傳送到整個(gè)區(qū)域之內(nèi),目的區(qū)域之外
          
                  //設(shè)定平面長(zhǎng)寬相等,生成在與目的區(qū)域相對(duì)的區(qū)域內(nèi)
          
                  Vector3 v2=new Vector3(0,-4.5f,0);
          
                  float myWidth=GetComponent<Transform>().localScale.x*0.5f; //由于算的是物體中心的位置,要減去到中心的距離
          
                  float width=plane.GetComponent<Transform>().localScale.x*5-myWidth;
          
                  v2.x=this.comVxy(far.x,near.x,width);
          
                  v2.z=this.comVxy(far.z,near.z,width); //筆者的實(shí)例里y軸朝上
          
                  transform.localPosition=v2; //這里是相對(duì)坐標(biāo)
          
                  print(v2);
          
              }
          
          }

          可以看到在Cube.cs中,我們傳送物體使用的是transform.localPosition(GetComponent<Transform>().localPosition),而非position。這是因?yàn)楣P者在之前建立了一個(gè)空游戲?qū)ο笞鳛镃ube的父對(duì)象,而這里需要對(duì)正方體的父對(duì)象定位(如果沒有父對(duì)象localPosition就與position相同)。我們把position稱為世界位置,而localPosition則是相對(duì)位置。position是游戲?qū)ο笤诮^對(duì)坐標(biāo)系下(世界坐標(biāo)系,也就是無父對(duì)象時(shí)Transform面板顯示的坐標(biāo))的位置,而localPosition則是position對(duì)游戲?qū)ο蟮乃懈笇?duì)象的位置進(jìn)行變換之后的位置。例如在場(chǎng)景下有一個(gè)根游戲?qū)ο驛(1,1,1),其子游戲?qū)ο驜在Transform面板里的坐標(biāo)為(0,1,-1),則B在世界坐標(biāo)系的坐標(biāo)為A+B(1,2,0)。

          由于需要判斷兩個(gè)物體的位置,為了節(jié)省代碼量我們把判斷位置部分的代碼封裝為一個(gè)函數(shù)comPosition(其實(shí)也就是節(jié)省了一行不到,但是也省得寫了)。同時(shí),建議讀者盡量使用unity的Random來生成隨機(jī)數(shù),而不使用C#自帶的Random。

          映維網(wǎng)Nweon 2023年03月15日)Unity的XR Interaction Toolkit(XRI)是一個(gè)基于組件的high level交互系統(tǒng),主要用于創(chuàng)建VR和AR體驗(yàn)。它為交互提供了一個(gè)通用框架,并簡(jiǎn)化了跨平臺(tái)的創(chuàng)建。新發(fā)布的XRI 2.3版本增加了三個(gè)關(guān)鍵功能:

          • 用于實(shí)現(xiàn)更自然交互的眼動(dòng)追蹤和手部追蹤互
          • 令交互變得更為生動(dòng)的視聽可供性
          • 以及改進(jìn)的設(shè)備模擬器

          值得一提的是,XR開發(fā)者兼LearnXR.io創(chuàng)始人迪爾默·瓦萊西洛斯(Dilmer Valecillos)發(fā)布了一個(gè)XRI 2.3視頻教程:而下面我們將介紹XRI 2.3的主要亮點(diǎn):

          https://v.qq.com/x/page/g3506gcwsds.html

          全面支持關(guān)節(jié)式手部追蹤

          與XRI 2.3一起,Unity在預(yù)發(fā)行版中提供了XR Hands package。XR Hands是一個(gè)新的XR子系統(tǒng),它添加了支持手部追蹤的API。它包括OpenXR的內(nèi)置支持,不久將支持Meta平臺(tái)。另外,第三方硬件提供商可以通過API文檔,從現(xiàn)有XR SDK中獲取實(shí)時(shí)追蹤數(shù)據(jù)。

          XRI的這一版本包括Hands Interaction Demo。這個(gè)展示手部交互設(shè)置的示例包允許你在裸手交互和控制器之間切換,無需更改設(shè)備場(chǎng)景中的任何內(nèi)容。使用所述功能,你的內(nèi)容可以從標(biāo)準(zhǔn)控制器設(shè)置開始,但可以無縫過渡到特定任務(wù)或游戲中的自然交互。

          XRI 2.3同時(shí)支持通過XR Poke Interactitor進(jìn)行的自然點(diǎn)戳交互。這允許你在3D UI或啟用XRI的UGUI畫布元素使用裸手或控制器進(jìn)行點(diǎn)戳。

          使用眼睛注視進(jìn)行交互

          像微軟HoloLens 2、Meta Quest Pro和PSVR 2這樣的新頭顯包括可以追蹤用戶視線的傳感器。基于注視的交互可以幫助你構(gòu)建感覺更自然的XR應(yīng)用程序,并提供一種與內(nèi)容交互的額外方式。為了支持這種類型的交互,Unity引入了由眼睛注視或頭部姿勢(shì)驅(qū)動(dòng)的XR Gaze Interactor。你可以使用這個(gè)交互器進(jìn)行直接操作。

          由于Unity通常不建議應(yīng)用程序完全由眼睛控制,所以團(tuán)隊(duì)提供了一種額外的控制器和基于手部的交互輔助形式,從而幫助用戶選擇特定對(duì)象:XR Interactible Snap Volume。這個(gè)組件可以作為XR Gaze Interactor的補(bǔ)充,因?yàn)樗试S在瞄準(zhǔn)對(duì)象周圍的定義區(qū)域時(shí)將交互鎖定至附近的可交互對(duì)象。Snap Volume同時(shí)可以在沒有Gaze Interactor的情況下使用,以便用戶更容易地選擇對(duì)象。

          視聽可供性

          使用裸手進(jìn)行交互與使用控制器不同,因?yàn)闆]有觸覺反饋來確認(rèn)交互何時(shí)發(fā)生。可供性系統(tǒng)可以根據(jù)對(duì)象的交互狀態(tài)動(dòng)畫化對(duì)象動(dòng)或觸發(fā)聲音效果,從而幫助緩解這種反饋差距。

          用雙手拉伸、擺動(dòng)和旋轉(zhuǎn)

          新的XR General Grab Transformer降低了層次結(jié)構(gòu)的復(fù)雜性,并允許一個(gè)通用Transformer在可交互平臺(tái)支持單手和雙手交互,而不是多個(gè)Grab Transformer。它同時(shí)支持雙手縮放,允許你通過移動(dòng)雙手來上下縮放對(duì)象。

          Unity同時(shí)添加了一個(gè)Interaction Group組件,從而允許開發(fā)人員將interactor分組,并按優(yōu)先級(jí)對(duì)其進(jìn)行排序,這使得每個(gè)組在給定時(shí)間只能有一個(gè)interactor進(jìn)行交互。例如,當(dāng)Poke、Direct和Ray interactor組合在一起時(shí),點(diǎn)戳一個(gè)按鈕將暫時(shí)阻止其他interactor與場(chǎng)景交互。

          無頭顯XR迭代變得更容易

          在頭顯測(cè)試XR應(yīng)用程序很重要,但在編輯器中測(cè)試有助于減少迭代時(shí)間。在這個(gè)版本中,團(tuán)隊(duì)優(yōu)化了XR Device Simulator,其中包括一個(gè)新的屏幕UI小組件,從而允許你更容易地查看哪些輸入驅(qū)動(dòng)模擬器,哪些輸入當(dāng)前處于活動(dòng)狀態(tài)。

          Unity同時(shí)添加了新的模擬模式,以便你可以在常用的控制模式之間切換。在啟動(dòng)時(shí),設(shè) XR Device Simulator激活新的第一人稱射擊(FPS)模式,并操作頭顯和兩個(gè)控制器。然后,你可以在其他模式中循環(huán)操作各個(gè)設(shè)備:頭顯、左控制器和右控制器。要使用 XR Device Simulator,請(qǐng)從Package Manager導(dǎo)入示例。

          新的XRI示例項(xiàng)目

          Unity提供了新的示例項(xiàng)目,并用于展示了你可以在XRI 2.3中使用的一系列XR體驗(yàn)構(gòu)建模塊。你可以訪問GitHub的示例項(xiàng)目,并使用它開啟下一個(gè)XR應(yīng)用程序。

          展望未來

          盡管眼手操作依然處于早期階段,但Unity正在努力優(yōu)化體驗(yàn)。隨著邁向XRI 2.4及以上版本,團(tuán)隊(duì)將繼續(xù)根據(jù)用戶反饋來改進(jìn)工具。

          網(wǎng)絡(luò)套接字是在unity webgl 游戲中擴(kuò)展網(wǎng)絡(luò)的一個(gè)好的選擇。網(wǎng)絡(luò)套接字提供兩種現(xiàn)存的連接到服務(wù)器的方式。不幸的是,Unity WebGL中的網(wǎng)絡(luò)套接字這個(gè)時(shí)候會(huì)受限制。Unity團(tuán)隊(duì)中Unity商店中有一個(gè)示例源庫(kù),但是,網(wǎng)絡(luò)套接字功能還沒有全部被拓展。這篇文章介紹了如何使用Javascript Socket.io來擴(kuò)展現(xiàn)存的通過網(wǎng)絡(luò)服務(wù)器來連接p2p的方式。

          Socket.io一種特殊的使用方法是服務(wù)器編碼能夠用Javascript來寫,這個(gè)作用是允許代碼在服務(wù)器和客戶端都很相似,為了更清晰和易維護(hù)。

          解釋概念

          為了用webgl 游戲來擴(kuò)展socket.io:,這個(gè)方法有三個(gè)重要的部分:

          用unity 創(chuàng)建一個(gè)網(wǎng)絡(luò)連接腳本

          創(chuàng)建javascript客戶端代碼

          創(chuàng)建javascript服務(wù)端代碼

          通過轉(zhuǎn)換數(shù)據(jù)到/從JSON對(duì)象和字符串,數(shù)據(jù)傳回到unitygame。

          擴(kuò)展

          項(xiàng)目創(chuàng)建

          為了嘗試這種方法,你的服務(wù)器必須要安裝Node.js。一旦安裝,打開命令行并轉(zhuǎn)到unity 項(xiàng)目的WebGl 的目錄。然后創(chuàng)建JSON文件命名為package.json在目錄下用下面的內(nèi)容。

          {

          "dependencies": {

          "express": "4.13.4",

          "socket.io": "1.4.5"

          }

          }

          實(shí)際最新版本可以通過命令行“hpm info express version”來獲得,文檔被創(chuàng)建后:

          1:運(yùn)行“npm install”來下載節(jié)點(diǎn)模塊,傳遞socket.io 到你創(chuàng)建的目錄。

          2:創(chuàng)建一個(gè)文件夾"public"到你unity創(chuàng)建的目錄

          3:創(chuàng)建一個(gè)空白的“client.js”腳本到“public”文件夾

          Unity 特有的代碼

          下面是一個(gè)示例你可以用另外的客戶端javascript來交互,反過來也可以與服務(wù)器端腳本交互。

          JSONUtility類在例子中會(huì)有影響,因?yàn)橹挥凶址當(dāng)?shù)據(jù)能能夠通過Application.externalCall及在客戶端javaacript 方面,它的對(duì)應(yīng)的接收方法。

          使用下列代碼,數(shù)據(jù)可以被傳輸并在瀏覽器中執(zhí)行:

          Application.ExternalCall (string functionName, string dataParameter);

          理論上,我們應(yīng)該編碼網(wǎng)絡(luò)管理器前,首先設(shè)置一些數(shù)據(jù)類,用JSONUnit來添加轉(zhuǎn)變 到/從Json 對(duì)象。

          // Sample Data Classes that could be stringified by JSONUtility

          public class User

          {

          public string uid;

          public string displayname;

          public User(string u,string d)

          {

          uid=u;

          displayname=d;

          }

          }

          public class MatchJoinResponse

          {

          public bool result;

          }

          下面創(chuàng)建一個(gè)C#腳本命名為“NetworkManager”并賦予場(chǎng)景中的游戲?qū)ο螅℅ameObject)

          using UnityEngine;

          public class NetworkManager : MonoBehaviour

          {

          public void ConnectToServer(User user)

          {

          Application.ExternalCall ("Logon", JsonUtility.ToJson (user));

          }

          public void OnMatchJoined(string jsonresponse)

          {

          MatchJoinResponse mjr=JsonUtility.FromJson<MatchJoinResponse> (jsonresponse);

          if(mjr.result)

          {

          Debug.Log("Logon successful");

          }

          else

          {

          Debug.Log("Logon failed");

          }

          }

          public void BroadcastQuit()

          {

          Application.ExternalCall ("QuitMatch");

          }

          }

          當(dāng)你重新創(chuàng)建你的Unity項(xiàng)目時(shí),確保你添加下面幾行代碼到“index.html”文件:

          <script type="text/javascript" src="/socket.io/socket.io.js"></script>

          <script type="text/javascript" src="client.js"></script>

          客戶端Javascript

          客戶端javascript接受了從unity game的調(diào)用在以前部分并在下一部分與服務(wù)器連接。用下面的調(diào)用來調(diào)用Unity Game:

          SendMessage(string GameObjectName, string MethodName, string data);

          例子使用了暫停功能來阻止在事件中游戲的進(jìn)程,服務(wù)器性能下降。在客戶端的.js文件:

          var connection;

          var logonTimeout;

          var logonCallback=function (res)

          {

          clearTimeout(logonTimeout);

          // Send Message back to Unity GameObject with name 'XXX' that has NetworkManager script attached

          SendMessage('XXX','OnMatchJoined',JSON.stringify(response));

          };

          function Logon(str)

          {

          var data=JSON.parse(str);

          connection=io.connect();

          // Setup receiver client side function callback

          connection.on('JoinMatchResult', logonCallback);

          // Attempt to contact server with user data

          connection.emit('JoinMatchQueue', data);

          // Disconnect after 30 seconds if no response from server

          logonTimeout=setTimeout(function(){

          connection.disconnect();

          connection=null;

          var response={result:false};

          // Send Message back to Unity GameObject with name 'XXX' that has NetworkManager script attached

          SendMessage('XXX','OnMatchJoined',JSON.stringify(response));

          },30000);

          }

          function QuitMatch()

          {

          if(connection)

          {

          connection.disconnect();

          connection=null;

          }

          }

          服務(wù)器Javascript

          例子中服務(wù)器傳遞路徑和文件簡(jiǎn)單遞送。在例子中,服務(wù)器和客戶端功能是類似的。

          // Variable Initialization

          var express=require('express'),

          app=express(),

          server=require('http').createServer(app),

          port=process.env.PORT || 3000,

          io=require('socket.io')(server);

          // Store Client list

          var clients={};

          // Allow express to serve static files in folder structure set by Unity Build

          app.use("/TemplateData",express.static(__dirname + "/TemplateData"));

          app.use("/Release",express.static(__dirname + "/Release"));

          app.use(express.static('public'));

          // Start server

          server.listen(port);

          // Redirect response to serve index.html

          app.get('/',function(req, res)

          {

          res.sendfile(__dirname + '/index.html');

          });

          // Implement socket functionality

          io.on('connection', function(socket){

          socket.on('JoinMatchQueue', function(user){

          socket.user=user;

          clients[user.uid]=socket;

          var response={result:true};

          socket.emit('JoinMatchResult', response);

          console.log(user.uid + " connected");

          });

          socket.on('disconnect', function()

          {

          delete clients[socket.user.uid];

          console.log(socket.user.uid + " disconnected");

          });

          });

          一旦保存,服務(wù)器可以在主機(jī)上啟動(dòng),用Node.js用命令行"node server.js".

          其他記錄

          游戲中最可能要考慮的是性能。數(shù)據(jù)從Json對(duì)象轉(zhuǎn)化為Json對(duì)象以及瀏覽器中的字符串并返回游戲中;每個(gè)轉(zhuǎn)變?cè)诜椒ㄖ惺潜匾拈_銷。如果闡述這種方法的人有任何關(guān)于性能與經(jīng)驗(yàn)的信息,我很樂意傾聽的。

          同時(shí),如果在Azure服務(wù)器解析Socket.io,確保下面的代碼也添加到網(wǎng)站的web.config文件中:

          <webSocket enabled="false"/>

          這會(huì)使IIS WebSockets模塊不起作用,包括自己的WebSockets解析和與Node.js 具體的websocket模塊沖突,比如Socket.IO.

          結(jié)論

          這篇文章講述了一種把Socket.io和WebGLUnity創(chuàng)建連接成網(wǎng)絡(luò)的方式。

          顯然更好的方式執(zhí)行Socke.io和Unity 互用性會(huì)是在unity環(huán)境中主要的唯一的插件。文章中表現(xiàn)出來的解決方式是一個(gè)可擴(kuò)展的可替代的。直到某些時(shí)候,Unity解析websocket原生功能性地到游戲引擎中。最終,有添加的好處在javascript客戶端和服務(wù)器代碼會(huì)很相似。

          關(guān)于作者

          Damian Osiebo是一個(gè)職業(yè)海軍軍官。從MIT中取得計(jì)算機(jī)科學(xué)碩士學(xué)位。空閑時(shí)間是一個(gè)游戲愛好者和編程狂人。

          許可證

          GDOL(Gamedev.net Open License)

          原文鏈接:https://www.gamedev.net/resources/_/technical/multiplayer-and-network-programming/integrating-socketio-with-unity-5-webgl-r436

          原文作者:Damian Osiebo


          主站蜘蛛池模板: 无码人妻精品一区二区三区99不卡 | 无码精品一区二区三区| av无码免费一区二区三区| 久久99国产精一区二区三区| 国产精品女同一区二区久久| 能在线观看的一区二区三区| 在线精品一区二区三区电影 | 精品福利视频一区二区三区| 蜜桃臀无码内射一区二区三区| 国产精品视频一区二区三区不卡| 动漫精品专区一区二区三区不卡| 国产福利一区二区| 日韩经典精品无码一区| 一区二区视频在线免费观看| 亚洲男人的天堂一区二区| 日韩精品一区二三区中文| 中文字幕在线播放一区| 国精产品一区一区三区| 性色av一区二区三区夜夜嗨| 91在线精品亚洲一区二区| 国产日韩精品视频一区二区三区| 亚洲色偷精品一区二区三区| 国产情侣一区二区| 婷婷国产成人精品一区二| 国产一区中文字幕在线观看| 精品日本一区二区三区在线观看| 国产免费播放一区二区| 免费视频一区二区| 精品人伦一区二区三区潘金莲| 精品深夜AV无码一区二区老年| 日韩免费视频一区| 精品久久久久中文字幕一区| 亚洲AV综合色区无码一区| 亚洲sm另类一区二区三区| 无码AV动漫精品一区二区免费| AV怡红院一区二区三区| 无码免费一区二区三区免费播放| 中文字幕亚洲综合精品一区| 在线视频一区二区| 波多野结衣中文一区二区免费| 中日av乱码一区二区三区乱码|