Unity內部的腳本,是通過附加自定義腳本對象到游戲物體組成的。在腳本對象內部不同的函數被特定的事件調用。最常用的列在下面:
Awake: 在MonoBehavior創建后就立刻調用
Start: 將在MonoBehavior創建后在該幀Update之前,在該Monobehavior.enabled == true的情況下執行。
當MonoBehavior沒有定義[ExecuteInEditMode]時
總結:我們盡量將其他Object的reference設置等事情放在Awake處理。然后將這些reference的Object的賦值設置放在Start()中來完成。
當MonoBehavior有定義[ExecuteInEditMode]時
當我們為MonoBehavior定義了[ExecuteInEditMode]后,我們還需要關心Awake和Start在編輯器中的執行狀況。
-
當該MonoBehavior在編輯器中被賦於給GameObject的時候,Awake, Start 將被執行。
-
當Play按鈕被按下游戲開始以后,Awake, Start 將被執行。
-
當Play按鈕停止后,Awake, Start將 再次被執行。
-
當在編輯器中打開包含有該MonoBehavior的場景的時候,Awake, Start將被執行。
值得注意的是,不要用這種方式來設定一些臨時變量的存儲(private, protected)。因為一旦我們觸發Unity3D的代碼編譯,這些變量所存儲的內容將被清為默認值。
Update:這個函數在渲染一幀之前被調用。這里是大部分游戲行為代碼被執行的地方,除了物理代碼。
FixedUpdate:這個函數在每個物理時間步被調用一次。這是處理基於物理游戲行為的地方。
常用操作
大多數游戲物體的操作是通過游戲物體的Transform和/或Rigidbody來做的。在行為腳本內部它們可以分別通過transform和rigidbody訪問.因此如果你想繞着Y軸每幀旋轉5度,你可以如下寫:
function Update() {
transform.Rotate(0, 5, 0);
}
如果你想向前移動一個物體,你應該如下寫:
function Update() {
transform.Translate(0, 0, 2);
}
移動物體:
function Update() {
transform.Translate(0, 0, 2 * Time.deltaTime);
}
如果你加或減一個每幀改變的值,你應該將它與 Time.deltaTime相乘。當你乘以Time.deltaTime時,你實際表達:我想以 10米 /秒移動這個物體而不是 10米 /幀。這不僅僅是因為你的游戲將獨立於幀率運行,同時也是因為運動的單位容易理解。( 10米 /秒)
另一個例子,如果你想隨着時間增加光照的范圍。下面的表達式,以2單位/秒改變半徑.
function Update() {
light.range += 2.0 * Time.deltaTime;
}
當通過力處理剛體的時候,你通常不必用Time.deltaTime乘,因為引擎已經為你考慮到了這一點。
訪問其他組件
組件被附加到游戲物體。附加Renderer到游戲物體使它在場景中渲染,附加一個Camera使它變為相機物體。所有的腳本都是組件,因為它們能被附加到游戲物體。
最常用的組件可以作為簡單成員變量訪問:
Component
可如下訪問
Transform
Rigidbody
Renderer
Camera (only on camera objects)
Light (only on light objects)
Animation
Collider
... 等等。
對於完整的預定義成員變量的列表,查看Component, Behaviour和MonoBehaviour類文檔。如果游戲物體沒有你想取回類型的組件,上面的變量將被設置為null。
任何附加到一個游戲物體的組件或腳本都可以通過GetComponent訪問。
transform.Translate(0, 1, 0);
// 等同於
GetComponent(Transform).Translate(0, 1, 0);
注意transform和Transform之間大小寫的區別. 前者是變量(小寫),后者是類或腳本名稱(大寫). 大小寫不同使你能夠從類和腳本名中區分變量。
應用我們所學,你可以使用GetComponent找到任何附加在同一游戲物體上的腳本和組件。請注意要使下面的例子能夠工作,你需要有一個名為 OtherScript的腳本,其中包含一個DoSomething函數。OtherScript腳本必須與下面的腳本附加到相同的游戲物體上。
//這個在同一個游戲物體上找到名為OtherScript的腳本
//並調用它上面的DoSomething.
function Update () {
otherScript = GetComponent(OtherScript);
otherScript.DoSomething();
}
訪問其他游戲物體
大多數高級的代碼不僅需要操作一個物體。Unity腳本接口有各種方法來找到並訪問其他游戲物體和組件。在下面,我們假定有一個名為OtherScript.js的腳本附加到場景的游戲物體上。
var foo = 5;
function DoSomething ( param : String) {
print(param + " with foo: " + foo);
}
1. 通過檢視面板賦值引用.
你可以通過檢視面板賦值變量到任何物體。
// 變換拖動到target槽的物體
var target : Transform;
function Update ()
{
target.Translate(0, 1, 0);
}
你也可以在檢視面板中公開到其他物體的引用。下面你可以拖動一個包含OtherScript的游戲物體到檢視面板中的target槽。
// 設置在檢視面板中賦值的target變量上的foo,調用DoSomething.
var target : OtherScript;
function Update ()
{
//設置target物體的foo變量
target.foo = 2;
// 調用target上的DoSomething
target.DoSomething("Hello");
}
2. 通過物體層次定位.
對於一個已存在的物體,可以通過游戲物體的Transform組件來找到子和父物體:
// 找到腳本所附加的
// 游戲物體的子"Hand"
transform.Find("Hand").Translate(0, 1, 0);
一旦在層次視圖中找到這個變換,你可以使用GetComponent來獲取其他腳本.
//找到名為"Hand"的子.
//在附加到它上面的OtherScript中, 設置foo為2.
transform.Find("Hand").GetComponent(OtherScript).foo = 2;
//找到名為"Hand"的子.
//調用附加到它上面的OtherScript腳本中的DoSomething.
transform.Find("Hand").GetComponent(OtherScript).DoSomething("Hello");
//找到名為"Hand"的子.
//然后應用一個力到附加在hand上的剛體.
transform.Find("Hand").rigidbody.AddForce(0, 10, 0);
你可以循環所有的子。
// 變換的所有子向上移動10個單位!
for (var child : Transform in transform)
{
child.Translate(0, 1, 0);
}
參考Transform類文檔獲取更多信息。
3.根據名稱或標簽定位.
你可以使用GameObject.FindWithTag和GameObject.FindGameObjectsWithTag搜索具有特定標簽的游戲物體。使用GameObject.Find根據名稱查找物體.
function Start ()
{
// 按照名稱
var go = GameObject.Find("SomeGuy");
go.transform.Translate(0, 1, 0);
// 按照標簽
var player = GameObject.FindWithTag("Player");
player.transform.Translate(0, 1, 0);
}
你可以在結果上使用GetComponent,在找到的游戲物體上得到任何腳本或組件。
function Start ()
{
// 按名稱
var go = GameObject.Find("SomeGuy");
go.GetComponent(OtherScript).DoSomething();
//按標簽
var player = GameObject.FindWithTag("Player");
player.GetComponent(OtherScript).DoSomething();
}
一些特殊的物體有快捷方式,如主相機使用Camera.main。
4. 作為參數傳遞.
一些事件消息在事件中包含詳細信息。例如,觸發器事件傳遞碰撞物體的Collider組件到處理函數。
OnTriggerStay給我們一個到碰撞器的引用。從這個碰撞器我們可以獲取附加到其上的剛體。
function OnTriggerStay (other : Collider ) {
//如果另一個碰撞器也有一個剛體
// 應用一個力到它上面!
if (other.rigidbody) {
other.rigidbody.AddForce(0, 2, 0);
}
}
或者我們可以通過碰撞器獲取附加在同一物體上的任何組件。
function OnTriggerStay (other : Collider ) {
// 如果另一個碰撞器附加了OtherScript
// 調用它上面的DoSomething.
// 大多數時候碰撞器不會附加腳本,
// 所以我們需要首先檢查以避免null引用異常。
if (other.GetComponent(OtherScript)) {
other.GetComponent(OtherScript).DoSomething();
}
}
注意通過上述例子中的other變量,你可以訪問碰撞物體中的任何組件。
5.一種類型的所有腳本
使用Object.FindObjectsOfType找到所有具有相同類或腳本名稱的物體,或者使用Object.FindObjectOfType找到這個類型的第一個物體。
function Start ()
{
// 找到場景中附加了OtherScript的任意一個游戲物體.
var other : OtherScript = FindObjectOfType(OtherScript);
other.DoSomething();
}
向量
Unity使用Vector3類統一表示全體3D向量。3D向量的不同組件可以通過x, y 和 z成員變量訪問。
var aPosition : Vector3;
aPosition.x = 1;
aPosition.y = 1;
aPosition.z = 1;
你也能夠使用Vector3構造函數來同時初始化所有組件.
var aPosition = Vector3(1, 1, 1);
Vector3也定義了一些常用的常量值.
var direction = Vector3.up; // 與Vector3(0, 1, 0);相同
單個向量上的操作可以使用下面方式訪問:
someVector.Normalize();
使用多個向量的操作可以使用Vector3類函數:
theDistance = Vector3.Distance(oneVector, otherVector);
(注意你必須在函數名之前寫Vector3.來告訴Javascript在哪里找到這個函數. 這適用於所有類函數。)
你也可以使用普通數學操作來操縱向量。
combined = vector1 + vector2;
查看Vector3類文檔獲取完整操作和可用屬性的列表。
成員變量 & 全局變量變量
定義在任何函數之外的變量是一個成員變量。在Unity中這個變量可以通過檢視面板來訪問。任何保存在成員變量中的值也可以自動隨工程保存。
var memberVariable = 0.0;
上面的變量將在檢視面板中顯示為名為"Member Variable"的數值屬性。
如果你設置變量的類型為一個組件類型(例如Transform, Rigidbody, Collider, 任何腳本名稱, 等等.)然后你可以在檢視面板中通過拖動一個游戲物體來設置它們。
var enemy : Transform;
function Update()
{
if ( Vector3.Distance( enemy.position, transform.position ) < 10 ) {
print("I sense the enemy is near!");
}
}
你也可以創建私有成員變量。私有成員變量可以用來存儲那些在該腳本之外不可見的狀態。私有成員變量不會被保存到磁盤並且在檢視面板中不能編輯。當它被設置為調試模式時,它們在檢視面板中可見。這允許你就像一個實時更新的調試器一樣使用私有變量。
private var lastCollider : Collider;
function OnCollisionEnter( collisionInfo : Collision ) {
lastCollider = collisionInfo.other;
}
全局變量
你也可以使用static關鍵字創建全局變量。
這創造了一個全局變量,名為someGlobal。
// 'TheScriptName.js'中的一個靜態變量
static var someGlobal = 5;
// 你可以在腳本內部像普通變量一樣訪問它
print(someGlobal);
someGlobal = 1;
為了從另一個腳本訪問它,你需要使用這個腳本的名稱加上一個點和全局變量名。
print(TheScriptName.someGlobal);
TheScriptName.someGlobal = 10;
實例化
實例化,復制一個物體。包含所有附加的腳本和整個層次。它以你期望的方式保持引用,到外部物體引用的克隆層次將保持完好,在克隆層次上到物體的引用將映射到克隆物體。
實例化是難以置信的快和非常有用的。因此最大化地使用它是必要的。
例如,這里是一個小的腳本,當附加到一個帶有碰撞器的剛體上時將銷毀它自己並實例化一個爆炸物體。
var explosion : Transform;
// 當碰撞發生時銷毀我們自己
// 並生成一個爆炸預設
function OnCollisionEnter ()
{
Destroy (gameObject);
var theClonedExplosion : Transform;
theClonedExplosion = Instantiate(explosion,transform.position, transform.rotation);
}
實例化通常與預設一起使用。