Unity3D中Javascript的基本使用與介紹詳解

七大黍發表於2014-10-19


在Unity中指令碼是必不可少的。因為他將定義你遊戲的各種行為和規則。
這個教程將介紹JavaScript的基本使用。
1.目標

在Unity中,指令碼是用來界定使用者在遊戲中的行為或規則。Unity推薦使用的程式語言是JavaScript,同時也支援C#或Boo。

2.前提
本教程的重點是Unity指令碼基礎,前提是你已經熟悉了Unity的介面。

3.命名規範
開始前,先說下Unity的一些規範。
變數 – 首寫為小寫字母。變數用來儲存遊戲狀態中的任何資訊。
函式 – 首寫為大寫字母。函式是一個程式碼塊,在需要的時候可以被重複呼叫。
類 – 首寫為大寫字母。可以被認為是函式的庫。
當閱讀範例時注意首寫字母,將有助於你更好的理解物件之間的關係。

4.使用者輸入
我們第一個例子是在場景中實現一個簡單的移動。
1)設定場景:
-啟動Unity。建立一個用來移動的平面。GameObject->CreateOther->Plane。並且在Inspector皮膚中設定Position為”0,0,0″。如果當前頁面沒有Inspector皮膚,選擇Window-

>Layouts->2by 3。建議熟悉各種佈局以便開發需要。

-建立一個Cube。GameObject->CreateOther->Cube。在Inspector皮膚中設定Position為”0,1,0″。

-我們都知道現實世界裡物體成像靠的是光反射,那麼我們這裡也是需要光線的。選擇GameObject->CreateOther->PointLight。在Inspector皮膚中設定座標為”0,5,0″。

-儲存當前場景。快捷鍵為Ctrl+s。

2)新建指令碼。
我們打算移動使用者的視線,這需要通過控制主相機的位置來實現。
我們就要寫一個指令碼,然後把指令碼和相機結合起來。

-建立一個空指令碼。Assets->Create->JavaScript並命名為”Move”。重新命名快捷鍵為F2。

-雙擊開啟指令碼Move。預設包含Update()函式。將我們的程式碼加入這個函式,他將在每一幀執行一次。
我們需要用transform來改變相機的位置,用到Translate這個函式,他有x,y,z三個引數。我們加入以下程式碼:

function Update(){
    transform.Translate(Input.GetAxis("Horizontal"),0,Input.GetAxis("Vertical"));
}

Input.GetAxis()函式返回一個從-1到1之間的值,如橫軸上左半軸為-1到0,右半軸為0到1。
如果需要,我們可以通過Edit->ProjectSettings->Input中重定義按鍵對映。
3)連線指令碼
指令碼寫完了,如何讓他起作用呢?我們需要把指令碼賦予物體才行。

-點選希望應用指令碼的物體物件。這裡對我們而言就是相機。從Hierarchy皮膚中選中它。

-在選單中選擇Components->Scripts->Move,這樣我們便從Inspector皮膚中看到相機中新增了Move這個元件。(我們也可以用滑鼠把指令碼拖拽到物體物件上)
點選執行,我們即可前後左右按鍵來控制相機移動了。

注意一個關於DeltaTime的問題。放在Update()函式中的程式碼是按照幀來執行的。
如果我們需要物體的移動按照時間秒來執行,我們需要將Input.GetAxis()函式的返回值乘以Time.deltaTime:

var speed = 5;
function Update(){
    var x = Input.GetAxis("Horizontal")*Time.deltaTime*speed;
    var y = Input.GetAxis("Vertical")*Time.deltaTime*speed;
    transform.Translate(x, y, 0);
}
這樣設定之後按下WASD便可以實現上下左右的視角移動了。
這裡的speed為顯式變數,可以在Inspector皮膚中看到。我們可以在使用中隨時調整它的值,很方便。

5.連線變數
Unity允許在介面上拖拽(drag and drop)的方式賦指令碼。快捷方便。這裡,我們將涉及連線變數的概念。

-在場景中新增一個聚光燈。GameObject->CreateOther->SpotLight。Position為”0,5,0″,Rotation為”90,0,0″。

-建立一個JavaScript指令碼,命名為”SpotLight”。

我們想讓聚光燈照向主相機。我們可以使用transform.LookAt()這個函式。
如何使用這個函式呢?我們需要建立一個顯式變數。在SporLight指令碼中寫入如下程式碼:

var target : Transform;
        function Update(){
        transform.LookAt(target);
}
-把指令碼賦予聚光燈物件。要麼在選單欄Component中新增,要麼滑鼠拖放。之後,”target”變數就出現在Inspector皮膚裡了。

-將Hierarchy皮膚中的主相機物件拖放到Target變數上。如果我們想讓聚光燈照向其他物體,我們也可以將其他物體拖放上去,只要是Transform型別的即可。
-執行。你可以看到聚光燈一直照向主相機。

6.訪問元件
一個遊戲物件可能有多個指令碼或其他元件。它將不可避免的要訪問其他元件的函式或變數。Unity中通過GetComponent()函式來實現這個目的。我們現在要實現按下空格鍵後讓聚光燈照向Cube


我們考慮一下這個步驟:1.監視空格鍵被按下。2.空格鍵按下後聚光燈照向Cube。
由於SporLight指令碼中有target變數,我們只需要為這個變數設定新的值就可以了。

-建立一個指令碼,命名為Switch,新增如下程式碼:

var switchToTarget : Transform;
function Update(){
        if(Input.GetButtonDown("Jump"))
                GetComponent(SpotLight).target = switchToTarget;
}
注意GetComponent()的引數,它將返回一個引數給Switch指令碼,我們就可以用它來訪問”target”變數。
這裡的GetComponent獲取的不是點光源,而是那個名為SpotLight的JS檔案。

