# 總而言之大概整理一下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)