# Unity程式入門 --- # C#簡介 C#是微軟推出的一種基於.NET框架的、物件導向的進階程式語言。 自2017年Unity廢除掉JavaScript後,為用來編寫Unity的主要語言。 --- # 編譯器 ## Visual Studio Microsoft Visual Studio(視覺工作室,簡稱VS或MSVS)是微軟公司的開發工具套件系列產品。VS是一個基本完整的開發工具集,它包括了整個軟體生命週期中所需要的大部分工具,如UML工具、程式碼管控工具、整合開發環境(IDE)等等。所寫的目的碼適用於微軟支援的所有平台,包括Microsoft Windows、Windows Phone、Windows CE、.NET Framework、.NET Compact Framework和Microsoft Silverlight。 --- # Unity下載 [Unity版本 2019.4.9f1 LTS下載 ](https://unity3d.com/unity/qa/lts-releases?_ga=2.37425065.848543940.1599638662-1872926875.1576549933) ![](https://i.imgur.com/yzBkJpQ.png) --- # C#程式 ---- ## 宣告變數 `宣告 型別 變數名稱;` ```csharp= private float a;//宣告一個私有的浮點數(小數)變數 名稱為a protected bool b;//宣告一個被保護的布林變數 名稱為b public int c;//宣告一個公開的整數變數 名稱為c ``` 如果是宣告 `private float a = 0; ` 這邊的=是指往a這個容器塞入0這個數值,跟數學上的定義不太一樣 # ### 宣告部分 #### private 私有的,意指此變數只可被自己所讀取,無法被別的class(類別)存取 #### protected 被保護的,意指此變數只可被自己或繼承自己的子對象存取 #### public 公開的,意指此變數可被任意class(類別)存取,同時在Unity內可以直接從視窗修改其數值 # ### 型別 #### bool 只有true(真)和false(假)這2種值的型別,大小是1 byte #### int 最常用的整數型別,如果沒有特殊需求,要使用整數時,就會選擇這個型別 大小是4 bytes,範圍是 -2,147,483,648 到 2,147,483,647 之間 #### float 單精度浮點數 如果你使用Unity引擎,那麼這是你最常使用的浮點數型別。 大小是4 bytes,範圍是1.5 × 10-45 到 3.4 × 1038 之間,7 位數精確度 這邊特別提一下在C#,想要賦予的值為小數時,必須在數值後加上f。 範例: 先宣告一個名稱為F的浮點數 ``` public float F; ``` 錯誤用法: `F = 0.5;` 小數值後面未加f, ERROR編譯器報錯 正確為: `F = 0.5f;` 程式碼正常執行 #### double 雙精度浮點數 大小為8 bytes ,範圍為±5.0 × 10−324 至 ±1.7 × 10308 , 跟float不同,值為小數時,不用在數值後面加上f。 ``` pulbic double x = 0.0; ``` #### string 字串型別,string的大小是內容字元大小的總和 用來代表一串字元。使用雙引號來包裝以表示字串。 例如:”C8763!” #### var 這比較特別, 是讓Unity根據你後面下的值來自己填型別。 ```csharp= var i; //報錯 var一定要後面有值才可讓Unity判斷 var i = 0.5f;//此時i的型別為float var j = 5;//此時j的型別為int var k = false;//此時k的型別為bool ``` # 這邊只介紹比較常用的幾個型別,其他的型別請自行Google~~ ---- ## if條件式 ``` if(條件式) { 執行程式 } ``` 範例: ```csharp= public int input = 10; if(input == 10)//在c# "==" 才是兩者相等的意思 { input += 5; } ``` 當input這個變數為true時, 進入if(條件式結果為真){執行下面程式賦予input一個新的值false} ---- ## 迴圈 ### for ``` for (起始值; 條件式; 更新值) { 執行程式 } ``` 範例: ```csharp= for(int i=0; i<5; i++) { print(i);// 輸出i這個數值 } ``` 輸出結果為 ```01234``` ### while ``` while (條件式) { 執行程式 } ``` 範例: ```csharp= int i = 0; while(i<5) { print(i); i++; } ``` 輸出結果為 ```01234``` While很容易變無窮迴圈,尤其在Untiy執行耗的資源量比一般寫程式要來的大, 很可能會直接把記憶體全部吃爆,讓電腦死當,請小心謹慎 ### do while ``` do { 執行程式 } while (條件式); ``` 範例 ```csharp= int i = 0; do { print(i); i++; } while (i<0); ``` 輸出: ``` 0 ``` 基本上跟一般while一樣,差別在於是先執行,再來考量條件成不成立, 所以最少也會執行一次 ### foreach ``` foreach(宣告變數 in Array/List) { 依序讀取Array/List內的值 讀取所有的值後及跳出迴圈 } ``` 範例: ```csharp= int[] numArray = {11,13,15,17}; foreach(int a in numArray) { print(a+" "); } ``` 輸出結果: ``` 11 13 15 17 ``` 據說foreach在Unity使用這個會很浪費效能(?),總之慎用 ---- ## 陣列 一個連續的記憶體空間,可大量宣告變數,並用index(索引)來管理裡面的資料。 ### 靜態陣列 #### 範例: ```csharp= public int[] i;//宣告一個整數陣列i,然後未指定陣列長度(陣列大小) public int[] j = new int[5];//宣告一個整數陣列j,長度為5個 for (int k = 0; k < j.Length ;k++) //陣列名稱.Length 為獲取陣列長度 { j[k] = k; print(j[k] + " "); } ``` 輸出: ``` 0 1 2 3 4 ``` 同時 ```csharp= j[0]的值為0 j[1]的值為1 j[2]的值為2 j[3]的值為3 j[4]的值為4 ``` ### 動態陣列 #### 宣告 ``` public List<int> L = new List<int>(); ``` #### 範例 ```csharp= public List<int> L = new List<int>(); L.Add(5);//此時L增加了一個空間L[0] 並且L[0]的值為5 L.Add(10);//此時L增加了一個空間L[1] 並且L[1]的值為10 print(L.Count);//Count可獲得目前所有元素的數量,現在裡面有2個元素,則輸出結果為2 L.Remove(0);//移除掉L[0]的空間,而後面的L[1]會自動往上遞補移到L[0]的位置 print(L[0]);//輸出值為10 L.Clear();//清空整個陣列 移除掉所有的元素 ``` ---- ## 方法 ### 宣告: ``` 傳回值 方法名稱(參數)//void為無傳回值 { 程式執行 } ``` ### 範例: ```csharp= public class 主程式() : MonoBehaviour { int Test(int a,int b) { return a + b; } void Start() { print(Test(1,3)+"");//隱含轉換 } } ``` ### 輸出結果 `4` ---- ## 物件導向 ### 封裝 ### 繼承 ### 多型 --- # Unity相關 ---- ## 介面介紹 ### Unity 操作介面 Unity 編輯器的操作介面是由多個不同功能的視窗組成,使用者可以調整視窗的大小與位置。 ![](https://i.imgur.com/IdtoBte.png) ### Toolbar 工具列 Unity 編輯器的最上方是工具列,提供移動、旋轉、縮放物件的編輯工具。 Transform Tools 變形工具 移動 ( W )、旋轉 ( E )、縮放 ( R ) Transform Gizmo Toggles 切換物件使用自身座標或世界座標 Play / Pause / Step Buttons 遊戲檢視的執行、暫停、單格前進按鈕 ![](https://i.imgur.com/asl5zvZ.png) ### Project視窗 每個 Unity 遊戲專案的檔案都是儲存在一個專案資料夾,您可以從 Project View 專案視窗瀏覽專案資料夾的內容。 您可以為遊戲專案建立場景 ( Scenes )、預製物件 ( Prefabs )、行為腳本 ( Scripts ) ,或是匯入模型 ( 3D Models )、紋理 ( Textures )、音效 ( Audio ),並使用 Unity 的專案視窗來進行管理。若需要將資源加入目前的遊戲專案,可點選功能表 [ Assets > Import New Asset ] 並選擇檔案,或是使用滑鼠將檔案拖曳到 Project View 專案視窗。 ![](https://i.imgur.com/vxOoU06.png) ### Scene視窗 主要工作區是的場景視窗,可以編輯地形或是加入各種遊戲物件,例如玩家角色、燈光、攝影機、粒子系統。 ![](https://i.imgur.com/4KJp8RM.png) ### Hierarchy視窗 顯示目前場景的物件與其階層關係,需要在物件附加元件或腳本時,可直接拖曳到階層面板的遊戲物件。 階層視窗中以藍色顯示名稱的遊戲物件是「預製物件」,而以灰色標示的遊戲物件則是暫時關閉的物件。 ![](https://i.imgur.com/cpZ6jDK.png) ### Inspector視窗 Unity 畫面右側的屬性編輯器用於設定遊戲物件的屬性(物件名稱、座標位置、旋轉角度、縮放比例等),是否為靜態物件(用於計算燈光貼圖)。 此外,若是物件已附加燈光、攝影機、碰撞器、程式腳本等元件,也可透過 Inspector 屬性編輯器修改各項參數。 ![](https://i.imgur.com/6R27Dl8.png) ### Game視窗 遊戲視窗可用於遊戲的執行測試,點選右上方的 Stats 按鈕即可顯示 Statistics 半透明視窗,檢視 Draw Calls 數量、模型面數、材質貼圖的記憶體用量。 ![](https://i.imgur.com/ilgLvJC.png) ### Console視窗 用來除錯以及Debug。 接受Debug.Log以及print兩種輸出方式。 ![](https://i.imgur.com/ofCCPPc.png) ![](https://i.imgur.com/59txKbB.png) ---- ## 基礎方法: 當此class(類)繼承於monobehaviour時,可以調用以下函式 ### void Start() 此函式將在物件生成時執行一次。 ``` void Start() { print("姆咪姆咪蹦蹦跳!");//此物件生成時 會輸出訊息姆咪姆咪蹦蹦跳至控制台中 } ``` ### void Awake() 基本同Start(),只是優先於Start()執行。 ### void Update() ``` void Update() { Move(); //將會不斷調用Move這個函式 } ``` 每幀逐幀執行,基於電腦效能不同可能速度會不一致,請千萬不要在這裡面用while(true)... ### void FixedUpdate() 同Update(),但是會固定速度去執行。 ---- ## GameObject 只要是在場景中被實例化出來的對象都是一個GameObject。 ### 生成 ``` Instantiate(物件, 位置,旋轉); ``` ``` Instantiate(gameObject, transform.position,transform.rotation); ``` #### 預置物(Prefab) ###### 將Hierarchy視窗裡的物件拖曳到Project視窗,即可視為創建預置物(Prefab),預置物可以從腳本中動態生成。 ##### 1. 直接拖曳 * 在腳本裡宣告公開變數,之後直接從Project視窗拖曳至腳本上。 ![](https://i.imgur.com/5cq2QqU.png) ![](https://i.imgur.com/wq2sxp6.png) * 之後自由生成吧。 ``` Instantiate(Obj, transform.position,transform.rotation); ``` ##### 2. Resources方法 創建一個名為Resources的資料夾在Project的最外層即可使用。 ``` Resources.Load<資料型態>(資料位置); ``` 生成: ``` //如果是物件的話: GameObject Obj = Resources.Load<資料型態>(資料位置); Instantiate(Obj, transform.position,transform.rotation); ``` 範例: ##### 3. AssetBundle:暫不做介紹。 ### 刪除 將此物件從場景中刪除。 ``` Destroy(gameObject); ``` ### 隱藏、顯示 將此物件從場景中隱藏。 ``` gameObject.SetActive(false);//隱藏 gameObject.SetActive(true);//顯示 ``` ---- ## Transform Transform儲存其位置相關訊息,也包含其父子關係。 ### position位置 Unity想要調用位置訊息的話需用Vector3來進行存取。 2D的話也可以使用Vector2。 獲取自身的世界座標 ``` transform.position ``` 修改 ``` transform.position = new Vector3(0,0,0); //將自身位置改到世界座標(0,0,0) ``` ### scale修改大小 ``` transform.loclaScale(向量); ``` ### 旋轉 旋轉比較特別,單位不是向量,而是歐拉角度,具體應用如下: ``` transform.rotation = Quaternion.Euler(向量); ``` ### 父子物件關係 在視窗中,當把一個物件拖到另一個物件之中,它就會成為其的子物件。 而視窗中子物件的位置也將從世界座標改為本地座標。 本地座標就是相對於父物件世界座標的位置。 本地座標(0,0,0)就是跟父物件一樣的位置。 修改自己的父物件 ``` transform.parent = 父物件.transform; ``` 獲取自己的子物件 ``` transform.GetChild(0);//獲取排在其下的第一個子物件 ``` #### Find方法 抓取物件 效率低蠻耗資源的做法,可以在場景中依據物件名字去搜尋出來。 除此之外,能搜尋到的只限於沒有被隱藏的的物件。 建議只用在Start()中獲取再存在變數裡面,以便之後調用。 ``` GameObject.Find("場景中的物件名稱"); ``` ---- ## 元件添加與獲取元件 ### 添加 ![](https://i.imgur.com/9XxH4gn.png) ### 獲取 ``` 物件名稱.GetComponent<元件名稱> ( ) .參數名稱 ``` ---- ## 讀取鍵盤輸入 ### 讀取按鍵 1. KeyDown: 按下該按鍵的當下會執行一次。 ``` if (Input.GetKeyDown (KeyCode.W)) { Debug.Log("您按下了W鍵"); } ``` 2. KeyUp: 按下該按鍵後鬆手,按鍵彈起來後觸發。` ``` if (Input.GetKeyUp (KeyCode.W)) { Debug.Log("您擡起了W鍵"); } ``` 3. Key: 一直按著就會不斷返回true來執行。 ``` if (Input.GetKey (KeyCode.A)) { Debug.Log("AAAAA"); } ``` ### Unity內建 1. Edit/Project Setting ![](https://i.imgur.com/QymjRSf.png) ![](https://i.imgur.com/DMBnHd1.png) 2. 使用GetAxis可讀取列於Input Manager上的值 ``` float Hor = Input.GetAxis("Horizontal"); float Ver = Input.GetAxis("Vertical"); //讀取到的值為-1~1 //以Horizontal為例 0為沒按 -1為按下了往左鍵 1為按下往右鍵 ``` ---- ## Rigibody剛體跟碰撞 ### Rigibody剛體 要讓物件有重力及碰撞反應需要的就是剛體,剛體可以在選取物件後在inspect標籤或上方工具列的Component - Physics 裡加入。 ![](https://i.imgur.com/DxIZQn1.png) ### 碰撞盒 當兩個碰撞盒撞上,則其中必須要有一個有剛體才能觸發判斷。 ![](https://i.imgur.com/1yphiED.png) 當勾上isTrigger時,碰撞盒將不存在實體可以穿過其他碰撞盒,但還是可以觸發判斷。 ### 碰撞判斷 #### 當2個碰撞盒中有一個勾選了isTrigger的話 請使用OnTrigger判斷式 1.OnTrigger判斷式 ``` void OnTriggerEnter2D(Collider2D col) { //碰撞時調用一次 } void OnTriggerStay2D(Collider2D col) { //碰撞時持續調用 } void OnTriggerExit2D(Collider2D col) { //離開碰撞時調用 } ``` 2.OnCollision判斷式 ``` void OnCollisionEnter2D(Collision2D collision) { //碰撞時調用一次 } void OnCollisionStay2D(Collision2D collision) { //碰撞時持續調用 } void OnCollisionExit2D(Collision2D collision) { //離開碰撞時調用 } ``` #### 標籤 可使用Unity標籤來判斷碰撞到的物體是啥,例如:碰撞的對象是子彈,那麼就扣血 ##### 1.設置標籤 ![](https://i.imgur.com/k53Z4Pa.png) ##### 2.腳本應用 ``` int HP = 100; void OnTriggerEnter2D(Collider2D col) { if (col.CompareTag("Bullet")) { HP -= 10;//當碰撞到子彈時,血量扣10 } } ``` ---- ## 移動 ### 一、向量相加減控制移動 ``` transform.position += transform.up * Time.deltaTime*5f;//往上方移動 ``` ### 二、Translate控制移動 ``` transform.Translate(Vector3.up * Time.deltaTime*5f); //往上方移動 ``` ### 三、MoveTowards移動至目標點 ``` transform.position = Vector3.MoveTowards(transform.position, 目標點, Time.deltaTime*速度); ``` ### 四、剛體移動 ``` public Rigibody Rig; void Start() { Rig = GetComponent<Rigidbody2D>();//先獲取元件並存至變數裡 } ``` 先獲取元件... #### AddForce 使用AddForce時會受到物體質量影響 ``` Rig.AddForce (Vector3.right * 10);//往右移動 ``` #### Velocity 修改Velocity時,會給物體一個向量值,這個值就是物體當下的速度 ``` Rig.velocity = new Vector2(0,10);//往上移動 Rig.velocity = new Vector2(0,-10);//往下移動 Rig.velocity = new Vector2(10,0);//往右移動 Rig.velocity = new Vector2(-10,0);//往左移動 ``` ---- ## 計時器與協程 ### 使用Time.deltaTime 一秒內從第1個Frame到最後一個Frame所花的時間, 所以不管電腦是一秒跑60格或者一秒30格、24格,值都會趨近於一。 就結果而言,deltaTime是為了遊戲「公平性」而產生的東西, 因此最常用於位移(translate),但拿來計時也是勉強可以用。 ``` void Update() { float ti += Time.deltaTime;// if(ti >= 3) { print("每三秒計一次時"); ti = 0; } } ``` ### StartCoroutine協程 啟動一個「協程」。 協程簡言之就是執行一個可繼續、可中斷的函式, 所以我可以告訴程式我要隔幾秒在執行下一行陳述式, 因此可以拿來當做計時器。 載入場景時,會把資源都花在讀取上,場景畫面會卡住。 此時也可以用協程來做些Loading動畫。 ``` IEnumerator Clock() { while(true) { yield return new WaitForSecondsRealtime(5); print("每5秒執行一次"); } } void Start() { StartCoroutine(Clock());//必須用此函式才有辦法呼叫協程 不然不會呼叫 } ``` 直接將協程放在Update不優,會大量產生Clock協程,產生不可預期之結果。 ### InvokeRepeating 調用一個方法/秒 。 InvokeRepeating接受三個參數,第一個是方法名,第二個是「第一次調用」要隔幾秒,第三個則是「每隔幾秒調用一次」,與StartCoroutine一樣,是可以中斷的,只要使用CancelInvoke()。 ``` void Clock() { print("每秒調用"); } void Start() { InvokeRepeating("Clock",1f,1f); } ``` ### Time.time 從遊戲開始到現在所使用的時間。 ---- --- # Unity好用插件推薦 ---- ## DoTween 可用程式直接生成各種關於位移、更改顏色等的動畫。 ---- ---
{"metaMigratedAt":"2023-06-15T12:52:52.952Z","metaMigratedFrom":"Content","title":"Unity程式入門","breaks":true,"contributors":"[{\"id\":\"faca3329-cc98-475b-ac42-c0a846116bf8\",\"add\":11954,\"del\":1269}]"}
    656 views