譯者注:javascript
Unity3D中支持三種語言:JavaScript、C#、Boo,不少人不知道如何選擇,經過這篇譯文,咱們能夠搞清楚這三者語言的前因後果,對選擇主語言有必定的借鑑意義。html
首先,Unity是基於Mono也就是.Net的運行環境的,因此它確定支持C#;而後,Unity團隊自行開發了一種Boo的語言;後面可能考慮到用戶的接受程度的問題,又開發了相似JS的一種語言,但那絕對不是JS,勉強能夠稱之爲UnityScript。這三種語言的代碼最後都會被編譯執行,並且能夠互相訪問。java
花了一上午,才譯完,文章有點長,估計有耐心看完的都很少,呵呵。編程
#pragma strict
進行這樣的聲明,是一種很好的習慣,而且對於進行iOS開發來講也是必須的。 #pragma strict 意味着強制進行更嚴格的類型檢測、儘早生成更多有用的錯誤信息、養成更好的編程習慣。api
enum WeaponType { pistol, rifle, launcher } var type : WeaponType = WeaponType.pistol;
這種方式更加簡潔,而且是比使用字符串產生更少潛在錯誤的方法。數組
儘管Unity中的JavaScript嘗試儘可能作得至少某種程度上要像ECMAScript標準,但它與一樣基於ECMAScript的JavaScript在其餘實現方面有不少不一樣。也許它與微軟的JScript更加類似,尤爲是它們都是.NET平臺上的語言。固然,Unity的JavaScript版本是本身獨立開發實現的,而且二者之間也有不少不一樣之處。瀏覽器
Unity JavaScript 是編譯型的,因此性能很高,但瀏覽器中的JavaScript是動態解釋型的。ide
在Unity中,JavaScript、C#與Boo在運行速度上顯然沒有差別。它們各有優缺點,但速度上是一致的。函數
說明:若是你關注過瀏覽器之爭的話,你應該知道現代瀏覽器中JavaScript已經不是簡單的解釋執行,而是以JIT方式編譯執行。固然,確定是不支持嚴格類型定義的。若是ECMAScript標準改爲容許顯式聲明變量類型(像Adobe公司所提倡的,譯註:其實我的以爲UnityScript更像是ActionScript3),JavaScript的性能還能以數量級的提高。儘管如此,現實是真正的JavaScript就算是拿Safari瀏覽器的Squirrelfish Extreme引擎進行測試,比Unity中的UnityScript仍要慢上兩個數量級。工具
JavaScript中,若是你定義變量時不用var關鍵字,該變量將會做爲全局變量處理。
function DoSomeStuff() { x = 3; } DoSomeStuff(); alert(x); // returns 3 ... in JavaScript (not in Unity's UnityScript)
爲了不JS老用戶在Unity碰到這種模棱兩可的狀況,就要求在定義變量時加上var關鍵字,那樣就能夠自動將變量的做用域限定在當前範圍。
function DoSomeStuff() { var x = 3; } DoSomeStuff(); print(x); // raises an error because x is not global in any sense.
UnityScript中,沒有.prototype那樣混亂的寫法。要定義類,你只要這樣簡單的定義:
// Foo.js var foo = "hello, world"; function doEet () { // does nothing, intended to be overridden }
編譯器最後在編譯以前會自動補全一些代碼,構造一個完整的類定義結構。最終形式應該相似以下:
// Foo.js import UnityEngine; class Foo extends MonoBehaviour { public var foo = "hello, world"; public function doEet () { // does nothing, intended to be overridden } }
請注意,文件名就是對應的類名。
子類寫法:
// PrintingFoo.js class PrintingFoo extends Foo { function doEet() { print( foo ); } }
在UnityScript中,你能夠建立虛函數。
class Foo { virtual function DoSomething () { Debug.Log("from base class"); } } //SubFoo.js class SubFoo extends Foo { virtual function DoSomething() { Debug.Log("from sub class"); } } //Elsewhere var foo : Foo = new SubFoo(); foo.DoSomething();//prints from sub class
若是你要調用父類的方法,用關鍵字super。示例以下:
class SubFoo extends Foo { virtual function DoSomething() { super.DoSomething(); Debug.Log("from sub class"); } } //Elsewhere var foo : Foo = new SubFoo(); foo.DoSomething();//prints "from base class" and "from sub class"
能夠很容易編寫相互訪問與調用的類,但還有一種方式可能比用對指定對象進行子類繼承具備更好的維護性。
如:
/* Foo.js */ var bar : Bar; function Start(){ bar = gameObject.GetComponent(Bar); } function doEet(){ // do my own thing if( bar ){ bar.doEet(); } } /* Bar.js */ function doEet(){ // do something special }
var x : String;
你在JavaScript所知道及喜歡的字符串函數都在,不一樣的是調用時首字母大寫。
好比如何分割字符串,寫法以下:
var qualifiedName = "System.Integer myInt"; var name = qualifiedName.Split(" "[0]);
分割後,name[1] 就包含"myInt"。
要查看可用的字符串函數清單,請訪問Mono文檔(http://go-mono.com/docs/monodoc.ashx?link=T%3aSystem.String%2f*)
a = "fred"; // works in JavaScript (a is treated as a global), error in Unity var a = "fred"; // a is now a string variable containing 'fred' var b: String; // b is now a string variable, with no assigned value b = "wilma"; var c; // c is now a dynamically typed variable with no assigned value c = "barney"; c = 17;
a) 你能夠(一般也應該這麼作)顯式聲明變量的做用域,如private、public等。不聲明的話,默認表明public。
b) 在你聲明一個變量時,若是直接賦值給它,Unity就會隱式的給它定義一個數據類型,因此:
var a = "fred"; // a is now of type String a = 5; // ERROR! -- a is a String var b : String = "fred"; // redundant
但:
var a; // a is dynamically typed; a = "fred"; // works a = 5; // works
方法名與類名通常是首字母大寫的,除非當它們不是遵循這一原則的時候。這句話很矛盾。本質上,UnityScript是處在.NET的命名約定的環境 - 方法名採用CamelCase這種駱駝峯式及camelCase這種首字母大寫的寫法、屬性採用駱駝峯式且首字母小寫,但它也試着像JavaScript的寫法 - 像C同樣,嚴重分化成小寫命名及camelCase駱駝峯式。
如 JavaScript 中, typeof("fred") == 'string', 但在Unity中你的寫法是 var a: String;
JavaScript本質上有三種類型:數值、字符串與對象(函數與數組都是對象)。UnityScript則具備更多的數據類型,包括:
1)對象:不能與array、Array進行互相轉換;
var a = new Object(); // works a.fred = "wilma"; // runtime exception!
2)原生數組:沒法進行動態調整;
var a = [1, 2, 3]; a.Push(4); // ERROR -- won't work!
若是要定義指定類型的數組,語法以下:
public var friendsOfCarlotta : Transform[];
3)UnityScript Array:能夠動態調整
var a = new Array(); a.Push(4); // This works
你能夠把UnityScript Array轉換成原生array,效率更高但靈活性下降,具體是使用方法ToBuiltIn(ArrayType),如:
var a = new Array(); a.Push(1); a.Push(3.1415926535); a.Push(17); var b = a.ToBuiltin(float);
4)整型(包括int、uint3二、等等):
Unity支持各類整型的大數,你不須要擔憂。
5)Unity的大量內置類(如Vector3):
你在使用Unity的過程當中,你會愈來愈熟悉這些類,就像Web開發時那些DOM類同樣。Unity中的類相比DOM要少。
使得用Unity很是有趣的一件事是,它的類採用了很是自由的mixin策略。一般你能夠很是快速簡單的查到你所須要的類。最通用的一個例子是Transform類,對於你正在處理的一個對象,全部被附加到該對象的相關聯的類,你均可以簡單快速的獲取。(譯註:這段話沒有翻譯好)
好比,典型的動做就是你會訪問名叫"transform"的變量,它表明與該對象關聯的Transform類的實例。若是你須要相關的位置座標,就訪問transform.position(一個 Vector3對象);若是你須要它的GameObject,就訪問transform.gameObject;若是你須要它的渲染器,就訪問transform.renderer。等等。通常若是你一個對象的主要屬性,你就能夠快速獲取全部其餘的屬性。
a) Unity的String類缺乏JavaScript中字符串的好的特性;
b) Unity的內部數組遠不如JavaScript中數組和對象的靈活。固然,能夠用各類集合類如List、Queue、Dictionary等來配合實現。內部數組速度是最快的。
通常來講,貼入以下代碼:
var x : int; function y(){}
並保存到Foo.js文件中,等同於在該文件中輸入以下代碼:
class Foo extends MonoBehaviour { var x : int; function y(){} }
可是,你能夠在同一個文件中聲明多個類,尤爲是當你須要使用一些輔助工具類時很是有用,通常這種輔助類沒有繼承自MonoBehaviour。
如
class ButtonState { var currentState : int; var offset : Vector2; }
若是你在一個文件中聲明瞭MonoBehaviour的子類,但類名與文件名不匹配的話,即便是大小寫不一致,你也會碰到麻煩。
必定要理解,當你在js文件中編寫行爲腳本是,你實際上在編寫一個類:
a) 文件名就是類名,若是文件名是foo.js,你就能夠在其餘地方以var x = new foo()的格式進行調用;
b) 有一些特定的方法是實現系統預先定義的一些事件處理器,如Start、FixedUpdate等。任何事件中,聲明的一個函數就是這個文件所表明的類的一個方法。
c) 文件中在函數定義以外編寫的代碼都在該類的範圍以內執行,聲明的變量也是該類的成員變量。
d) 類中的靜態函數、變量本質上是類的方法與屬性。
這種方式遠比真正的JavaScript中實現的類來的更優雅,但某種程度上來講是限定你以更好的方式進行編碼。
例如,建立一個行爲腳本,命名爲foo,那文件名就應該是foo.js。假設文件的內容以下:
public name : String; // when you drag the behavior onto a gameobject, these values will be visible and editable public age : int; // other scripts which have a reference to this object (e.g. if they're attached to the same object) can see public functions private favoriteColor : Color; // private members are NOT visible to other scripts, even if they have a reference to this object public bestFriend : foo; // you can assign a value to bestFriend by dragging a gameObject with an attached copy of the foo behavior to this property. This will give you access to bestFriend's public methods and members function Update(){ // this function will be called every frame by Unity, so it's actually an event handler var t = transform; // transform is a property inherited from the gameObject the behavior is attached to } function Bar(){ // this is just a function, if you don't call it yourself, it will never do anything }
調用父類方法
super()表明父類的構造函數,supper則至關於父類中的本來應該以this訪問的成員函數,如super.foo()表明代用父類的foo()方法。
JavaScript中分號是可寫可不寫的,但在Unity中必需要寫。
var foo = 3 // OK in JavaScript but an error in Unity foo += 17
JavaScript的Math庫在Unity中對應爲Mathf庫,而且方法名是首字母大寫的,如Math.abs()在Unity中就應該是Mathf.Abs()。
UnityScript運行環境使用Mono - .NET的開源克隆。實際上,UnityScript是用Boo實現的,Boo是運行在Mono虛擬機上的一種語言,而且編譯成本機代碼。JavasScript不少典型的運行環境如String和Math庫由Mono提供。你也就知道了爲何UnityScript中方法名要大寫了,由於要與Mono中相同。
要使用Mono庫,就須要導入它們,如:
import System;
import System.IO;
不然,你帶指定完整的命名空間來調用函數,如System.IO.File.Open(),而不是File.Open()。
當Mono函數須要字符char做爲輸入參數時,你能夠簡單的使用索引來獲取,好比你像將小寫的a做爲字符char a傳遞,你能夠這樣寫:
"a"[0]
如,當使用String.Replace()函數時,寫法以下:
var s : String = "Whatever_it_may_be"; s = s.Replace("_"[0], " "[0]); // replace all the underscores with spaces
當處理Array對象時,能夠把它轉換成更快的內置array類型數據:
fastArray : SomeType[] = monoArray.ToBuiltin(SomeType);
UnityScript可使用泛型,因此當用到動態大小的數組時,最好用List來替代Array。基本上就沒有什麼理由要用到Array了,List更快而且功能更多。若是你須要混合類型的數組,你能夠用Object List。UnityScript中泛型的語法與C#中接近,除了要加一個額外的「.」符號在「<>」以前。如C#中的"var myList = new List<int>();"在UnityScript中對應的寫法爲:"var myList = new List.<int>();"。
第三方.NET庫如XML-RPC能夠以新建資源Asset的方式引入。
腳本錯誤 會在Unity窗口狀態欄中以紅色x圖標顯示。點擊該圖標,會打開console視圖,顯示錯誤列表,而且能夠快速跳轉到腳本中出錯的那一行。
Unity也會生成有用的警告,這些警告以黃色的!圖標顯示,好比會告訴你聲明的一個變量沒有用到過。努力讓編寫的代碼不會生成警告信息是一個很是好的習慣。
print()函數將會生成消息,並輸出到狀態欄及控制檯中,但僅限MonoBehavioour類範圍內。更好的辦法是使用Debug.Log("insert message here");,該方法處處均可使用。還可用Debug.LogWarning 和 Debug.LogError生成警告和錯誤消息。
Debug.Break(); 能夠將遊戲暫停在一個精確的點。當一種特定的情條件發生時,若是你想檢查對象的狀態的時候,這個特性很是有用。
開發環境運行項目時,編輯界面也是徹底實時更新的,你能夠查看對象實例的內部狀態。
本文由Tonio Loewald (a.k.a. podperson)編寫。翻譯:http://x3d.cnblogs.com/p/3838619.html