在上一節(jié)中我們給球體添加了紋理,并且為場(chǎng)景設(shè)置了一個(gè)目的區(qū)域。當(dāng)球體處于目的區(qū)域內(nèi)時(shí),其將變色。在這一節(jié)里,我們將完善球體在到達(dá)目的區(qū)域時(shí)游戲的反饋,增加音樂和UI顯示。
增加小球進(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);
}
}
}
-本節(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即可)。
同樣是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è)置文字的描邊顏色漸變等,并且可以圖文混用。
-本節(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)鍵功能:
值得一提的是,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
*請(qǐng)認(rèn)真填寫需求信息,我們會(huì)在24小時(shí)內(nèi)與您取得聯(lián)系。