文說的是在unity中去調用js腳本的函數。本文說另一個方式,就是從web前端,使用js去調用unity中的函數。
方案如下:
1.在Unity場景中有一個GameObject,我們命名為A, A上有C#腳本,里面有個方法
public void Func(string str)
{
//處理邏輯
}
2.在發布出的WebGL項目index.html中用JS調用此方法
<script>
var gameInstance=UnityLoader.Instantiate("gameContainer", "Build/WebAndUnity.json",{onProgress:UnityProgress});
function testSend()
{
gameInstance.SendMessage("A", "Func", "string");
}
</script>
需要注意的就是gameInstance,先要初始化出一個gameInstance,如上代碼,再用gameInstance調用SendMessage方法。
這段代碼的大概意思就是:web前端通過unityloader創建一個unity的容器實例,再通過容器實例給游戲對象A發送一個調用Func函數的消息,并且傳入一個string參數。
注:可以傳遞的參數類型:int ,string,空。
案前情提要:
可視化方案,3D端使用unity的WebGL方案,圖表那些則是Web前端實現。那么這個結構其實就是WebGL一層作為背景層,Web圖表作為前景層。
碰到的特殊需求:點擊背景層(WebGL)的3D物體,反饋數據給web前景層,動態改變Web圖表的數據內容。
舉例:3D場景中有100個攝像頭,點擊其中一個(第66個),反饋給web前端id:66,web前端拿到這個id,進行處理,打開編號為66的攝像頭(海康/大華)的視頻彈框。
方案實現:
1.unity端實現一個jslib文件預定義函數作為橋接。
2.c#使用DllImport引入和調用預定義的函數。
3.web端使用js定義被調用函數。
基于以上的原理制作了一個生成器
1.在Unity中Project目錄“Assets\Plugins"下,創建一個jslib文件,可以用txt創建文件,文件名加后綴名為“xxx.jslib”,切記后綴名更改為jslib
jslib當作中間者,unity與它通信,前端也與它通信,在此基礎上三者之間進行了通信對接
2.在剛剛創建的jslib文件里,先來個簡單的,添加以下代碼:
mergeInto(LibraryManager.library, {
StartTime: function(){ //StartTime是Unity調用的方法名字
BeginTime(); //BeginTime是調用前端BeginTime()方法
},
});
3 .在unity中,新建一個腳本,添加命名空間using System.Runtime.InteropServices; 并添加以下C#代碼:
[DllImport("__Internal")]
private static extern void StartTime();
在unity中調用StartTime()方法,即調用jslib里的StartTime()方法
4 .在unity打包程序后,在index.html中添加BeginTime()方法
以上是unity基礎的向前端通信方式
例子一:
在Unity中向js傳遞字符串時需要在js中使用 Pointer_stringify(str) 進行轉換。 以下是將unity端的學生成績發送到前端
js端:
mergeInto(LibraryManager.library,{
PostScore: function (score,sceneName) {
strs=Pointer_stringify(sceneName);
GetScore(score,strs);
},
});
unity端:
[DllImport("__Internal")]
private static extern void PostScore(int currentScore, string currentScene); //當前分數,當前場景
html:
function GetScore(score,name){
console.log(score); //log出成績測試是否成功
}
例子二:
在js中向Unity返回字符串的時候需要進行如下轉換操作: var bufferSize=lengthBytesUTF8(returnStr) + 1; var buffer=_malloc(bufferSize); stringToUTF8(returnStr, buffer, bufferSize); return buffer; 以下為獲取服務器ip返回到Unity端的例子
js端:
mergeInto(LibraryManager.library, {
GetIp: function(){
var returnStr=GetIPInformation();
var bufferSize=lengthBytesUTF8(returnStr) + 1;
var buffer=_malloc(bufferSize);
stringToUTF8(returnStr, buffer, bufferSize);
return buffer;
},
});
unity端:
[DllImport("__Internal")]
private static extern string GetIp();
private string m_IpStr="";
void Start()
{
m_IpStr=GetIp();
}
將返回到unity的字符串接收一下就好。
html:
function GetIPInformation(){
var urlPath=window.document.location.href; //瀏覽器顯示地址 http://10.15.5.83:5555/ISV/demo.aspx?a=1&b=2
var docPath=window.document.location.pathname; //文件在服務器相對地址 /ISV/demo.aspx
var index=urlPath.indexOf(docPath);
var serverPath=urlPath.substring(0, index);
console.log(serverPath);
return serverPath;
}
參考資料:Unity開發WebGL與前端之間如何通信互?
說了這么多,下面馬上給大家分享面試題。
還需要其他的面試題可以關注轉發并私信我回復“01”即可獲取我所有Unity面試題資料。
1. 什么是協同程序?
在主線程運行的同時開啟另一段邏輯處理,來協助當前程序的執行,協程很像多線程,但是不是多線程,Unity的協程是在每幀結束之后去檢測yield的條件是否滿足。
2. Unity3d中的碰撞器和觸發器的區別?
碰撞器是觸發器的載體,而觸發器只是碰撞器身上的一個屬性。當Is Trigger=false時,碰撞器根據物理引擎引發碰撞,產生碰撞的效果,可以調用OnCollisionEnter/Stay/Exit函數;當Is Trigger=true時,碰撞器被物理引擎所忽略,沒有碰撞效果,可以調用OnTriggerEnter/Stay/Exit函數。如果既要檢測到物體的接觸又不想讓碰撞檢測影響物體移動或要檢測一個物件是否經過空間中的某個區域時就可以用到觸發器。
3. 物體發生碰撞的必要條件?
兩個物體都必須帶有碰撞器(Collider),其中一個物體還必須帶有Rigidbody剛體,而且必須是運動的物體帶有Rigidbody腳本才能檢測到碰撞。
4. 請簡述ArrayList和List<T>的主要區別?
ArrayList存在不安全類型,會把所有插入其中的數據都當做Object來處理,裝箱和拆箱的操作耗費時間。
List<T>是泛型集合,指定了元素的類型,不需要裝箱和拆箱的操作。
5. 如何在不同的工程之間安全的遷移asset數據?
三種方法:
1. 將Assets目錄和Library目錄一起遷移
2. 導出包,export Package
3. 用unity自帶的assets Server功能
6. OnEnable、Awake、Start運行時的發生順序?哪些可能在同一個對象周期中返利的發生?
Awake->OnEnable->Start,OnEnable在同一周期中可以反復的發生。
7. MeshRender中material和sharematerial的區別?
修改sharedMaterial將改變所有物體使用這個材質的外觀,并且也改變儲存在工程里的材質設置,不推薦修改由sharedMaterial返回的材質,如果你想修改渲染器的材質,使用material替代。
8. Unity提供了幾種光源,分別是什么?
四種:
平行光: Directional Light
點光源: Point Light
聚光燈: Spot Light
區域光源: Area Light
9. 簡述一下對象池,你覺得在FPS游戲里哪些東西適合使用對象池?
對象池就是存放需要被反復調用的資源的一個空間,當一個對象會大量生成的時候,如果每次都銷毀創建會很費時間,通過對象池把暫時不用的對象放到一個池中(也就是一個集合),當下次要重新生成這個對象的時候先去池中查找一下是否有可用的對象,如果有的話就直接拿出來使用,不需要再創建,如果池中沒有可用的對象,才需要重新創建,利用空間換時間來達到游戲的高速運行效果,在FPS游戲中要常被大量復制的對象包括子彈,敵人,粒子等。
10. CharacterController和Rigidbody的區別?
Rigidbody具有完全真實物理的特性,是Unity中物理系統最基本的一個組件,包含了常用的物理我,而CharacterController可以說是受限的Rigidbody,具有一定的物理效果但不是完全真實的,是Unity為了使開發者能方便的開發第一人稱視角的游戲而封裝的一個組件。
11. 簡述Prefab的用處?
在游戲運行時實例化,Prefab相當于一個模板,對你已經有的素材,腳本,參數做一個默認的配置,以便于以后的修改,同時Prefab打包的內容簡化了導出的操作,便于團隊的交流。
12. 請簡述sealed關鍵字用在類聲明與函數聲明時的作用?
Sealed修飾的類為密封類,類聲明時可防止其他類繼承此類,在方法中聲明則可防止派生類重寫此方法。
13. 請簡述private,public,protexted,internal的區別?
Public:對和成員都公開,無限制訪問。
Private:僅對本類公開。
Protected:對本類和派生類公開。
Internal:只能在包含該類折程序集中訪問該類。
14. 使用Unity3d實現2d游戲,有幾種方式?
1. 使用本身的GUI,在Unity4.6以后出現的UGUI。
2. 把攝像機的Projection(投影)值調 為Orthographic(正交投影),不考慮Z軸。
3. 使用第三方插件,如NGUI,2DToolKit等
15. 在物體發生碰撞的整個過程中,有幾個階段,分別列出對應的函數?
共有三個階段:
碰撞發生時:OnCollisionEnter
碰撞過程中:OnCollisionStay
碰撞結束時:OnCollisionExit
16. Unity3d的物理引擎中,有幾種施加力的方式,分別描述出來?
一共有四種:
AddForce 添加力
AddExplosionForce 添加爆炸力
AddForceAtPosition 在指定位置上添加力
AddRelativeForce 添加相對力
17. 什么叫做鏈條關節?
Hinge Joint,可以模擬兩個物體間用一要鏈條連接在一起的情況,能保持兩個物體在一個固定距離內部相互移動而不產生作用力,但是達到固定距離后就會產生拉力。
18. 物體自身旋轉使用的函數是?
Transform.Rotate();
19. Unity3d提供了一個用于保存和讀取數據的類(PlayerPrefs),請列出保存和讀取數據的三種類型,以及對應的函數?
整型:PlayerPrefs.SetInt(); PlayerPrefs.GetInt();
浮點型:PlayerPrefs.SetFloat(); PlayerPrefs.GetFloat();
字符串:PlayerPrefs.SetString(); PlayerPrefs.GetString();
20. Unity3d腳本從喚醒到銷毀有著一套比較完整的生命周期,請列出系統自帶的幾個重要的方法?
Awake->OnEnable->Start->Update->FixedUpdate->LateUpdate->OnGUI->OnDisable->OnDestroy
21. 物理更新一般放在哪個系統函數里?
FixedUpdate,固定每幀繪制時執行一次,和Update不同的是FixedUpdate是固定時間間隔執行,不受渲染的影響。
22. 在場景中放置多個Camera并同時處于活動狀態會發生什么?
與Camera的Depth值有關,先渲染Depth值低的,再渲染Depth值高的。
23. 如何銷毀一個UnityEngine.Object及其子類?
使用Destroy()方法。
24. 請描述為什么Unity3d中會發生在組件上出現數據丟失的情況?
一般是組件上綁定的物體對象被刪除了。
25. LOD是什么,優缺點是什么?
LOD(Level of detail)多層次細節,是最常用的游戲優化技術,它按照模型的位置和重要程序決定物體渲染的資源分配,降低非重要物體的頁數和細節度,從而獲得高效率的渲染運算,缺點是增加了內存。
26. MipMap是什么,有什么作用?
MipMap技術有點類似于LOD技術,但不同的是,LOD針對的是模型資源,而MipMap針對的是紋理貼圖資源,使用MipMap后,貼圖會根據攝像機距離的遠近選擇使用不同精度的貼圖。
缺點:會占用內存,因為MipMap會根據攝像機遠近不同而生成對應的8個貼圖,所以會增加內存的消耗。
優點:會優化顯存帶寬,用來減少渲染,因為可以根據實際情況選擇適合的貼圖來渲染,距離攝像機越遠顯示的貼圖像素越低,反之,像素越高!
27. 請描述Interface和abstract class 的不同?
接口不能包含構造析構函數、字段,可以有方法的聲明但不能有方法的實現,子類繼承接口后必須實現接口中的所有方法。
抽象類可以包含構造析構函數、字段,屬性,可以有方法的聲明也可以有方法的實現,只有聲明沒有實現的方法要聲明為抽象方法,子類繼承抽象類后可以重寫抽象類中的方法也可以直接使用抽象類中的方法。
28. .net與mono的關系?
Mono是一個跨平臺工具,類似于java的虛擬機,.net只能在windows平臺下運行,mono可以實現跨平臺,可以運行于linux,unix,macos等系統下。
29. 簡述Unity3d支持的作為腳本的語言的名稱?
Unity支持的腳本語言主要有JavaScript,C#,Boo,基于Mono的.Net平臺上運行,可以使用.net庫,這也為xml、數據庫、正則表達式等問題提供了很好的解決方案。Unity里的腳本都會經過編譯,他們的運行速度也很快。這三種語言的功能和運行速度是一樣的,區別主要體現在語言特性上。
30. Unity中用于記錄節點空間幾何信息的組件名稱及其父類名稱是?
Transform,父類是Component
31. 向量的點乘、叉乘以及歸一化的意義?
1. 點乘描述了兩個向量的相似程度,結果越大兩向量越相似,還可以表示投影。
2. 叉乘得到的向量垂直于原來的兩個向量,用于求法向量。
3. 歸一化主要用在只關心方向,不關心大小的時候。
32. 為何大家都在移動設備上尋求unity原生GUI的替代方案?
因為UGUI不美觀,OnGUI很耗費時間,效率不高,使用不方便。
33. 請簡述如何在不同分辨率下保持UI的一致性?
NGUI很好的解決了這一點,屏幕分辨率的自適應性,原理就是計算出屏幕的寬高比跟原來的預設的屏幕分辨率求出一個對比值 ,然后修改攝像機的size。
UGUI通過錨點和中心點和分辨率也解決了這個問題。
34. 什么是LightMap?
LightMap:就是指在三維軟件里事先打好光,然后渲染把場景各表面的光照輸出到貼圖上,最后又通過引擎貼到場景上,這樣就使物體有了光照的感覺。
35. Unity和Cocos2d的區別?
Unity支持C#,JavaScript,Boo語言,cocos2d-x支持c++,html5,lua等語言。
Cocos2d開源且免費,Unity閉源且收費
Unity支持IOS,Android,Flash,Windows,Mac等平臺的游戲開發,cocos2d-x支持IOS,Android,wp等平臺。
Unity也可以做2D游戲,但對3D的支持更好,cocos也可以做3D游戲,但對2D的支持更好。
36. C#和C++的區別?
C++是編譯型的語言,C#是半編譯半解釋型的語言,會先編譯成中間代碼,然后通過解釋器解釋執行。C#在C++的基礎上進行了更多的封裝,取消了指針類型。C++的資源需要手動釋放,C#的資源由垃圾回收器GC自動回收。
37. 結構體和類有什么區別?
結構體是一種值類型,存儲于棧中,而類是引用類型,存儲于堆中。
結構體的成員默認是public,類的變量和常量默認是private,其他成員是public。
結構體隱式繼承自ValueType類,而不能繼承任何其他類型,類則可以繼承處ValueType以外的任何類。
結構體無法被繼承,類則可以。
38. Ref參數和out參數是什么?有什么區別?
Ref參數是引用,out參數是輸出參數,兩者都是傳入變量的地址,ref傳入的數據有效,out傳入的數據無效,ref可以在函數內改變其值,也可以不改變,out則必須在函數中賦值。
39. C#的委托是什么?有何用處?
委托類似于c/c++中的函數指針,它能夠引用函數,但在C#中委托是一個對象,且是安全的,一個委托類型的變量可以引用一個或多個方法,這些方法由委托存放于一個調用列表中,當調用一個委托類型的變量即相當于依次調用它的調用列表中的方法。C#中提供了兩個泛型委托Action和Func,區別是Action是無返回值的,Func是有返回值的。
40. C#中的排序方式有哪些?
選擇排序,冒泡排序,快速排序,插入排序,希爾排序,歸并排序
41. 射線檢測碰撞物的原理是?
射線是3D世界中一個點向一個方向發射的一條無終點的線,在發射軌跡中與其他物體發生碰撞時,它將停止發射。
42. Unity中,攝像機的Clipping Planes的作用是什么?調整Near,Far兩個值 時,應該注意什么?
剪裁平面,從相機到開始渲染和停止渲染之間的距離。
43. 如何讓已經存在的GameObject在LoadLevel后不被卸載掉?
Void Awake()
{
DontDestroyOnLoad(transform.gameObject);
}
44. 請簡述GC(垃圾回收)產生的原因,并描述如何避免?
原因:回收堆上的內存
避免:
1. 減少new產生對象的次數
2. 使用公用的對象(靜態成員)
3. 將String換為StringBuilder.
45. 反射的實現原理?
反射是審查元數據并收集關于它的類型信息的能力。
實現原理:在運行時根據程序集及其中的類型得到元數據。
實現步驟:
1. 導入using System.Reflection;
2. Assembly.Load(“程序集”); //加載程序集,返回類型是一個Assembly
3. 得到程序集中所有類的名稱
Foreach(Type type in assembly.GetTypes())
{
String t=type.Name;
}
4. Assembly.GetType(“程序集.類名”); //獲取當前類的類型
5. Activator.CreateInstance(type); //創建此類型實例
6. MethodInfo mInfo=type.GetMethod(“方法名”); //獲取當前方法
7. M.Info.Invoke(null,方法參數);
46. 簡述四元數的作用,四元數對歐拉角的優點?
四元數用于表示旋轉。
相對于歐拉角的優點:
1. 能進行增量旋轉
2. 避免萬向節死鎖
3. 給定方位的表達方式有兩種,互為負(歐拉角有無數種表達方式)
47. 移動相機動作在哪個函數里,為什么在這個函數里?
LateUpdate,是在所有的update結束后才調用,比較適合用于命令腳本的執行,不然有可能出現攝像機已經推進,但視角里未有角色的空幀出現。
48. GPU的工作原理?
簡而言之,GPU的圖形(處理)流水線完成如下的工作:(并不一定是按照如下順序) 頂點處理:這階段GPU讀取描述3D圖形外觀的頂點數據并根據頂點數據確定3D圖形的形狀及位置關系,建立起3D圖形的骨架。在支持DX8和DX9規格的GPU中,這些工作由硬件實現的Vertex Shader(定點著色器)完成。 光柵化計算:顯示器實際顯示的圖像是由像素組成的,我們需要將上面生成的圖形上的點和線通過一定的算法轉
換到相應的像素點。把一個矢量圖形轉換為一系列像素點的過程就稱為光柵化。例如,一條數學表示的斜線段,最終被轉化成階梯狀的連續像素點。 紋理帖圖:頂點單元生成的多邊形只構成了3D物體的輪廓,而紋理映射(texture mapping)工作完成對多變形表面的帖圖,通俗的說,就是將多邊形的表面貼上相應的圖片,從而生成“真實”的圖形。TMU(Texture mapping unit)即是用來完成此項工作。 像素處理:這階段(在對每個像素進行光柵化處理期間)GPU完成對像素的計算和處理,從而確定每個像素的最終屬性。在支持DX8和DX9規格的GPU中,這些工作由硬件實現的Pixel Shader(像素著色器)完成。 最終輸出:由ROP(光柵化引擎)最終完成像素的輸出,1幀渲染完畢后,被送到顯存幀緩沖區。
總結:GPU的工作通俗的來說就是完成3D圖形的生成,將圖形映射到相應的像素點上,對每個像素進行計算確定最終顏色并完成輸出。
49. 什么是渲染管道?
是指在顯示器上為了顯示出圖像而經過的一系列必要操作。渲染管道中的很多步驟,都要將幾何物體從一個坐標系中變換到另一個坐標系中去。主要步驟有:
本地坐標->視圖坐標->背面裁剪->光照->裁剪->投影->視圖變換->光柵化
50. 如何優化內存?
有很多種方式,例如:
1. 壓縮自帶類庫。
2. 將暫時不用的以后還需要使用的物體隱藏起來而不是直接Destroy掉。
3. 釋放AssetBundle占用的資源。
4. 降低模型的片面數,降低模型的骨骼數量,降低貼圖的大小。
5. 使用光照貼圖,使用多層次細節(LOD),使用著色器(Shader),使用預設(Prefab)。
6. 代碼中少產生臨時變量。
*請認真填寫需求信息,我們會在24小時內與您取得聯系。