- Unity 4 3D開發(fā)實戰(zhàn)詳解
- 峰 杜化美 張月霞 索依娜編著
- 439字
- 2019-01-01 21:14:58
3.4 Unity腳本的基本語法
通過前面兩節(jié)的介紹,讀者應該對Unity 中專用JavaScript和C#腳本有了一些簡單的了解,下面就分別對Unity中專用JavaScript和C#腳本的基本語法進行介紹說明。
3.4.1 常用操作
Unity 中很多對游戲?qū)ο蟮牟偈峭ㄟ^腳本來修改對象的 Transform(變換屬性)與 Rigidbody (剛體屬性)參數(shù)來實現(xiàn)的。上述屬性的參數(shù)可以非常方便地通過腳本編程實現(xiàn)修改,例如讓物體繞x軸順時針旋轉(zhuǎn)20°,則可以使用如下的JavaScript代碼片段來實現(xiàn)。
1 function Update(){ //聲明Update方法
2 this.transform.Rotate(20, 0, 0); //繞x軸上旋轉(zhuǎn)20°
3 }
腳本開發(fā)完成后,將這個腳本掛載到需要旋轉(zhuǎn)的游戲?qū)ο笊?,在項目運行時即可實現(xiàn)所需功能。當然,也可以使用如下的C#代碼片段來實現(xiàn)相同的功能。
1 using UnityEngine;
2 using System.Collections; //引入系統(tǒng)包
3 public class example : MonoBehaviour { //聲明一個example類
4 void Update() { //重寫Update函數(shù)
5 transform.Rotate(20, 0, 0); //繞x軸旋轉(zhuǎn)20°
6 }}
如果希望游戲?qū)ο笱貁軸正方向移動,則可以使用如下的JavaScript代碼片段來實現(xiàn)。
1 var gameobject : GameObject; //聲明一個游戲?qū)ο?/p>
2 function Update(){ //聲明Update方法
3 gameobject.transform.Translate(0, 0, 1);//實現(xiàn)gameobject每幀向前移動1個單位長度
4 }
上述代碼運行時可以實現(xiàn)gameobject游戲?qū)ο竺繋蚯耙苿?個單位。當然,也可以使用如下的C#代碼片段來實現(xiàn)相同的功能。
1 using UnityEngine;
2 using System.Collections; //引入系統(tǒng)包
3 public class example : MonoBehaviour { //聲明一個example類
4 void Update() { //重寫Update函數(shù)
5 transform.Translate(0, 0, 1); //實現(xiàn)gameobject每幀向前移動1個單位長度
6 }}
提示
一般情況下,在Unity中,x軸為紅色的軸表示左右,y軸為綠色的軸表示上下,z軸為藍色的軸表示前后。
3.4.2 記錄時間
在Unity中記錄時間需要用到Time類。Time類中比較重要的變量為deltaTime(只讀),它指的是從最近一次調(diào)用Update()或者FixUpdate()到現(xiàn)在的時間。
說明
系統(tǒng)在繪制每一幀時,都會回調(diào)一次Update函數(shù),因此,如果想在系統(tǒng)繪制每一幀時都做相同的工作,可以把對應的代碼寫在Update函數(shù)中。
如果想勻速地旋轉(zhuǎn)一個物體,不考慮幀速率的情況下,可以乘以 Time.deltaTime,具體可以使用如下的JavaScript代碼片段來實現(xiàn)。
1 var gameobject : GameObject; //聲明一個游戲?qū)ο?/p>
2 function Update(){ //聲明Update方法
3 gameobject.transform.Rotate(10* Time.deltaTime,0 , 0); //繞x軸均勻旋轉(zhuǎn)
4 }
當然,也可以使用如下的C#代碼片段來實現(xiàn)相同的功能。
1 using UnityEngine;
2 using System.Collections; //引入系統(tǒng)包
3 public class example : MonoBehaviour { //聲明一個example類
4 void Update() { //重寫Update函數(shù)
5 transform.Rotate(10 * Time.deltaTime, 0, 0); //繞x軸均勻旋轉(zhuǎn)
6 }}
同樣地,也可以使用類似的方法來移動物體,具體可以使用如下的JavaScript代碼片段來實現(xiàn)。
1 var gameobject : GameObject; //聲明一個游戲?qū)ο?/p>
2 function Update(){ //聲明Update方法
3 gameobject.transform.Translate(0, 0, 1 * Time.deltaTime); //沿z軸向前移動
4 }
當然,也可以使用如下的C#代碼片段來實現(xiàn)相同的功能。
1 using UnityEngine;
2 using System.Collections; //引入系統(tǒng)包
3 public class example : MonoBehaviour { //聲明一個example類
4 void Update() { //重寫Update函數(shù)
5 transform.Translate(0, 0, 1 * Time.deltaTime);//沿z軸均勻平移
6 }}
如果想每秒增加或者減少一個值,需要乘以 Time.deltaTime,同時也要明確在游戲中是需要每秒1個單位還是每幀1個單位的效果。如果是乘以Time.deltaTime,那么,游戲?qū)ο缶蜁垂潭ǖ墓?jié)奏運動而不是依賴游戲的幀速率,因此,游戲?qū)ο蟮倪\動變得更容易控制。
例如想讓游戲?qū)ο螅℅ameobject)沿 y 軸正方向每秒上升 5 個單位,具體可以使用如下的JavaScript代碼片段來實現(xiàn)。
1 var gameobject : GameObject; //聲明一個游戲?qū)ο?/p>
2 function Update(){ //聲明Update方法
3 gameobject.transform.position.y+=5*Time.deltaTime;//游戲?qū)ο笱貀軸每秒上升5個單位長度
4 }
當然,也可以使用如下的C#代碼片段來實現(xiàn)相同的功能。
1 using UnityEngine;
2 using System.Collections; //引入系統(tǒng)包
3 public class example : MonoBehaviour { //聲明一個example類
4 public GameObject gameobject; //聲明一個游戲?qū)ο?/p>
5 void Update() { //重寫Update函數(shù)
6 gameobject.transform.position.y+=5*Time.deltaTime; //沿y軸每秒上升5個單位
7 }}
如果涉及剛體時,可以寫在FixUpdate函數(shù)里面,這樣就不需要乘以Time.deltaTime,例如,讓一個剛體沿y軸正方向每秒上升2個單位,可以使用如下的JavaScript代碼片段來實現(xiàn)。
1 var gameobject : Rigidbody; //聲明一個游戲?qū)ο?/p>
2 function FixUpdate() { //聲明Update方法
3 gameobject.rigidbody.transform.position.y+=2;//剛體沿y軸每秒上升2個單位長度
4 }
當然,也可以使用如下的C#代碼片段來實現(xiàn)相同的功能。
1 using UnityEngine;
2 using System.Collections; //引入系統(tǒng)包
3 public class example : MonoBehaviour { //聲明一個example類
4 public GameObject gameobject; //聲明一個游戲?qū)ο?/p>
5 void FixUpdate() { //重寫Update函數(shù)
6 gameobject.rigidbody.transform.position.y+=2;//剛體沿y軸每秒上升2個單位長度
7 }}
說明
FixUpdate方法是按固定的物理時間被系統(tǒng)回調(diào)執(zhí)行的,其中的代碼的執(zhí)行和游戲的幀速率無關。
如果涉及剛體的力的時候,通常也不需要乘以Time.deltaTime,因為Unity引擎系統(tǒng)內(nèi)部事先處理好了。
3.4.3 訪問其他組件
組件屬于游戲?qū)ο?,比如把一個 Renderer(渲染器)組件附加到游戲?qū)ο笊?,可以使游戲?qū)ο箫@示到游戲場景中;把Camera(攝像機)組件附加到游戲?qū)ο笊峡梢允乖搶ο缶哂袛z像機的所有屬性。由于所有的腳本都是組件,因此一般的腳本都可以附加到游戲?qū)ο笊稀?/p>
常用的組件可以通過簡單的成員變量取得,下面介紹了一些常見的成員變量,如表3-1所示。
表3-1 常見的成員變量

