# 總而言之大概整理一下Unity常用的一些或許需要的知識之類的 有關Unity的一些很基本的東西(目前大部分coding為主),因為作者很菜所以可能會有錯誤,如果有發現歡迎修正 ## Monobehavior底下的那些 #### Properties * gameObject 被當前script掛載的GameObject ``` csharp void Start() { Destroy(gameObject); } ``` #### Methods * void Start() 在一開始會被執行的部分放這,用來初始化 ``` csharp void Start() { rb2d = gameObject.GetComponent<Rigidbody2D>(); } ``` * void Updata() 這東西**每一禎**會呼叫一次,用它來處理需要一直做的事 ``` csharp void Update() { transform.position += Vector3.Left * speed; } ``` * void FixedUpdate() 每隔**一段固定時間**就會呼叫一次,官方推薦用來處理物理相關的部分 而這個間隔定義在Edit->ProjectSetting->time裡的Fixedtimestep ``` csharp void FixedUpdate() { rb2d.AddForce(Vector3.left); } ``` * void LateUpdate() 在所有Update之後被執行的函式,這裡的所有不限於當前腳本本身,包含其他遊戲中的物件 ``` csharp void LateUpdate() { Vector3 newPosition = transform.position; newPosition.z = -10; Camera.main.transform.position = newPosition; } ``` 另外,在同一個腳本底下三種Update是可以並存的 ## GameObject #### properties * tag 在Inspector底下可以設置的那個tag,是個string * transform 掛在物件底下的Transform,根據[官方文件](https://docs.unity3d.com/Manual/MobileOptimizationPracticalScriptingOptimizations.html),因為它並非單純的呼叫一個變數,最好避免在程式中大量呼叫,以免造成較大的負擔。 >Little known fact: all of the component accessors in MonoBehaviour, things like transform, renderer, and audio, are equivalent to their GetComponent(Transform) counterparts, and they are actually a bit slow. 所以當你在程式中需要時常存取此類物件時,較好的方式是建立一個快照(cache) * 較慢的寫法 ``` csharp void Update() { float step = speed * Time.deltaTime; Transform target = GameObject.FindWithTag("Player").transform; transform.position = Vector3.MoveTowards(transform.position, target, step); } ``` * 較有效率的寫法 ``` csharp private Transform mTransform; private Transform target; void Start() { mTransform = transform; target = GameObject.FindWithTag("Player").transform; } void Update() { float step = speed * Time.deltaTime; mTransform.position = Vector3.MoveTowards(mTransform.position, target, step); } ``` #### Methods * GetComponent 非常常見的一個函式,用來取得掛在GameObject底下的Component 有三種型式: ``` csharp Transform self = gameObject.GetComponent<Transform>(); Rigidbody2D rb2d = gameObject.GetComponent(typeof(Rigidbody2D)) as Rigidbody2D; Animator anim = gameObject.GetComponent("Animator") as Animator; ``` 三種結果都是一樣的,然而因為第一種寫起來比較短,所以我比較喜歡 * Destroy 摧毀一個"東西",在這裡可能是一個GameObject、Component或是其他繼承自UnityEngine.Object的Class,並且可以設定延遲,預設為零 ``` csharp void Start() { //destroy the game object after 10.086 seconds. Destroy(gameObject, 10.086f); } void Update() { if(Input.GetKeyDown(KeyCode.D)) { //destroy the game object Immediately. Destroy(gameObject); } } ``` * Instantiate 創建一個東西,可以產生的東西跟Destroy可以接受的型態一樣,並且可以在產生時指定位置及旋轉量,並且回傳此實例 ``` csharp public Rigidbody2D circle; void Update() { if(Input.GetMouseButtonDown(0)) { Vector3 spawnPosition = Camara.main.ScreenToWorldPoint(Input.mousepPsition); Rigidbody2D clone = Instantiate(circle, spawnPosition, Quaternion.identity); } } ``` ## Vector3 Vectoe3在Unity裡面算是一個蠻常用到的型別,裡面存著x y z三個數,型別為float,通常拿來表示一個座標或向量 * 建構子(constructor) ``` csharp //initialize a vector3 with (x, y, z) = (10, 10, 10) Vector3 v1 = new Vector3(10, 10, 10); //default z is 0 Vector3 v2 = new Vector3(10, 10); ``` * operator + 將兩個Vector3相加,相應的值會相加,就如同向量的加法一樣 ``` csharp Vector3 result = new Vector(1, 2, 3) + new Vector3(4, 5, 6); //the result should be (5, 7, 9) ``` * operator * 一個向量乘上一個數字 ``` csharp Vector3 result = new Vector3(1, 1, 1) * 55688; //result => (55688, 55688, 55688) ``` * static properties 一些預先定義好的向量,以下列舉幾個,詳細的請查[官方文件](https://docs.unity3d.com/ScriptReference/Vector3.html) * Vector3.zero => Vector3(0, 0, 0) * Vector3.one => Vector3(1, 1, 1) * Vector3.left => Vector3(1, 0, 0) * Vector3.up => Vector3(0, 0, 1) ## Transform Transform是Unity裡面最常見的一個component(大概),儲存了物件的座標(position)、旋轉量(rotation)、縮放量(scale)等等 #### Properties * position 一個Vector3,紀錄了當前物件的座標,不能直接改動回傳的Vector3裡的內容(見範例) ``` csharp //correct! transform.position += (Vector3.left * speed); //bubu~desuwa! you can't only modify the x! transform.position.x += speed; ``` * rotation 一個Quaternion,因為旋轉較複雜,先跳過,待日後補上。 #### Methods * void Rotate(Vector3 eulers) 按照z x y的順序旋轉物件,大部分時候沒什麼問題。 ``` csharp transfrom.Rotate(Vector3.left * Time.deltaTime); ``` ## Rigidbody2D 剛體是Unity裡面做物理運算時不可或缺的component,裡面包含了物理運算所需的各種資訊 #### Properties * bodyType 影響剛體物理性質的一個值,通常在inspector裡面修改,官方建議不要在遊戲執行期間去修改他,會造成較大的效能開銷 bodyType共有三種: * RigidbodyType2D.Dynamic 預設值,總之就是很正常,沒啥特別的 * RigidbodyType2D.Kinematic 中文翻譯貌似叫"動力學"之類的,其不受各種力的影響,所以像是放在半空中或是使用AddForce之類的都不會影響它,但可以透過設置velocity來使它移動 另外,它的效能開銷比Dynamic要來的低 * RigidbodyType2D.Static 總之就是不會動,撞它也不會,給它速度也不行 當然,效能開銷最低的一種 * velocity 如同字面上的意思,就是速度,在Rigidbody2D下是個Vector2,而在Rigidbody下是Vecotr3 ``` csharp Rigidbody2D rb2d = gameObject.GetComponent<Rigidbody2D>(); rb2d.velocity = Vector2.left * 10; ``` #### Methods * void AddForce(Vector2 force) 總之就是施一個力,跟force一樣的力,可以拿來作人物移動之類的 ``` csharp //jump! rb2d.AddForce(Vector2.up * power); ``` ## Collider2D 除了剛體,還需要碰撞器才能產生碰撞,另外碰撞又分成兩種: * ##### 碰撞(Collision) 總之就是碰撞,沒什麼特別的,撞到之後該發生什麼就會發生什麼,不清楚的可以自己撞看看 * ##### 觸發(Trigger) 觸發比較特別,當相撞兩方至少其中一邊的collider底下的Is Trigger有被勾選便會發生,它會使得當前碰撞造成的物理影響失效,可以用來製造地形啥的 舉例來講,像是踏進冰鳥的R會扣血,但還是可以走過去,並不會被擋住 #### Functions Collider相關的函式可以分成三類:Enter、Stay、Exit,他們被呼叫的時機就如同字面上的意思,看以下範例: ``` csharp void OnCollisionEnter2D(Collision2D other) { if(other.collider.tag == "Enemy") { this.Damaged(); } } ``` 這就是一個簡單的碰撞判定,判斷撞到的是不是敵人,是的話就扣血 如果是Trigger的話,要把上面的Collision換成Trigger,另外還有參數,Trigger的參數型別是Collider2D,跟碰撞並不一樣 ## Animator Animator是Unity裡面控制動畫的一個Component,內容表示為一個狀態機,並且可以攜帶參數,目前Unity支援的參數型別有int、float、bool跟trigger trigger本身的作用就像是一個按鈕,按下去之後會彈回來,用來取代某些時候bool設定為true後需要馬上改成false的場合,詳見範例 #### State #### Transition #### Methods * 參數相關 控制Animator大部分時候就是透過調整它的參數,可以透過Animator底下的函式完成,get系列只接受一個參數,Animator參數的名字,或是它的id,需要注意的是沒有GetTrigger,set的話除了名字,後面還要傳入要修改的值,當然Trigger是例外,它只需要一個參數,它的名字 ``` csharp Animator anim; void Start() { anim = gameObject.GetComponent<Animator>(); } void Update() { if(Input.GetKey(KeyCode.Space)) { anim.SetTrigger("Jump"); } } ``` ## 參考連結 [Unity scripting reference](https://docs.unity3d.com/ScriptReference/index.html) [Unity碰撞器(Collider)与触发器(Trigger)](http://gad.qq.com/article/detail/39479) [Unity性能优化——Rigidbody2D详解](https://blog.csdn.net/SerenaHaven/article/details/78851089)