1. 簡單介紹
在Unity3D中,游戲對象(GameObject)的行為是由附加其上的腳本來控制的,游戲開發人員通過編寫腳本來控制游戲中的全部對象,如移動Camera等。
GameObject能夠被附加不同類型的組件。但每種類型的組件僅僅能有一個或沒有。
腳本本質上也是一種組件。
在Unity3D中默認的腳本代碼例如以下所看到的:
<span style="font-family:Arial;"><span style="font-family:Arial;">// ***** C# script *****
using UnityEngine;
using System.Collections;
public class ffc : MonoBehaviour {
// Use this for initialization
void Start () {
}
/ Update is called once per frame
void Update () {
}
}
//***** Java script *****
#pragma strict
function Start () {
}
function Update () {
}
</span></span>
由此可見,腳本代碼與大家熟悉的Java代碼類似,即都是由下面兩部分組成:
• 變量
• 函數
• 其他代碼:在不論什么函數之外的代碼在物體被載入的時候執行。這個能夠用來初始化腳本狀態。
MonoBehaviour是全部腳本的基類。每一個Javascript腳本自己主動繼承MonoBehaviour,使用C#或Boo時,須要顯式繼承MonoBehaviour.
1.1 腳本成員變量
腳本變量就是指類的成員變量(即在JavaScript或C#或Boo中定義的成員變量,而不是基類MonoBehaviour中定義的變量),在Unity3D中將成員變量設為公有的時候,當把它附加到游戲對象后。能夠在游戲對象的監視面板中的腳本組件那欄里面看到該“公有變量”。即能夠在編輯器中直接對該公有變量進行賦值,同一時候在Debug狀態下也能夠在面板中看到它的值。
1.2 基類可被繼承的成員變量(內置變量)
| 變量名 | 描寫敘述 |
| transform | The Transform attached to this GameObject (null if there is none attached). |
| rigidbody | The Rigidbody attached to this GameObject (null if there is none attached). |
| camera | The Camera attached to this GameObject (null if there is none attached). |
| light | The Light attached to this GameObject (null if there is none attached). |
| animation | The Animation attached to this GameObject (null if there is none attached). |
| constantForce | The ConstantForce attached to this GameObject (null if there is none attached). |
| renderer | The Renderer attached to this GameObject (null if there is none attached). |
| audio | The AudioSource attached to this GameObject (null if there is none attached). |
| guiText | The GUIText attached to this GameObject (null if there is none attached). |
| networkView | The NetworkView attached to this GameObject (Read Only). (null if there is none attached) |
| guiTexture | The GUITexture attached to this GameObject (Read Only). (null if there is none attached) |
| collider | The Collider attached to this GameObject (null if there is none attached). |
| hingeJoint | The HingeJoint attached to this GameObject (null if there is none attached). |
| particleEmitter | The ParticleEmitter attached to this GameObject (null if there is none attached). |
| gameObject | The game object this component is attached to. A component is always attached to a game object. |
| tag | The tag of this game object. |
1.3 基類可被繼承的類函數
| 類函數 | 描寫敘述 |
| Destroy | Removes a gameobject, component or asset. |
| DestroyImmediate | Destroys the object obj immediately. It is strongly recommended to use Destroy instead. |
| DontDestroyOnLoad | Makes the object target not be destroyed automatically when loading a new scene. |
| FindObjectOfType | Returns the first active loaded object of Type type. |
| FindObjectsOfType | Returns a list of all active loaded objects of Type type. |
| Instantiate | Clones the object original and returns the clone. |
1.4 基類可被繼承的函數
| 類函數 | 描寫敘述 |
| GetComponent | Returns the component ofType type if the game object has one attached, null if it doesn't. function GetComponent (type :Type) : Component |
| GetComponent | Returns the component withnametype if the game object has one attached, null if it doesn't. function GetComponent (type :string) : Component |
| GetComponentInChildren | Returns the component of Type type in the GameObject or any of its children using depth first search. |
| GetComponentsInChildren | Returns all components of Type type in the GameObject or any of its children. |
| GetComponents | Returns all components of Type type in the GameObject. |
| CompareTag | Is this game object tagged tag? |
| SendMessageUpwards | Calls the method named methodName on every MonoBehaviour in this game object and on every ancestor of the behaviour |
| SendMessage | Calls the method named methodName on every MonoBehaviour in this game object. |
| BroadcastMessage | Calls the method named methodName on every MonoBehaviour in this game object or any of its children. |
| GetInstanceID | Returns the instance id of the object. |
| ToString | Returns the name of the game object. |
1.5 基類可重寫函數
1.5.1 常規更新事件
| 函數名 | 描寫敘述 |
| Update | Update is called every frame, if the MonoBehaviour is enabled. |
| LateUpdate | LateUpdate is called every frame, if the Behaviour is enabled. LateUpdate is called after all Update functions have been called. This is useful to order script execution. For example a follow camera should always be implemented in LateUpdate because it tracks objects that might have moved inside Update. |
| FixedUpdate | This function is called every fixed framerate frame, if the MonoBehaviour is enabled. |
1.5.2 初始化事件
| 函數名 | 描寫敘述 |
| Awake | Awake is called when the script instance is being loaded. |
| Start | Start is called just before any of the Update methods is called the first time. |
| Reset | Reset to default values. |
1.5.3 GUI元素或Collider碰撞體事件
| 函數名 | 描寫敘述 |
| OnMouseEnter | nMouseEnter is called when the mouse entered the GUIElement or Collider. |
| OnMouseOver | OnMouseOver is called every frame while the mouse is over the GUIElement or Collider. |
| OnMouseExit | OnMouseExit is called when the mouse is not any longer over the GUIElement or Collider. |
| OnMouseDown | OnMouseDown is called when the user has pressed the mouse button while over the GUIElement or Collider. |
| OnMouseUp | OnMouseUp is called when the user has released the mouse button. |
| OnMouseUpAsButton | OnMouseUpAsButton is only called when the mouse is released over the same GUIElement or Collider as it was pressed. |
| OnMouseDrag | OnMouseDrag is called when the user has clicked on a GUIElement or Collider and is still holding down the mouse. |
1.5.4 Collider碰撞體事件
| 函數名 | 描寫敘述 |
| OnTriggerEnter | OnTriggerEnter is called when the Collider other enters the trigger. |
| OnTriggerExit | OnTriggerExit is called when the Collider other has stopped touching the trigger. |
| OnTriggerStay | OnTriggerStay is called once per frame for every Collider other that is touching the trigger. |
1.5.5 Collider碰撞體或rigibody剛體事件
| 函數名 | 描寫敘述 |
| OnCollisionEnter | OnCollisionEnter is called when this collider/rigidbody has begun touching another rigidbody/collider. |
| OnCollisionExit | OnCollisionExit is called when this collider/rigidbody has stopped touching another rigidbody/collider. |
| OnCollisionStay | OnCollisionStay is called once per frame for every collider/rigidbody that is touching rigidbody/collider. |
2. 控制游戲對象(GameObject)
在Unity3D中,能夠在監視器面板中改動物體的組件屬性,可是很多其它的時候,須要使用腳本來進行動態操作。
2.1 訪問組件
最常見的一個情形是須要使用腳本訪問附加到同樣游戲對象(GameObject)上的還有一個組件(當前腳本就是一個組件,其它的組件也就是還有一個組件了)。
一個組件實質上是一個類的實例。因而首先須要做的是獲取想要操作的組件實例的引用。這個通過GetComponent函數來實現。典型的,可能會想要將一個組件賦值給一個變量,例如以下代碼所看到的:
void Start () {
Rigidbody rb = GetComponent<Rigidbody>();
}
一旦獲取了組件實例的引用,就能夠對它的屬性進行想要的操作。同一時候也能夠調用它的一些功能函數。
假設想要訪問還有一個腳本文件。也能夠使用GetComponent,僅僅需使用腳本的類名作為該函數的組件類型參數(由於腳本本來就也是一個組件)。
// You can access script components in the same way as other components.
function Start () {
var someScript : ExampleScript;
someScript = GetComponent (ExampleScript);
someScript.DoSomething ();
}
因為一些組件類型常常使用。unity提供了一些內置的變量來訪問它們,參見1.2(內置變量)。其演示樣例代碼例如以下:
void Start () {
transform.position = Vector3.zero;
}2.2 訪問其它對象
盡管游戲對象(GameObject)都有各自的組件(包含腳本)進行處理,使用代碼進行跟蹤其它物體是常有的事。
比如,一個追趕的敵人可能須要知道玩家的位置,Unity提供了一系列的方法來獲取其它對象,以適合不同的場合。
2.2.1 將對象【靜態】鏈接到公有成員變量
最直接的辦法是將一個游戲對象加入到腳本的公有成員變量上。直接在編輯器中將須要訪問的游戲對象拖到相應腳本組件的那個公有成員變量上,Unity3D會自己主動依據變量的類型將加入的游戲對象中同樣的組件類型映射到該變量。
比如將一個游戲對象拖給一個Transform的成員變量。就會自己主動的將游戲對象的Transform組件和該變量映射起來。
直接將對象和變量鏈接起來在處理須要有永久鏈接的對象的時候是最實用的方法。
同一時候也能夠使用一個數組變量和幾個同樣類型的對象鏈接起來,可是這樣的鏈接必須在Unity3D編輯器中完畢,而不能在執行時進行。
2.2.2 【動態】定位其他對象
2.2.2.1 查找子物體
假設一個游戲場景中有非常多同一類型的對象,比如敵人、路點(waypoints)和障礙物。這些對象在游戲中須要由一個特定的腳本來監視和響應。這個時候使用變量來鏈接這些對象太過麻煩。對於這樣的情況。通常更好的方法是將一系列的對象加入到一個父對象以下,這些子對象能夠通過使用父對象的Transfrom組件來獲得。
public class WaypointManager : MonoBehaviour {
public Transform waypoints;
void Start() {
waypoints = new Transform[transform.childCount];
int i = 0;
for (Transform t in transform) {
waypoints[i++] = t;
}
}
} 同一時候也能夠使用Tranfrom.Find來查找某個詳細的子對象。使用Transform來進行對象查找操作是由於每個游戲對象都有Transfrom組件。
2.2.2.2 通過名稱或標簽訪問對象
僅僅要有一些信息。在層級場景中的不論什么位置定位到該游戲對象是可能的。單個對象能夠通過GameObject.Find函數進行查找。例如以下:GameObject player;
void Start() {
player = GameObject.Find("MainHeroCharacter");
}某個對象或者一系列的對象也能夠分別通過GameObject.FindWithTag和GameObject.FindObjectsWidthTag函數進行定位。
2.2.2.3 查找特定類型的對象
static Object FindObjectOfType(Type type)返回指定類型對象中的第一個活動的載入對象, 須要注意的是這個函數非常慢(可能是因為要在整個場景中進行遍歷),不推薦每一幀都使用這個函數。在大多數情況下能夠使用單件模式。比如:
Camera cam = FindObjectOfType(typeof(Camera)) as Camera;
因為該函數返回的類型是Object,所以須要使用as進行一下強制轉換。
static Object[ ] FindObjectsOfType(Type type);
返回指定類型的載入活動對象的列表。速度也慢
HingeJoint[ ] hinges = FindObjectsOfType(typeof(HingeJoint)) as HingeJoint[ ];
3. 創建和銷毀對象
在執行時創建和銷毀對象是常有的事。在Unity3D中。能夠使用Instantiate函數對現有的一個對象做一個拷貝來創建一個新的游戲對象。
實例化很多其它通經常使用於實例投射物(如子彈、榴彈、破片、飛行的鐵球等)。AI敵人,粒子爆炸或破壞物體的替代品。
// Instantiates 10 copies of prefab each 2 units apart from each other
var prefab : Transform;
for (var i : int = 0;i < 10; i++) {
Instantiate (prefab, Vector3(i * 2.0, 0, 0), Quaternion.identity);
} 值得注意的是用於進行拷貝的對象並不一定須要放置在場景中。更普遍的做法是將一個預設(Prefab)拖到腳本的相應公有成員變量上,實例化的時候直接對這個成員變量進行實例化就可以。
// Instantiate a rigidbody then set the velocity
var projectile : Rigidbody;
function Update () {
// Ctrl was pressed, launch a projectile
//按Ctrl發射炮彈
if (Input.GetButtonDown("Fire1")) {
// Instantiate the projectile at the position and rotation of this transform
//在該變換位置和旋轉。實例化炮彈
var clone : Rigidbody;
clone = Instantiate(projectile, transform.position, transform.rotation);
// Give the cloned object an initial velocity along the current object's Z axis
//沿着當前物體的Z軸給克隆的物體一個初速度。
clone.velocity = transform.TransformDirection (Vector3.forward * 10);
}
}
實例化也能直接克隆腳本實例,整個游戲物體層次將被克隆。而且返回被克隆腳本的實例。
同一時候也有一個Destroy函數在幀更新函數完畢后或設定的一個延時時間后銷毀一個對象。
// Kills the game object
//銷毀游戲物體
Destroy (gameObject);
// Removes this script instance from the game object
//從游戲物體刪除該腳本實例
Destroy (this);
// Removes the rigidbody from the game object
//從游戲物體刪除剛體
Destroy (rigidbody);
// Kills the game object in 5 seconds after loading the object
//載入物體5秒后銷毀游戲物體
Destroy (gameObject, 5);
// When the user presses Ctrl, it will remove the script
// named FooScript from the game object
//當按下Ctrl將從游戲物體刪除名為FooScript的腳本
function Update () {
if (Input.GetButton ("Fire1") && GetComponent (FooScript))
Destroy (GetComponent (FooScript));
}注意到Destroy函數能夠銷毀單獨的組件而不正確游戲對象本身產生影響,一個通常易犯的錯誤是Destroy(this); 這句代碼只銷毀腳本組件,而不銷毀該腳本所附加在的對象。
4. 協程(Coroutines)
一個coroutine就像一個能夠暫停運行並將控制權返回給Unity3D的函數,可是在下一幀的時候又能夠在它停止的位置繼續運行。在C#中,這樣聲明一個coroutine:
IEnumerator Fade() {
for (float f = 1f; f <= 0; f -= 0.1f) {
Color c = renderer.material.color;
c.alpha = f;
renderer.material.color = c;
yield return;
}
} 實質上它是一個返回類型為IEnumerator的函數,同一時候在函數體中添加了yield return這句代碼。yield return這行就是會在運行的時候暫停、在下一幀的時候恢復運行的位置。要啟動coroutine,須要使用StartCorutine函數。
void Update() {
if (Input.GetKeyDown("f")) {
StartCoroutine("Fade");
}
} 默認的情況下。一個coroutine在它暫停后的下一幀恢復,可是也能夠使用WaitFroSeconds來引入一個延時。
IEnumerator Fade() {
for (float f = 1f; f <= 0; f -= 0.1f) {
Color c = renderer.material.color;
c.alpha = f;
renderer.material.color = c;
yield return new WaitForSeconds(.1f);
}
}
這個能夠用於產生一個隨時間變化的效果,同一時候也是一個用於進行優化的有效方法。游戲中的很多人物須要周期性的運行。最經常使用的做法是將它們包括在Update函數中。可是Update函數通常每秒會調用多次。
當有的任務並不須要這么頻繁的被調用的時候,能夠將它放在一個coroutine中按一定時間進行調用,而不是每一幀都調用。
參考:http://game.ceeger.com/Script/