提示
這里的組件體現(xiàn)在屬性查看器中,而變量是在腳本中體現(xiàn)的。一個游戲?qū)ο蟮乃薪M件及其所帶的屬性參數(shù)都能夠在屬性查看器中查看。如果想通過掛載在游戲?qū)ο笊系哪_本代碼來實現(xiàn)獲得該游戲?qū)ο笊系膶M件及其屬性,可以通過變量名來獲得,例如,獲得游戲?qū)ο螅?gameobject )上的 Transform 組件,可這樣寫gameobject.transform;如果想進一步獲得其 position 屬性,則可這樣寫gameobject.transform.position。
如果想查看所有的預定義成員變量,可以查看關于 Component、Behavior 和 MonoBehaviour類的文檔,本書不再一一介紹。如果游戲?qū)ο笾袥]有想要取得的值,那么上面的變量將為null。
在 Unity 中,附加到游戲?qū)ο笊系慕M件可以通過 GetComponent 獲得,具體可以使用如下的JavaScript代碼片段來實現(xiàn)。
1 var gameobject : Rigidbody; //聲明游戲?qū)ο?/p>
2 function Update(){ //聲明Update方法
3 gameobject.transform.Translate(1, 0, 0); //沿x軸移動一個單位
4 gameobject.GetComponent(Transform).Translate(1, 0, 0);//沿x軸移動一個單位
5 }
第4行和第5行代碼作用是一樣的,都是使游戲?qū)ο笱豿軸正方向移動。當然,也可以使用如下的C#代碼片段來實現(xiàn)相同的功能。
1 using UnityEngine;
2 using System.Collections; //引入系統(tǒng)包
3 public class example : MonoBehaviour { //聲明一個example類
4 void Update() { //重寫Update函數(shù)
5 transform.Translate(1, 0, 0); //沿x軸移動一個單位
6 GetComponent<Transform>().Translate(1, 0, 0); //沿x軸移動一個單位
7 }}
提示
注意transfom和Transform之間大小寫的區(qū)別,前者是變量(小寫),后者是類或腳本名稱(大寫)。大小寫不同使你能夠從類和腳本名中區(qū)分變量。
同樣地,也可以通過GetComponent獲取其他的腳本。比如有一個HelloWorld腳本,里面有一個sayHello函數(shù)。HelloWorld腳本要與調(diào)用它的腳本附加在同一游戲?qū)ο笊?,具體可以使用如下的JavaScript代碼片段來實現(xiàn)。
1 var otherScript : HelloWorld; //聲明一個HelloWorld腳本
2 function Update (){ //聲明Update方法
3 otherScript = GetComponent (HelloWorld); //調(diào)用HelloWorld腳本
4 otherScript.sayHello(); //執(zhí)行sayHello方法
5 }
當然,也可以使用如下的C#代碼片段來實現(xiàn)相同的功能。
1 using UnityEngine;
2 using System.Collections; //引入系統(tǒng)包
3 public class example : MonoBehaviour { //聲明一個example類
4 void Update() { //重寫Update函數(shù)
5 OtherScript otherScript = GetComponent<OtherScript>(); //得到其他腳本組件
6 otherScript.sayHello(); //執(zhí)行sayHello方法
7 }}
提示
聲明otherScript變量時也可以不指定類型,但是指定類型后,Unity就不需要進行邏輯判斷otherScript,這樣可以優(yōu)化性能,提高運行速度。
3.4.4 訪問其他游戲?qū)ο?/h3>
大部分腳本不單單控制一個游戲?qū)ο?。Unity 腳本中有很多方法訪問它們的游戲?qū)ο蠛陀螒蚪M件。比如有一個Test腳本,并將其附加到一個游戲?qū)ο笊?,具體可以使用如下的JavaScript代碼片段來實現(xiàn)。
1 var otherScript : Test; //聲明一個Test腳本
2 function Update (){ //聲明Update方法
3 otherScript = GetComponent(Test); //調(diào)用Test腳本
4 otherScript.DoSomething(); //執(zhí)行Test腳本中的DoSomething方法
5 }
當然,也可以使用如下的C#代碼片段來實現(xiàn)相同的功能。
1 using UnityEngine;
2 using System.Collections; //引入系統(tǒng)包
3 public class example : MonoBehaviour { //聲明一個example類
4 void Update() { //重寫Update函數(shù)
5 OtherScript otherScript = GetComponent<OtherScript>(); //得到其他腳本組件
6 otherScript.DoSomething(); //調(diào)用腳本組件中的DoSomething()方法
7 }}
1.通過屬性查看器指定參數(shù)
可以通過屬性查看器來確定一些變量的值,具體可以使用如下的JavaScript代碼片段來實現(xiàn)。
1 // 將要轉(zhuǎn)換的對象拖曳到target位置
2 var target : Transform; //聲明一個游戲?qū)ο?/p>
3 function Update (){ //聲明Update方法
4 target.Translate(0, 0, 2); //沿z軸每幀移動2個單位
5 }
當然,也可以使用如下的C#代碼片段來實現(xiàn)相同的功能。
1 // 將要平移的對象拖曳到target位置
2 using UnityEngine;
3 using System.Collections; //引入系統(tǒng)包
4 public class example : MonoBehaviour { //聲明一個example類
5 public Transform target; //定義一個Transform類型的target變量
6 void Update() { //重寫Update函數(shù)
7 target.Translate(0, 0, 2); //在z軸上平移2個單位
8 }}
讀者也能將參數(shù)顯示在屬性查看器,然后就可以拖曳Test腳本到屬性查看器的gameobject位置,具體可以使用如下的JavaScript代碼片段來實現(xiàn)。
1 //設置a DoSomething到target變量指定在屬性查看器
2 var target : Test; //聲明一個游戲?qū)ο?/p>
3 function Update (){ //聲明Update方法
4 //設置Test對象的a變量
5 target.a = 2;
6 //調(diào)用Test的Dosomething
7 target.DoSomething("Hello");
8 }
當然,也可以使用如下的C#代碼片段來實現(xiàn)相同的功能。
1 //設置foo DoSomething到target變量指定在屬性查看器
2 using UnityEngine;
3 using System.Collections; //引入系統(tǒng)包
4 public class example : MonoBehaviour { //聲明一個example類
5 public Test target; //定義一個Test類型的target變量
6 void Update() { //重寫Update函數(shù)
7 target.a = 2; //設置target對象的a變量
8 target.DoSomething("Hello"); //調(diào)用target的DoSomething方法
9 }}
2.確定對象的層次關系
可以通過Transform組件去找到它的子對象和父對象,具體可以使用如下的JavaScript代碼片段來實現(xiàn)。
1 //獲得子游戲?qū)ο蟆癏and”
2 var gameobject : GameObject; //聲明一個游戲?qū)ο?/p>
3 function Update (){ //聲明Update方法
4 gameobject.transform.Find("Hand").Translate(0, 0, 1);//找到子對象“Hand”并沿Z軸每幀移動1個單位
5 }
當然,也可以使用如下的C#代碼片段來實現(xiàn)相同的功能。
1 using UnityEngine;
2 using System.Collections; //引入系統(tǒng)包
3 public class example : MonoBehaviour { //聲明一個example類
4 void Update() { //重寫Update函數(shù)
5 //找到子對象“Hand”,并沿z軸每幀移動1個單位
6 transform.Find("Hand").Translate(0, 0, 1);
7 }}
一旦讀者在Hierarchy面板找到Transform,讀者就可以通過GetComponent獲得其他腳本,例如有一個Test.js腳本掛載在子對象Hand上,具體可以使用如下的JavaScript代碼片段來實現(xiàn)。
1 var gameobject : GameObject;
2 function Update (){
3 //找到子對象 "Hand"
4 //獲取Test,設置a為2
5 gameobject.transform.Find("Hand").GetComponent(Test).a = 2;
6 //獲得子對象"Hand"
7 //調(diào)用附屬于它的Test的DoSomething
8 gameobject.transform.Find("Hand").GetComponent(Test).DoSomething("Hello");
9 //獲得子對象"Hand"
10 //加一個力到剛體上
11 gameobject.transform.Find("Hand").rigidbody.AddForce(0, 0, 2);
12 }
當然,也可以使用如下的C#代碼片段來實現(xiàn)相同的功能。
1 using UnityEngine;
2 using System.Collections; //引入系統(tǒng)包
3 public class example : MonoBehaviour { //聲明一個example類
4 void Update() { //重寫Update函數(shù)
5 //找到子對象 "Hand",并得到該對象上的Test腳本組件,同時設置a為2
6 transform.Find("Hand").GetComponent<Test>().a = 2;
7 //找到子對象 "Hand",并得到該對象上的Test腳本組件,同時調(diào)用DoSomething函數(shù)
8 transform.Find("Hand").GetComponent<Test>().DoSomething("Hello");
9 //找到子對象 "Hand",在該對象的剛體屬性上加一個沿z軸的大小為2的力
10 transform.Find("Hand").rigidbody.AddForce(0, 0, 2);
11 }}
也可以使用腳本來循環(huán)到所有的子對象,然后對子對象做某種操作,如平移。具體可以使用如下的JavaScript代碼片段來實現(xiàn)。
1 //y軸正方向移動所有的子對象5個單位
2 for (var child : Transform in transform) {
3 child.Translate(0, 5, 0);
4 }
當然,也可以使用如下的C#代碼片段來實現(xiàn)相同的功能。
1 //y軸正方向移動所有的子對象5個單位
2 foreach (Transform child in transform) {
3 child.Translate(0, 5, 0);
4 }
如果想要得到更多關于Transform的信息,可以參考相關的文檔。
3.指定名字或標簽
可以使用GameObject.FindWithTag和GameObject.Find GameObjectsWithTag搜索指定標簽的游戲?qū)ο螅皇褂肎ameObject.Find搜索指定名字的游戲?qū)ο?,具體可以使用如下的JavaScript代碼片段來實現(xiàn)。
1 function Start (){
2 //通過名字搜索
3 var name = GameObject.Find("SomeName");
4 name.transform.Translate(0, 0, 1);
5 //通過標簽搜索
6 var tag = GameObject.FindWithTag("SomeTag");
7 tag.transform.Translate(0, 0, -1);
8 }
當然,也可以使用如下的C#代碼片段來實現(xiàn)相同的功能。
1 using UnityEngine;
2 using System.Collections; //引入系統(tǒng)包
3 public class example : MonoBehaviour { //聲明一個example類
4 void Start() { //重寫Start函數(shù)
5 //找到名稱為SomeName的游戲?qū)ο?/p>
6 GameObject go = GameObject.Find("SomeName");
7 go.transform.Translate(0, 0, 1); //沿z軸平移1
8 //找到Tag為SomeTag的游戲?qū)ο?/p>
9 GameObject tag = GameObject.FindWithTag("SomeTag");
10 tag.transform.Translate(0, 0, -1); //沿z軸平移-1
11 }}
這樣,通過 GetComponent 就能得到指定游戲?qū)ο笊系娜我饽_本或組件,具體可以使用如下的JavaScript代碼片段來實現(xiàn)。
1 function Start (){
2 //通過名字搜索
3 var name = GameObject.Find("SomeName");
4 name.GetComponent(Test).DoSomething();
5 //通過標簽搜索
6 var tag = GameObject.FindWithTag("SomeTag");
7 tag.GetComponent(Test).DoSomething();
8 }
當然,也可以使用如下的C#代碼片段來實現(xiàn)相同的功能。
1 using UnityEngine;
2 using System.Collections; //引入系統(tǒng)包
3 public class example : MonoBehaviour { //聲明一個example類
4 void Start() { //重寫Start函數(shù)
5 //找到名稱為SomeName的游戲?qū)ο?/p>
6 GameObject go = GameObject.Find("SomeName");
7 //得到go對象上的Test腳本組件,并調(diào)用腳本中的方法
8 go.GetComponent<Test>().DoSomething();
9 //找到Tag為SomeTag的游戲?qū)ο?/p>
10 GameObject tag = GameObject.FindWithTag("SomeTag");
11 //得到go對象上的Test腳本組件,并調(diào)用腳本中的方法
12 tag.GetComponent<Test>().DoSomething();
13 }}
但是這里也有一些特殊的變量,比如主攝像機(Camera.main),即第一個有效的攝像機被標示為主攝像機(只讀),如果當前游戲場景中沒有主攝像機則返回null。
4.傳遞參數(shù)
一些事件中包含了特殊的信息,例如觸發(fā)碰撞事件的Collider組件。在OnTiggerStay函數(shù)中有一個碰撞體參數(shù),通過這個參數(shù),能得到碰撞的剛體,具體可以使用如下的 JavaScript 代碼片段來實現(xiàn)。
1 function OnTriggerStay( other : Collider ) {
2 //如果碰撞體是一個剛體
3 //則給它一個向前的力
4 if (other.rigidbody)
5 other.rigidbody.AddForce(0, 0, 2);
6 }
當然,也可以使用如下的C#代碼片段來實現(xiàn)相同的功能。
1 using UnityEngine; //引入系統(tǒng)包
2 using System.Collections; //引入系統(tǒng)包
3 public class example : MonoBehaviour {
4 void OnTriggerStay(Collider other) {
5 if (other.rigidbody) //如果碰撞體是剛體,則給它一個向前的力
6 other.rigidbody.AddForce(0, 0, 2);
7 }}
或者通過Collider得到這個對象上掛載的腳本,具體可以使用如下的JavaScript代碼片段來實現(xiàn)。
1 function OnTriggerStay( other : Collider ) {
2 //一般碰撞體沒有附腳本,所以讀者需要首先檢查是否為null
3 if (other.GetComponent(Test))
4 //如果其他的碰撞體附加了Test,則調(diào)用它的DoSomething方法
5 other.GetComponent(Test).DoSomething();
6 }
當然,也可以使用如下的C#代碼片段來實現(xiàn)相同的功能。
1 using UnityEngine;
2 using System.Collections; //引入系統(tǒng)包
3 public class example : MonoBehaviour {
4 void OnTriggerStay(Collider other) {
5 //如果other對象上存在Test腳本組件,就調(diào)用該腳本的方法
6 if (other.GetComponent<Test>())
7 other.GetComponent<Test>().DoSomething();
8
9 }}
說明
在上面的代碼中使用后綴方式訪問其他變量,也同樣能訪問到碰撞對象所包含的任意組件。
5.某個類型的腳本
可以使用FindObjectsOfType函數(shù)找到特定的組件,具體可以使用如下的JavaScript代碼片段來實現(xiàn)。
1 function Start (){
2 //獲得附加在場景里的游戲?qū)ο蟮腡est組件
3 var test : Test = FindObjectOfType(Test);
4 test.DoSomething();
5 }
當然,也可以使用如下的C#代碼片段來實現(xiàn)相同的功能。
1 using UnityEngine;
2 using System.Collections; //引入系統(tǒng)包
3 public class example : MonoBehaviour {
4 void Start() { //重寫Start函數(shù)
5 //找到Test類型的組件
6 Test test = FindObjectOfType(typeof(Test));
7 test.DoSomething(); //調(diào)用腳本中的DoSomething函數(shù)
8 }}
說明
如果使用FindObjectsOfType函數(shù)得到的Test類型的組件不止一個,則返回第一個Test類型腳本組件。
3.4.5 向量
在Unity中使用Vector3表示空間中的所有向量,具體可以使用如下的JavaScript代碼片段來實現(xiàn)。
1 var position : Vector3 ;
2 position.x = 3; //x軸分量
3 position.y = 4; //y軸分量
4 position.z = 5; //z軸分量
也可以直接給position賦值,不必分別給x、y、z賦值,具體可以使用如下的JavaScript代碼片段來實現(xiàn)。
1 var position : Vector3 ;
2 position = Vector3(3,4,5);
當然,也可以使用如下的C#代碼片段來實現(xiàn)相同的功能。
1 using UnityEngine; //引入系統(tǒng)包
2 using System.Collections; //引入系統(tǒng)包
3 public class example : MonoBehaviour {
4 public Vector3 position = new Vector3(3, 4, 5); //new一個新向量
5 }
Vector3也自定義了一些固定的值,例如Vector3.up等同于Vector3(0,1,0),Vector3.zero等同于Vector3(0,0,0)等,這樣可以簡化代碼。
Vector3類中有很多實用的方法,例如想要獲得兩點之間的距離時,可以使用Vector3.Distance()方法,具體可以使用如下的JavaScript代碼片段來實現(xiàn)。
1 var position1 : Vector3 = Vector3(2,1,3); //聲明向量position1
2 var position2 : Vector3 = Vector3(3,4,5); //聲明向量position2
3 var theDistance = Vector3.Distance(position1, position2);//求向量position1和position2之間的距離
當然,也可以使用如下的C#代碼片段來實現(xiàn)相同的功能。
1 using UnityEngine;
2 using System.Collections; //引入系統(tǒng)包
3 public class example : MonoBehaviour {
4 public Vector3 position1 = new Vector3(2, 1, 3); //聲明向量
5 public Vector3 position2 = new Vector3(3, 4, 5); //聲明向量
6 //求兩個向量之間的距離
7 public float theDistance = Vector3.Distance(position1, position2);
8 }
Vector3也支持運算符,比如:JavaScript中 var position= position1+ position2,C#中 public float theDistance = position1+ position2。
3.4.6 成員變量和全局變量
一般情況下,定義在方法體外的變量是成員變量,這個變量可以在屬性查看器查看到,若進行修改,而且它會隨著項目一起自動保存,如在JavaScript中:
var a : int = 1;
而在C#腳本中:
public int a = 1;
在屬性查看器中可以看到這個變量,名字為“a”,值為“1”,讀者可以修改它的值。
如果聲明的是一個組件類型的變量(類似GameObject、Transform、Rigidbody等),需要在屬性查看器拖曳游戲?qū)ο蟮阶兞刻幉⒋_定它的值,具體可以使用如下的JavaScript代碼片段來實現(xiàn)。
1 //聲明一個敵人對象
2 var enemy: GameObject;
3 function Update(){
4 //如果敵人和初始點的距離小于10
5 if ( Vector3.Distance( enemy.position, Vector3.zero ) < 10 ) {
6 print("I sense the enemy is near!");
7 } }
這樣,在屬性查看器中直接拖曳敵人對象到 enemy 變量即可。當然,也可以使用如下的 C#代碼片段來實現(xiàn)相同的功能。
1 using UnityEngine;
2 using System.Collections; //引入系統(tǒng)包
3 public class example : MonoBehaviour { //聲明example類
4 public Transform enemy; //聲明一個Transform
5 void Update() { //重寫Update方法
6 //如果enemy和transform的距離小于10,則打印出一句話
7 if (Vector3.Distance(enemy.position, transform.position) < 10)
8 print("I sense the enemy is near!");
9 }}
可以通過private創(chuàng)建私有變量,這樣在屬性查看器中就不會顯示該變量,避免錯誤地修改。具體可以使用如下的JavaScript代碼片段來實現(xiàn)。
1 private var lastCollider : Collider;
2 //碰撞檢測事件
3 function OnCollisionEnter(collisionInfo : Collision ) {
4 lastCollider = collisionInfo.collider;
5 }
當然,也可以使用如下的C#代碼片段來實現(xiàn)相同的功能。
1 using UnityEngine;
2 using System.Collections; //引入系統(tǒng)包
3 public class example : MonoBehaviour { //聲明example類
4 private Collider lastCollider; //聲明一個Collider
5 //碰撞檢測事件
6 void OnCollisionEnter(Collision collisionInfo) {
7 lastCollider = collisionInfo.collider;
8 }}
也可以通過 static 來創(chuàng)建全局變量,這樣就可以在不同腳本間調(diào)用這個變量,具體可以使用如下的JavaScript代碼片段來實現(xiàn)。
1 //腳本里的靜態(tài)變量名為 'test'
2 static var test : int = 5;
3 //讀者可以像普通變量一樣去調(diào)用它
4 print(test);
5 test = 1;
當然,也可以使用如下的C#代碼片段來實現(xiàn)相同的功能。
1 using UnityEngine;
2 using System.Collections; //引入系統(tǒng)包
3 public class example : MonoBehaviour { //聲明example類
4 public static int test = 5; //聲明一個靜態(tài)整型變量
5 print(test); //打印
6 test = 1; //賦值
7 }
如果想從另外一個腳本調(diào)用變量 test,讀者可以通過“腳本名.變量名”的方式調(diào)用,具體可以使用如下的JavaScript代碼片段來實現(xiàn)。
1 //腳本名稱為“Hello.js”
2 print(Test.test);
3 Test.test = 10;
當然,也可以使用如下的C#代碼片段來實現(xiàn)相同的功能。
1 using UnityEngine;
2 using System.Collections; //引入系統(tǒng)包
3 public class hello : MonoBehaviour { //聲明example類
4 void Start() { //重寫Start方法
5 print(Test.test); //打印Test.cs腳本中的變量
6 Test.test = 10; //給Test.cs腳本中的變量賦值
7 }}
3.4.7 實例化
Unity 中如果要創(chuàng)建很多相同的物體(比如射擊出去的子彈,保齡球瓶等)時,可以通過實例化(Instantiate)快速實現(xiàn)。而且實例化出來的對象包含了這個對象所有的屬性,這樣就能保證原封不動地創(chuàng)建所需的對象。實例化在 Unity 中有很多用途,充分使用它非常必要。實例化常和預制件(Prefabs)一起使用。
例如,創(chuàng)建一個腳本“Hit.js”,當一個碰撞體撞擊到一個物體時,銷毀這個物體,并創(chuàng)建一個損壞的物體,具體可以使用如下的JavaScript代碼片段來實現(xiàn)。
1 var broke : Transform ;
2 //當一個碰撞發(fā)生自毀
3 //在相同位置實例化一個代替物體
4 function OnCollisionEnter (){
5 //撞擊發(fā)生1s后銷毀物體
6 Destroy (broke.gameObject,1);
7 var brokes : Transform ;
8 //在物體原來的位置創(chuàng)建一個和原來物體姿態(tài)一樣的物體
9 theClonedExplosion = Instantiate(brokes,broke.position, broke.rotation);
10 }
當然,也可以使用如下的C#代碼片段來實現(xiàn)相同的功能。
1 using UnityEngine;
2 using System.Collections; //引入系統(tǒng)包
3 public class example : MonoBehaviour { //聲明example類
4 public Transform explosion; //聲明explosion變量
5 void OnCollisionEnter() { //重寫OnCollisionEnter方法
6 Destroy(gameObject,1); //撞擊發(fā)生1s后銷毀對象
7 Transform theClonedExplosion; //聲明變量
8 //在物體原來的位置創(chuàng)建一個和原來物體姿態(tài)一樣的物體
9 theClonedExplosion = Instantiate(explosion, transform.position,
10 transform.rotation) as Transform;
11 }}
說明
Destroy(gameobject,n)是在n秒后銷毀物體,也可以使用DestroyImmediate(gameobject,boolean),這樣就可以根據(jù)布爾值,判斷是否直接銷毀物體。
3.4.8 協(xié)同程序和中斷
如果通過寫代碼去實現(xiàn)游戲的連續(xù)步驟的話,有時會產(chǎn)生大量重復的工作,具體可以使用如下的JavaScript代碼片段來實現(xiàn)。
1 private var state = 0;
2 function Update() {
3 if (state == 0) {
4 //做步驟0
5 state = 1;
6 return;
7 }
8 if (state == 1) {
9 // 做步驟1
10 state = 2;
11 return;
12 }
13 // ...
14 }
當然,也可以使用如下的C#代碼片段來實現(xiàn)相同的功能。
1 using UnityEngine;
2 using System.Collections; //引入系統(tǒng)包
3 public class example : MonoBehaviour { //聲明example類
4 private int state = 0; //聲明state變量
5 void Update() { //重寫Update函數(shù)
6 if (state == 0) { //做步驟0
7 state = 1;
8 return;
9 }
10 if (state == 1) { // 做步驟1
11 state = 2;
12 return;
13 }}}
這時候,如果使用中斷可以更方便,具體可以使用如下的JavaScript代碼片段來實現(xiàn)。
1 while(true) {
2 // 做步驟0
3 yield;
4 // 等待一幀
5 // 做步驟1
6 yield;
7 // 等待一幀
8 // ...
9 }
當然,也可以使用如下的C#代碼片段來實現(xiàn)相同的功能。
1 using UnityEngine;
2 using System.Collections; //引入系統(tǒng)包
3 public class example : MonoBehaviour { //聲明example類
4 IEnumerator Example() { //聲明Example函數(shù)
5 while (true) {
6 yield return null; // 等待一幀
7 yield return null; // 等待一幀
8 }}}
說明
在腳本中,中斷語句是一個特殊的返回類型,它可以使函數(shù)的執(zhí)行跳到中斷語句的下一行。
也可以傳遞時間值到中斷語句,Update函數(shù)會在中斷時間結(jié)束后執(zhí)行下一語句,具體可以使用如下的JavaScript代碼片段來實現(xiàn)。
1 //...
2 yield WaitForSeconds (2.0); //等待2s
3 //...
當然,也可以使用如下的C#代碼片段來實現(xiàn)相同的功能。
1 //...
2 yield return new WaitForSeconds(2.0F); //等待2s
3 //...
下面的代碼片段先執(zhí)行 Do()函數(shù),但是 Do()函數(shù)之后的 print 語句也會立即執(zhí)行,具體JavaScript代碼片段來實現(xiàn)。
1 Do (); //執(zhí)行Do函數(shù)
2 print ("This is printed immediately"); //打印提示信息
3 function Do (){ //聲明Do函數(shù)
4 print("Do now"); //打印提示信息
5 yield WaitForSeconds (2); //休眠2s
6 print("Do 2 seconds later"); //打印提示信息
7 }
當然,也可以使用如下的C#代碼片段來實現(xiàn)相同的功能。
1 using UnityEngine;
2 using System.Collections; //引入系統(tǒng)包
3 public class example : MonoBehaviour { //聲明example類
4 IEnumerator Do() { //聲明Do函數(shù)
5 print("Do now"); //打印
6 yield return new WaitForSeconds(2); //等待2s
7 print("Do 2 seconds later"); //再次打印
8 }
9 void Example() { //聲明Exame函數(shù)
10 Do(); //調(diào)用Do方法
11 print("This is printed immediately"); //打印
12 }}
修改上面的代碼,使用連接協(xié)同程序,那么程序?qū)⑾葓?zhí)行Do函數(shù),等待,執(zhí)行完Do函數(shù)之后再執(zhí)行其他語句,具體可以使用如下的JavaScript代碼片段來實現(xiàn)。
1 //連接協(xié)同程序
2 yield StartCoroutine("Do");
3 print("Also after 2 seconds"); //打印提示信息
4 print ("This is after the Do coroutine has finished execution"); //打印提示信息
5 function Do (){ //聲明D函數(shù)
6 print("Do now"); //打印提示信息
7 yield WaitForSeconds (2); //休眠2s
8 print("Do 2 seconds later"); //打印提示信息
9 }
當然,也可以使用如下的C#代碼片段來實現(xiàn)相同的功能。
1 using UnityEngine;
2 using System.Collections; //引入系統(tǒng)包
3 public class example : MonoBehaviour { //聲明example類
4 IEnumerator Do() { //聲明Example函數(shù)
5 print("Do now"); //打印
6 yield return new WaitForSeconds(2); //等待2s
7 print("Do 2 seconds later"); //再次打印
8 }
9 IEnumerator Example() { //聲明Example函數(shù)
10 yield return StartCoroutine("Do"); //啟動Do協(xié)同程序
11 print("Also after 2 seconds"); //打印
12 print("This is after the Do coroutine has finished execution");//打印
13 }}
說明
任何時間處理程序都是協(xié)同程序,但是在Update()和FixUpdate()中不能使用協(xié)同程序。
3.4.9 一些重要的類
本小節(jié)將向讀者介紹Unity腳本中的一些重要的類,由于篇幅的限制,所以本小節(jié)只對這些類中的比較常用的變量和函數(shù)進行簡單的介紹說明,其他具體的信息讀者可參考官方腳本參考手冊。
1.MonoBehaviour類
MonoBehaviour 是每個腳本的基類,其繼承自 Behaviour 類。每個 JavaScript 腳本自動繼承MonoBehaviour,使用C#時,需要顯式繼承MonoBehaviour。
MonoBehaviour 類中的方法可以重寫,這些方法在兩種腳本中只是在方法聲明上有一點差別外,其他大致相同。下面介紹一下主要可重寫的方法,如表3-2所示。
表3-2 MonoBehaviour類中主要可重寫的函數(shù)

