# Unity入門
---
# 開發環境
----
# 遊戲引擎
----
遊戲引擎可被簡單敘述為「一些已編寫好的可編輯電腦遊戲系統或者一些互交式實時圖像應用程式的核心組件」。但其實概觀一點的來看,遊戲引擎就是一個程式庫,負責幫助團隊處理所有遊戲開發相關的事宜。
----
## Rpg Maker
最簡易上手的遊戲引擎之一,基本上不用撰寫什麼程式碼,用內建的事件就可以做出遊戲,美術素材不論是動畫、人物、地圖都有,不過缺點就是太多東西被寫死,如果想要用這引擎做出RPG以外類型的遊戲會很困難。
----
## Unity
Unity是由Unity Technologies研發的跨平台2D/3D遊戲引擎,可跨平台開發。除可以用於研發電子遊戲之外,Unity還廣泛用作建築視覺化、即時三維動畫等類型互動內容的綜合型創作工具。
使用C#進行遊戲開發,開發者社群活躍,資源商店有不少寶可以挖。
----
## Unreal
虛幻引擎有著古老的歷史,做為一個3A遊戲引擎,在3D畫面呈現上毫無疑問在Unity之上。
使用C++進行遊戲開發,入門相對Unity較為困難,開發週期較為漫長,加上對2D的不支援,以及開發者社群和資源商店的規模較小的緣故,所以本次教程不會使用。
----
# C#簡介
C#是微軟推出的一種基於.NET框架的、物件導向的進階程式語言。
自2017年Unity廢除掉JavaScript後,為用來編寫Unity的主要語言。
----
## Visual Studio
Microsoft Visual Studio(視覺工作室,簡稱VS或MSVS)是微軟公司的開發工具套件系列產品。VS是一個基本完整的開發工具集,它包括了整個軟體生命週期中所需要的大部分工具,如UML工具、程式碼管控工具、整合開發環境(IDE)等等。
----
如果嫌預設會安裝的Visual Studio 2019太胖了的話,可以考慮使用VSCode,可參考[此篇文章](https://tedliou.com/archives/vs-code-for-unity-setup/)進行安裝使用。
----
# Unity下載
[Unity版本 2019.4.9f1 LTS下載 ](https://unity3d.com/unity/qa/lts-releases?_ga=2.37425065.848543940.1599638662-1872926875.1576549933)

----
# 學生專案申請
厭倦Unity免費版,每7天一次的授權更新了嗎,可參考[此篇文章](https://ishengplab.dev/unity-student/)並去官網用學生信箱申請1年份的Unity Pro。
---
# 介面介紹
----
### Unity 操作介面
Unity 編輯器的操作介面是由多個不同功能的視窗組成,使用者可以調整視窗的大小與位置。

----
### Toolbar 工具列
Unity 編輯器的最上方是工具列,提供移動、旋轉、縮放物件的編輯工具。
Transform Tools 變形工具 移動 ( W )、旋轉 ( E )、縮放 ( R )
Transform Gizmo Toggles 切換物件使用自身座標或世界座標
Play / Pause / Step Buttons 遊戲檢視的執行、暫停、單格前進按鈕

----
### Project視窗
每個 Unity 遊戲專案的檔案都是儲存在一個專案資料夾,您可以從 Project View 專案視窗瀏覽專案資料夾的內容。
----
您可以為遊戲專案建立場景 ( Scenes )、預製物件 ( Prefabs )、行為腳本 ( Scripts ) ,或是匯入模型 ( 3D Models )、紋理 ( Textures )、音效 ( Audio ),並使用 Unity 的專案視窗來進行管理。若需要將資源加入目前的遊戲專案,可點選功能表 [ Assets > Import New Asset ] 並選擇檔案,或是使用滑鼠將檔案拖曳到 Project View 專案視窗。

----
### Scene視窗
主要工作區是的場景視窗,可以編輯地形或是加入各種遊戲物件,例如玩家角色、燈光、攝影機、粒子系統。

----
### Hierarchy視窗
顯示目前場景的物件與其階層關係,需要在物件附加元件或腳本時,可直接拖曳到階層面板的遊戲物件。
階層視窗中以藍色顯示名稱的遊戲物件是「預製物件」,而以灰色標示的遊戲物件則是暫時關閉的物件。

----
### Inspector視窗
Unity 畫面右側的屬性編輯器用於設定遊戲物件的屬性(物件名稱、座標位置、旋轉角度、縮放比例等),是否為靜態物件(用於計算燈光貼圖)。
此外,若是物件已附加燈光、攝影機、碰撞器、程式腳本等元件,也可透過 Inspector 屬性編輯器修改各項參數。

----
### Game視窗
遊戲視窗可用於遊戲的執行測試,點選右上方的 Stats 按鈕即可顯示 Statistics 半透明視窗,檢視 Draw Calls 數量、模型面數、材質貼圖的記憶體用量。

----
### Console視窗
用來除錯以及Debug。
接受Debug.Log以及print兩種輸出方式。


---
# 腳本寫法
----
### 1.在Project視窗右鍵創建一個C# Script

----
### 2.在Hierarchy視窗選定你要的物件

----
### 3.將腳本拖入Inspector視窗 即可運作

---
# [匯入素材](https://drive.google.com/file/d/19Uoj-1opL0eLu9kAVBh54Q8A81K7DE_U/view?usp=sharing)
----
### 步驟1:
#### 在Project視窗按右鍵選擇Show in Explorer

----
### 步驟2:
#### 將檔案全部解壓縮到Asset文件夾裡面

----
#### 即可在Project視窗中使用這些素材

---
# 基礎方法
----
## 當此class(類)繼承於monobehaviour時,可以調用以下函式
----
### void Start()
此函式將在物件生成時執行一次。
```csharp=
void Start()
{
print("peko!");//此物件生成時 會輸出訊息peko至控制台中
}
```
----
### void Awake()
基本同Start(),只是優先於Start()執行。
----
### void Update()
```csharp=
void Update()
{
Move(); //將會不斷調用Move這個方法
}
```
每幀逐幀執行,基於電腦效能不同可能速度會不一致
----
### void FixedUpdate()
```csharp=
void FixedUpdate()
{
Move(); //以固定速度調用Move這個方法
}
```
同Update(),但是會固定速度去執行。
---
### 讀取按鍵
----
1. KeyDown: 按下該按鍵的當下會執行一次。
```csharp=
if (Input.GetKeyDown (KeyCode.W))
{
Debug.Log("您按下了W鍵");
}
```
----
2. KeyUp: 按下該按鍵後鬆手,按鍵彈起來後觸發。`
```csharp=
if (Input.GetKeyUp (KeyCode.W))
{
Debug.Log("您擡起了W鍵");
}
```
----
3. Key: 一直按著就會不斷返回true來執行。
```csharp=
if (Input.GetKey(KeyCode.A))
{
Debug.Log("你按著A鍵不放");
}
```
---
## 物體位移
----
## Transform
Transform儲存其位置相關訊息,也包含其父子關係。
----
### position位置
Unity想要調用位置訊息的話需用Vector3來進行存取。
2D的話也可以使用Vector2。
----
獲取自身的世界座標
```csharp=
transform.position
```
修改
```csharp=
transform.position = new Vector3(0,0,0);
//將自身位置改到世界座標(0,0,0)
```
----
### scale修改大小
```csharp=
transform.loclaScale(向量);
```
----
### 旋轉
旋轉比較特別,單位不是向量,而是歐拉角度,具體應用如下:
```csharp=
transform.rotation = Quaternion.Euler(向量);
```
----
### 父子物件關係
在視窗中,當把一個物件拖到另一個物件之中,它就會成為其的子物件。
而視窗中子物件的位置也將從世界座標改為本地座標。
本地座標就是相對於父物件世界座標的位置。
本地座標(0,0,0)就是跟父物件一樣的位置。
----
修改自己的父物件
```csharp=
transform.parent = 父物件.transform;
```
獲取自己的子物件
```csharp=
transform.GetChild(0);//獲取排在其下的第一個子物件
```
----
### 一、向量相加減控制移動
```csharp=
transform.position += transform.up * speed;//往上方移動
transform.position += new Vector3(0,1) * speed;//往上方移動
transform.position -= transform.up * speed;//往下方移動
transform.position += transform.right * speed;//往右方移動
transform.position -= transform.right * speed;//往左方移動
```
----
### 二、移動至目標點
```csharp=
transform.position = Vector3.MoveTowards(transform.position, target, Time.deltaTime * speed);
```
----
### 三、剛體移動
```csharp=
public Rigibody2D rig;
void Start()
{
rig = GetComponent<Rigidbody2D>();//先獲取元件並存至變數裡
}
```
----
#### AddForce
使用AddForce時會受到物體質量影響
```csharp=
rig.AddForce (Vector3.right * speed);//往右移動
rig.AddForce (Vector3.right * -speed);//往左移動
rig.AddForce (Vector3.up * speed);//往上移動
rig.AddForce (Vector3.up * -speed);//往下移動
```
----
#### Velocity
修改Velocity時,會給物體一個向量值,這個值就是物體當下的速度
```csharp=
rig.velocity = new Vector2(0,speed);//往上移動
rig.velocity = new Vector2(0,-speed);//往下移動
rig.velocity = new Vector2(speed,0);//往右移動
rig.velocity = new Vector2(-speed,0);//往左移動
```
---
# 獲取元件
每一個在場景中的物件都是一個GameObject,
而每個GameObject可以添加各種元件。ex.碰撞盒...
在添加後如想要使用這些元件的功能,需要在腳本獲得他才可以去使用這些元件的方法
----
## 元件添加與獲取元件
### 添加

### 獲取
```csharp=
物件名稱.GetComponent<元件名稱>()
```
----
### 以剛體為例
```csharp=
gameObject.GetComponent<Rigbody2D>()
```
----
## 按下按鍵角色移動
----
```csharp=
public Rigibody2D rig;
void Start()
{
rig = GetComponent<Rigidbody2D>();
}
void Update()
{
if (Input.GetKey(KeyCode.W))
{
rig.velocity = new Vector2(0,speed);//往上移動
}
else if (Input.GetKey(KeyCode.S))
{
rig.velocity = new Vector2(0,,-speed);//往下移動
}
else if (Input.GetKey(KeyCode.A))
{
rig.velocity = new Vector2(-speed,0);//往左移動
}
else if (Input.GetKey(KeyCode.D))
{
rig.velocity = new Vector2(speed,0);//往右移動
}
}
```
---
# 動畫Animation與Animator
----
### Animation
----
#### 除了可以直接逐幀把圖片替換製作成逐幀動畫
#### 也可以進行形變、大小變換
----
#### 步驟1:
#### 如果預設沒有找到Animation視窗
#### 就點左上角選單的Window並選擇Animation
#### 將其叫出

----
#### 步驟2:
#### 在Inspector視窗加入元件

#### 搜尋並選擇Animator

----
#### 步驟3
#### 在Animation視窗創建相關動畫

----
#### 步驟4:
#### 按下左上角的小紅點即可開始錄製

----
#### 步驟5:
#### 按下錄製後
#### 將時間軸移到0:10左右的位置

----
#### 在Inspector視窗調整z軸的旋轉值至131.92
#### 這是動畫的起始點

----
#### 步驟6:
#### 將時間軸移到0:40左右的位置

----
#### 在Inspector視窗調整z軸的旋轉值至-135.3
#### 這是動畫的結束點

----
#### 有了起始點和結束點
#### 動畫就會自己漸變出中間的過程
#### 如此就完成了一個揮舞的動畫
----
#### 點此可新增動畫
#### 並請依照上述流程
#### 做一個反向揮舞(從右至左)的動畫

----
## Animator
----
#### 動畫的狀態機用來控管底下的Animation
#### 比如說人物可以會移動、跳、攻擊等等
#### 那麼Animator可以實現動畫邏輯
#### 判斷每個狀態應該用甚麼動畫
#### 這裡要來實作亞絲娜的克萊因連擊
----
#### 步驟1
#### 從Window/Animation/Animator叫出Animator視窗

----

----
#### 步驟2
#### 在左邊選擇Parameters(參數)
#### 按下+可以新增變數

----
#### 步驟3
#### 以攻擊為例
#### 在右邊區塊右鍵創建一個新的狀態

----
#### 命名為none
#### 對Entry右鍵選第二個
#### 將起始線連到none

----

----
#### 步驟4
#### 對none右鍵選第一個Make Transition
#### 將線連到我們做的兩個動畫(Animation)狀態

----
#### 步驟5
#### 同樣動畫部分也要回傳回來所以連成這樣

----
#### 步驟6
#### 點擊線段將值設定成如下
#### 其他幾個同理

----
#### 步驟7
#### 加入判斷如果Atk等於1的話
#### 則進入這個攻擊狀態

----
#### 反之
#### 不等於1的話則退出狀態

----
## 再來要寫程式碼控制
## 狀態機的參數Atk
----
## 腳本控制狀態機
狀態機邏輯部分雖然定好了
但是還需要寫程式去控制狀態機裡變數
繼續以Atk為例
----
```csharp=
Animator ani;
void Start()
{
ani = GetComponent<Animator>();
//獲得動畫元件並存在ani這個變數
AnimatorStateInfo stateinfo = ani.GetCurrentAnimatorStateInfo(0);
//獲得第0層的狀態機資訊 主要是要獲得動畫的時間軸的訊息
if(Input.GetKeyDown(KeyCode.A) && )
{
ani.SetInteger("Atk", 1);//將值寫入狀態機中
}
if(ani.GetInteger("Atk") == 1 && stateinfo.normalizedTime >= 1)
{//如果處於攻擊狀態且動畫播放完(normalizedTime的數值為0~1 指的是當前動畫播放到哪裡 0是還沒開是播放 0.5是播放到一半 1是播放完 )
ani.SetInteger("Atk", 0);
//攻擊完了 將攻擊狀態取消 狀態機就會回到原本的待機狀態
}
}
```
---
# 碰撞
----
### Rigibody剛體
要讓物件有重力及碰撞反應需要的就是剛體,剛體可以在選取物件後在inspect標籤或上方工具列的Component - Physics 裡加入。

----
### 碰撞盒
當兩個碰撞盒撞上,則其中必須要有一個有剛體才能觸發判斷。

當勾上isTrigger時,碰撞盒將不存在實體可以穿過其他碰撞盒,但還是可以觸發判斷。
----
### 碰撞判斷
#### 當2個碰撞盒中有一個勾選了isTrigger的話 請使用OnTrigger判斷式
----
1.OnTrigger判斷式
```csharp=
void OnTriggerEnter2D(Collider2D col)
{
//碰撞時調用一次
}
void OnTriggerStay2D(Collider2D col)
{
//碰撞時持續調用
}
void OnTriggerExit2D(Collider2D col)
{
//離開碰撞時調用
}
```
----
2.OnCollision判斷式
```csharp=
void OnCollisionEnter2D(Collision2D collision)
{
//碰撞時調用一次
}
void OnCollisionStay2D(Collision2D collision)
{
//碰撞時持續調用
}
void OnCollisionExit2D(Collision2D collision)
{
//離開碰撞時調用
}
```
----
#### 標籤
可使用Unity標籤來判斷碰撞到的物體是啥,例如:碰撞的對象是子彈,那麼就扣血
----
##### 腳本應用
```csharp=
int HP = 100;
void OnTriggerEnter2D(Collider2D col)
{
if (col.CompareTag("Bullet"))
{
HP -= 10;//當碰撞到子彈時,血量扣10
}
}
```
---
# 實作
---
# 生成和刪除
----
### GameObject
只要是在場景中被實例化出來的對象都是一個GameObject。
----
### 生成
```csharp=
Instantiate(物件, 位置,旋轉);
```
```csharp=
Instantiate(gameObject, transform.position,transform.rotation);
```
----
### 刪除
將此物件從場景中刪除。
```csharp=
Destroy(gameObject);//將自己刪掉
```
---
## 延伸閱讀
### [設計模式](https://gpp.tkchu.me/acknowledgements.html)
{"metaMigratedAt":"2023-06-15T20:23:33.411Z","metaMigratedFrom":"Content","title":"Unity入門","breaks":true,"contributors":"[{\"id\":\"faca3329-cc98-475b-ac42-c0a846116bf8\",\"add\":12184,\"del\":1474}]"}