-新增Switch指令碼到聚光燈物件,並將Cube拖放到Inspector皮膚中的switchToTarge變數上。

-執行。按下空格後,聚光燈將照向Cube。

前面我們提到,可以通過寫程式碼的方式指定變數(而不是通過Unity介面),如何做到呢?上面按下空格時告訴聚光燈聚焦到Cube上,我們是在SpotLight指令碼中做一個顯式的變數,將Cube拖放上

去。而在程式碼中主要有2種方法去實現:
1.使用物件的名稱(name)
2.使用物件的標籤(tag)

1.物件名稱
可以從Hierarchy皮膚上看到物件的名稱。用GameObject.Find()函式來使這些名稱作為引數。因此,我們可以這樣寫:

function Update(){
        if(Input.GetButtonDown("Jump"))
        {
                var newTarget = GameObject.Find("Cube").transform;
                GetComponent(SpotLight).target = newTarget;
        }
}
注意,以上沒有出現顯式的變數。

2.物件標籤
物件標籤是一個字串,用來識別一個元件。在Inspector皮膚中點選Tag按鈕檢視內建的標籤。我們也可以建立自己的標籤。GameObject.FindWithTag()函式能通過具體的標籤尋找元件並返

回一個字串作為引數。

function Update(){
        if(Input.GetButtonDown("Jump"))
        {
                var newTarget = GameObject.FindWithTag("fang").transform;
                GetComponent(SpotLight).target = newTarget;
        }
}
7.例項
我們要在執行時建立(create)物件就要用到Instantiate函式。
讓我們來實現如何在每次按下開火按鈕(滑鼠左鍵或Ctrl鍵)後通過例項化一個新的物件。需要思考以下幾點:
1.哪個物體做我們的例項?
2.在哪兒例項化?
關於第一個問題,最好的辦法就是顯式變數。
這樣我們就可以隨時通過拖放來改變我們的例項物件。
至於在哪兒例項化,我們只要實現當按下開火鍵時,在使用者的當前位置建立一個物件即可。
例項化函式有3個引數:1.我們要建立的物件。2.物件的位置座標。3.物件的旋轉位置。
完整的程式碼如下:

var newObject : Transform;
function Update(){
        if(Input.GetButtonDown("Fire1")){
            Instantiate(newObject, transform.position, transform.rotation);
        }
}
要記住,transform、position、transform、rotation是附加這個指令碼的物體的位置。我們這裡假設為主相機。一般情況下,將要被例項化的物件設定為預設(prefab),我們現將Cube設定為

預設。
-首先,讓我們建立一個預置。Assets->Create->Prefab。命名為Cube。

-從Hierarchy皮膚中選取Cube拖放到Project皮膚的Cube上。

-建立一個指令碼並命名為Create,並把上面的程式碼加進去。

-把這個指令碼賦予相機,並將Cube預設賦予指令碼變數。

-執行。移動相機並按下開火鍵,你能看到新的Cube出現。

8.除錯
除錯是發現和修正你的程式碼中人為錯誤的技巧,Unity中提供了Debug類,我們現在看看Debug.Log()函式。
Log()函式允許使用者傳送資訊到Unity的控制檯。這樣做的原因可能包括:
1.在執行時要驗證某部分程式碼是否達成。
2.報告變數的狀態。
我們現在使用Log()函式,當使用者點選開火按鈕時,傳送一個訊息到Unity控制檯。
-開啟建立的指令碼並在”Instantiate”程式碼內”if”處新增如下程式碼:

Debug.Log("Cube created");
-執行。點選開火鍵,我們能看到Unity介面下方顯式”Cube created”。

另外一個有用的功能是用於除錯私有變數。這使得當Debug模式被選中時Inspector皮膚中的變數,但它不能被編輯。為了證明這一點,我們將顯式一個私有變數作為Cube例項的計數器。我們

在指令碼中加入兩行內容
1.新增私有變數cubeCount。
2.當一個cube例項建立後增加這個變數
完整程式碼如下:

var newObject : Transform;
private var cubeCount = 0;
function Update(){
        if(Input.GetButtonDown("Fire1"))
        {
                Instantiate(newObject, transform.position, transform.rotation);
                Debug.Log("Cube created");
                cubeCount++;
                Debug.Log(cubeCount);
        }
}
9.常見指令碼型別

//在這個函式體中的程式碼每隔固定的間隔執行。它通常在Rigibody中有力的作用的時候被用到。如:
// Apply a upwards force to the rigibody every frame
function FixedUpdate(){
        rigidbody.AddForce(Vector3.up);
}


//這裡的程式碼將被用作初始化。
Awake(){

}

//這個函式在Update()之前,但在Awake()之後執行。
//Start()函式和Awake()函式的不同點在於Start()函式僅在指令碼啟用時候執行(Inspector皮膚中的核取方塊被選中)。
Start(){

}

//當遊戲物件的碰撞指令碼與另一個遊戲物件碰撞時執行這個函式內的程式碼。
OnCollisionEnter(){

}

//當滑鼠在一個載有GUI元素(GUIElement)或碰撞器(Collider)的遊戲物件裡按下時執行該函式體內的程式碼。
// Loads the level named "SomeLevel" as a response
// to the user clicking on the object
function OnMouseDown(){
        Application.LoadLevel("SomeLevel");
}

//當滑鼠懸停在一個GUI元素或碰撞器的物件上時,執行該函式體內的程式碼。如:
// Fades the red component of the material to zero
// while the mouse is over the mesh
function OnMouseOver(){
        renderer.material.color.r -= 0.1 * Time.deltaTime;
}



相關文章