MonoBehaviour類中有很多的繼承函數(shù),下面將介紹主要的繼承函數(shù),如表3-3所示。
表3-3 MonoBehaviour類中主要的繼承函數(shù)

MonoBehaviour類中還有很多繼承類函數(shù),下面將介紹主要的繼承類函數(shù),如表3-4所示。
表3-4 MonoBehaviour類中主要的繼承類函數(shù)

說明
讀者可能對“繼承函數(shù)”和“繼承類函數(shù)”兩個概念比較疑惑。“繼承函數(shù)”指的是其函數(shù)都是從父類直接繼承或者從父類間接繼承而來的函數(shù),而“繼承類函數(shù)”指的是其函數(shù)均從根類Object中間接繼承而來,而非從其他父類繼承而來。
2.Transform類
場景中的每一個物體都有一個Transform。用于儲存并操控物體的位置、旋轉(zhuǎn)和縮放。每一個Transform可以有一個父級,允許你分層次應用位置、旋轉(zhuǎn)和縮放??梢栽贖ierarchy面板查看層次關系。Transform類中包含了很多變量,下面將介紹主要的變量,如表3-5所示。
表3-5 Transform類中主要的變量

Transform類中同時還有很多函數(shù),下面將介紹主要的函數(shù),如表3-6所示。
表3-6 Transform類中主要的函數(shù)

3.Rigidbody類
Rigidbody可以模擬物體在物理效果下的狀態(tài)。它可以讓物體接收力和扭矩,讓物體相對真實地移動。如果一個物體想被重力所約束,其必須含有Rigidbody屬性。Rigidbody類中包含很多變量,下面將介紹主要的變量,如表3-7所示。
Rigidbody類中包含很多函數(shù),下面將介紹主要的函數(shù),如表3-8所示。
表3-7 Rigidbody類中主要的變量

表3-8 Rigidbody類中主要的函數(shù)

4.CharacterController類
角色控制器用于第三人稱或者第一人稱游戲主角控制。它可以根據(jù)碰撞檢測判斷是否能夠移動,而不必給角色控制器添加Rigidbody。而且角色控制器不會受到力的影響,當調(diào)用Move函數(shù)時,系統(tǒng)會先檢查角色控制器是否和其他物體發(fā)生碰撞,然后才決定移動與否。
在屬性查看器中可以查看到其屬性,具體的屬性如表3-9所示。
表3-9 Inspector面板中角色控制器的主要屬性

CharacterController類中包含很多變量,下面將介紹一下CharacterController類中的主要變量,如表3-10所示。
表3-10 CharacterControler類中的主要變量

CharacterController類中包含很多函數(shù),下面將介紹一下CharacterController類中的主要函數(shù),如表3-11所示。
表3-11 CharacterControler類中的主要函數(shù)

3.4.10 性能優(yōu)化
Unity 中專用的 JavaScript 對性能進行了大量的優(yōu)化措施,比如使用靜態(tài)類型,使用#pragma strict,緩存組件查詢,使用內(nèi)建數(shù)組以及盡量少調(diào)用函數(shù)等措施。下面將對各個措施進行介紹。
1.使用靜態(tài)類型
在JavaScript中,很重要的優(yōu)化就是使用靜態(tài)類型代替動態(tài)類型。Unity中有一種邏輯推理的技術(shù)自動將JavaScript轉(zhuǎn)換為靜態(tài)腳本,無需做額外的工作。例如:
var a = 1;
此時,Unity會推斷a為整形,不需要使用動態(tài)名稱查找等技術(shù),節(jié)省了大量的時間。但是,有些變量是無法被推斷的,比如下面的代碼片段所示:
1 function Start (){ //聲明Start方法
2 var test = GetComponent(Test); //調(diào)用Test腳本
3 test.DoSomething(); //執(zhí)行Test腳本中的DoSomething方法
4 }
因為 test 是未知類型,所以在調(diào)用 DoSomeThing()函數(shù)之前,Unity 需要檢查 test 是否支持DoSomeThing()函數(shù),所以很耗時間。
如果想要獲得更好的性能,可將上面的代碼改成如下代碼片段:
1 function Start () { //聲明Start方法
2 var test: Test = GetComponent(Test); //調(diào)用Test腳本
3 test.DoSomething(); //執(zhí)行Test腳本中的DoSomething方法
4 }
說明
在腳本中,聲明變量時明確變量的類型,避免了Unity系統(tǒng)對類型的檢查,可以獲得更快的速度,這對于移動開發(fā)更重要。
2.使用#pragma strict
有時可能會在無意識的情況下寫出未知類型的變量,如果在腳本的開始加入#pragma strict語句后,Unity就會禁用JavaScript的動態(tài)類型,如果腳本中有動態(tài)類型的聲明,Unity就會報告編譯錯誤。例如,在禁用動態(tài)類型的情況下,下面的代碼片段在Unity中編譯就會報錯。
var test = GetComponent(Test);
3.緩存組件查詢
這種優(yōu)化不一定是必須的,但是如果想更高的提升性能的話,優(yōu)化組件緩沖也是可以考慮的。當通過GetComponent查詢一個組件時,可以設置一個私有變量去儲存這個組件。這樣,Unity無需在每一幀中去查詢Transform類型的組件。實現(xiàn)方式可以參考如下代碼片段:
1 private var myTransform : Transform ; //聲明靜態(tài)變量
2 function Awake (){ //聲明Awake方法
3 myTransform = transform;
4 }
5 function Update (){ //聲明Update方法
6 myTransform.Translate(0, 0, 2); //沿z軸每幀移動2個單位
7 }
說明
這種先聲明一個私有變量,然后在Awake方法中賦值,把對應的組件對象存放在私有變量的方式同樣適用于腳本組件。
4.使用內(nèi)建數(shù)組
雖然ArrayList和Array很容易使用,而且很方便,但是相比內(nèi)建數(shù)組而言,他們的速度還是有很大的差異。內(nèi)建數(shù)組直接嵌入 struct 數(shù)據(jù)類型存入第一個緩沖區(qū)里,不需要其他類型信息或者其他資源。因此做緩存遍歷更快捷,如:
1 private var positions : Vector3 []; //聲明靜態(tài)向量
2 function Awake (){ //聲明Awake方法
3 positions = new Vector3 [100]; //創(chuàng)建一個向量
4 for (var i=0;i<100;i++){ //執(zhí)行for循環(huán)
5 positions[i] = Vector3.zero ; //為每個向量賦值
6 } }
5.盡量少調(diào)用函數(shù)
最簡單和最有效的優(yōu)化就是干最少的工作。Unity中Update()函數(shù)每一幀都在運行,所以減少Update()函數(shù)里面工作量,可以大量優(yōu)化性能。讀者通過協(xié)調(diào)程序或者加入標志位就能實現(xiàn)。
說明
在實際開發(fā)中,一般把標志位檢查放在函數(shù)外面,這樣就無需每一幀都檢查標志位,減少了系統(tǒng)性能的消耗。
3.4.11 腳本編譯
Unity 可以把腳本編譯為.dll 文件,.dll 文件將在運行時編譯運行。這樣做可以提高執(zhí)行的速度,比傳統(tǒng)的JavaScript腳本要快20倍左右。
腳本具體的編譯需要以下4步。
(1)所有的“Standard Assert”、“Pro Standard Assert”或者“Plugins”文件夾里的腳本會被首先編譯。
(2)所有的“Standard Assert/Editor”、“Pro Standard Assert/Editor”或者“Plugins/Editor”文件夾里的腳本會被首先編譯。
(3)所有在“Editor”文件夾里面的腳本接著被編譯。
(4)其他腳本在最后編譯。所有這一步里編譯的腳本,可以訪問第一組提到的所有腳本(即“Standard Assets”、“Pro Standard Assets”或者“Plugins”文件夾里的腳本)。
提示
最后編譯的腳本可以訪問最先編譯的腳本,實現(xiàn)了不同的腳本語言之間的溝通。例如,想在一個JavaScript腳本中引用一個C#腳本,可以將C#腳本放到“Standard Assets”文件夾下,然后將JavaScript腳本放在此文件夾之外,JavaScript腳本便可以直接引用C#腳本。在“WebPlayer Templates”文件夾下的腳本不會被編譯。
根據(jù)Unity的版本進行編譯。在腳本的開始寫入一些代碼:
1 // 判斷Unity的版本
2 #if UNITY_2_6_0
3 //使用2.6.0特性
4 #endif
5 // 判斷Unity的版本
6 #if UNITY_2_6
7 // 使用2.6.x特性
8 #endif
說明
上面的代碼寫在腳本的開始處,然后,當Unity編譯器在編譯時,是從Unity2.6版本開始的。
這樣,就能確保游戲的特性只在對應的版本中使用。這樣也可以標記腳本,確保在對應的Unity版本中才能使用。
3.4.12 泛化方法
手冊中的一些方法可以進行泛化通過方法名字后面加T或者.<T>。如下面的代碼片段:
function FuncName.<T>(): T;
這些就是泛化方法。這對于腳本的意義就是,當調(diào)用這個方法時,可以指定參數(shù)的類型或者返回值的類型。在JavaScript中,泛化方法可以用于動態(tài)類型的局限性:
1 //類型推斷正確由于被定義為函數(shù)調(diào)用
2 var obj = GetComponent.<Rigidbody>();
手冊中任何一種方法都可以通過特殊的調(diào)用語句進行泛化。
- 大前端三劍客:Vue+React+Flutter
- 企業(yè)性能測試:體系構(gòu)建、落地指導與案例解讀
- App草圖+流程圖+交互原型設計教程
- 產(chǎn)品經(jīng)理入門攻略
- 產(chǎn)品眾包設計理論與方法
- 鑄魂:軟件定義制造
- Android深度探索(卷1):HAL與驅(qū)動開發(fā)
- 實用軟件工程
- Android應用安全防護和逆向分析
- 負載均衡:高并發(fā)網(wǎng)關設計原理與實踐
- 內(nèi)容理解:技術(shù)、算法與實踐
- 大數(shù)據(jù)實時流處理技術(shù)實戰(zhàn):基于Flink+Kafka技術(shù)
- 芯片改變世界
- 微信小程序開發(fā)詳解
- C語言程序開發(fā)范例寶典(軟件工程師典藏版)