--- title: 'Unity從入門到放棄 2D遊戲完整課程' --- Unity從入門到放棄 2D遊戲完整課程 === [TOC] # 課程目前程式碼 ```Csharp using System.Collections; using System.Collections.Generic; using UnityEngine; public class players : MonoBehaviour { Transform m_transform; Rigidbody2D m_rigidbody; float velocity_y = 0; public float max_velocity_y = 15; public float cat = 15; public float cat1 = 15; public float cat2= 15; void Start() { m_transform = gameObject.GetComponent<Transform>(); m_rigidbody = gameObject.GetComponent<Rigidbody2D>(); } // Update is called once per frame void Update() { float velocity_x = 0; velocity_y = m_rigidbody.velocity.y; if (Input.GetKey(KeyCode.D)) { velocity_x = 10; } else if(Input.GetKey(KeyCode.A)) { velocity_x = -10; } if (Input.GetKey(KeyCode.W) && velocity_y > -0.001 && velocity_y < 0.001) { velocity_y = max_velocity_y; } else { velocity_y -= 0.1f; } m_rigidbody.velocity = new Vector3(velocity_x, velocity_y, 0f); //將數值轉為Vector3形式並存入m_rigidbody.velocity } } ``` # ==課程前言== 哈喽~大家好我是Ray~也是本次課程的講師 這是Unity2D課程的教學 課程設計從完全基礎到能做出橫向移動 這次課程會教導有關物件導向基礎概念與Unity基礎語法 並且在本次課程中會帶領大家開發出一個可以被鍵盤控制移動 移動時會有移動動畫的人物 並進一步講述偵測系統的製作 本網站是根據學習進度進行編寫 你可以根據個人的能力跳過不必要的章節 ## C#語法 這堂課是授課給有基礎程式基礎的人 但教學盡量不會涉及到太多程式碼教學 否則我怕死一片 # ==Unity操作== ## Unity基本操作 **我時間不太夠QQ,詳細操作看我ㄉ實際演示** ![](https://i.imgur.com/ejAcvRz.png) ## 引入圖片 ![](https://i.imgur.com/hhKzrFk.png) ## 新建角色 ![](https://i.imgur.com/v2B43q4.png) ## 物理與碰撞 ![](https://i.imgur.com/wjToSKq.png) ## UI介面 ![](https://i.imgur.com/U7eyFn7.png) # ==程式領域== ## 新建腳本 在上一堂課當中,我們了解如何進行Unity的基本操作並且成功新增了角色 在遊戲中 這堂課我將教導如何撰寫C#腳本來控制角色 **新增腳本方式** 1.點選欲新增腳色 ![](https://i.imgur.com/aDHv8ve.png) 2.點擊角色右邊的Inspector下方的Add Component ![](https://i.imgur.com/q48Mvjl.png) 3.找到New script 並輸入腳本名稱 ![](https://i.imgur.com/4qSFZhi.png) 4.點擊Create and Add 便可以看到我們新建的腳本了喔 這個腳本會被放置在專案的Assets資料夾中 從Unity連點兩下可以透過Visual Studio開啟 ## 基礎框架 打開我們剛剛新建的腳本,裏頭Unity會幫我們先生成好基礎框架 範例程式說明 程式會逐漸拆解 ```csharp= using System.Collections; using System.Collections.Generic; using UnityEngine; public class test : MonoBehaviour { // Start is called before the first frame update void Start() { } // Update is called once per frame void Update() { } } ``` <br> ------------------------------------------------- <br> ### Start() 和 Update() ```csharp= void Start() { } void Update() { } ``` Start()是Unity的默認function 當遊戲一開始的時執行裡頭程式 Update()是每一fps執行一次 (不穩定 畢竟妳的fps不會永遠保持在60 她會浮動) ### (高階補充)Using語法 *屬於程式知識補充,建議閱讀* 由於Unity包含了非常多的功能,不過並不是任何功能我們功能都會用到 第一行到第三行的```using```便是在這種環境下問世而生的 我們可以告訴系統要**使用**什麼樣的內建程式功能 ::: info 各語言相似功能語法 C++ or C ```cpp= #include <iostream> using namespace std; ``` Java ```java= import java.util.Scanner; ``` python ```python= from abc import cde ``` ::: ### (高級補充)物件導向 *這邊的難度比較高,也是屬於資工純領域的部分,可以選擇性跳過* ```csharp= public class test : MonoBehaviour ``` 她的功能是宣告一個 名稱為 **test** 的公開類別 而且該類別繼承了**MonoBehaviour** 的功能 類別?繼承?功能? WHAT IS THIS?!!!!! 向下是物件導向的相關介紹(這個介紹是給新手快速入門用 用詞較通俗且可能偏離原義) ::: info 物件導向是程式設計的**方式** 有別於初學者常使用的**指令導向** 物件導向將程式包裝成了如同人與人的交流一般 大家都是人 但是人與人之間都會有相異之處 或類似之處 像是我跟妳都有存款 但是我的存款可能只剩100 妳還有5000 妳跟我可能都會騎車 我會寫程式 但妳可能不會 聽不懂?上實際例子 假設我要開發一個系統 可以記錄100人的存款 然後用兩個function實踐 存款跟提款 某個人的指定金額 **常規的指令導向** ```csharp= int individualMoney[100]; //以陣列宣告100個的存款數目 void Withdrawal(int who, int howMuchMoney){ //存款 individualMoney[who] += howMuchMoney; //將金額直接加入該存款裡 } void Deposit(int who, int howMuchMoney){ //提款 if(individualMoney[who] >= howMuchMoney){ //如果她的存款大於提款金額 individualMoney[who] -= howMuchMoney; //進行提款 } } ``` **物件導向**(詳細說明請向下看) ```csharp= class People{ private int Money; public People(int InitMoney){ this.Money = InitMoney; } public void Withdrawal(int howMuchMoney){ //存款 this.Money += howMuchMoney; //將金額直接加入該存款裡 } public void Deposit(int howMuchMoney){ //提款 if(this.Money >= howMuchMoney){ //如果她的存款大於提款金額 this.Money -= howMuchMoney; //進行提款 } } } People[] people = new People[100]; //宣告100個使用People模板的變數名叫people //People[] 表示接下來宣告的東西是個陣列 //People[100] 表示宣告陣列為長度100 值得一提的是這裡只是告知長度 還沒使用建構函數 完全建立 for(int i = 0;i < people.Lengh; i ++){ people[i] = new People(0); } //利用for迴圈 讓每一個people都啟動其建構函數 ``` 第一行的```class People```是什麼呢? 剛剛提到大家都是**人** class存在的意義就如同**模板** 模板會將所有有關人的參數定下來 而第二行的int Money便是說明每個人都會有各自的存款 第八行與第十二行便是人都共同會做的事情(function) 第四行看起來非常特別,看起來很function卻少了回傳型態的宣告(像是void表示不回傳 int表示回傳int) 這是建構function 故名思義,這個function僅會在模板把人給打模出來的瞬間被使用 並且不會回傳數值(建構function默認就是不會回傳數值的) 第十九行的 ```csharp= People people[100] = new People(0); for(int i = 0;i < people.Lengh; i ++){ people[i] = new People(0); } ``` 可以理解成這樣 ```csharp= 使用People模板而且是建立陣列 該變數名稱為people = new 宣告陣列長度為100 利用for迴圈 讓每一個people都啟動其建構函數 ``` this.Money 中的this.又表示什麼呢? 因為單純寫Money有個問題就是你可能會在其他地方也宣告同名為Money的變數 this.Money 代表的意思是我自己的Money變數 很好?那為何每一個function最前面都有一個public呢? 甚至連變數Money前面也有private public代表任何人都可以使用我的function 或者讀取該數值 與之相對的是private private代表只有我自己能使用該function 或者讀取該數值 還是看不懂嗎?我現在加上完整註解 ```csharp= class People{ //宣告一個名為People的模板 private int Money; //這個模板中定義一個數值叫做people 只有我自己的function能讀取或修改這個數值 public People(int InitMoney){ //建構函數 當有個變數被這個模板打印時啟動該function this.Money = InitMoney; //將"我自己"的Money變數變成傳入數值 } public void Withdrawal(int howMuchMoney){ //這是一個任何人都能使用的function 目的是存款 this.Money += howMuchMoney; //將金額直接加入該存款裡 } public void Deposit(int howMuchMoney){ //這是一個任何人都能使用的function 目的是提款 if(this.Money >= howMuchMoney){ //如果她的存款大於提款金額 this.Money -= howMuchMoney; //進行提款 } } } People people[100] = new People(0); 使用People模板 打印100個變數名稱為people的變數 = new 打印時同時激活People模板裏頭的建構函數並且傳數值0進入 ``` ::: 說完最基礎的物件導向與類別概念 該是來提到繼承的概念ㄌ ::: info 假設Ray跟Robeca都是人 但是我會寫程式她不會 她會彈琴我不會 但是我們都會走路 我便會使用繼承概念來開發 繼承便是有兩個模板 一個父模板跟子模板 繼承的話子模板會完全獲得父模板的能力 子模板也可以根據自己的需求再做宣告 like this ```csharp= class People{//宣告一個名為People的模板 void wake(){ //走路 } } class Ray : People{//宣告一個名為Ray的模板 並且繼承People模板的一切能力 void code(){ //寫程式 } } class Shane : People{//宣告一個名為Shane的模板 並且繼承People模板的一切能力 void piane(){ //彈琴 } } ``` 上面的寫法功能會等於下面的寫法 ```csharp= class Ray{//宣告一個名為Ray的模板 void code(){ //寫程式 } void wake(){ //走路 } } class Shane{//宣告一個名為Shane的模板 void piane(){ //彈琴 } void wake(){ //走路 } } ``` 這便是繼承 使其他物件擁有我的一切屬性 ::: 我們回到 ```csharp= public class test : MonoBehaviour ``` 便是宣告一個公開可被其他人讀取得class 名稱為test 並且繼承了MonoBehaviour的功能 值得一提的是MonoBehaviour是Unity幫妳寫好的程式庫 使其能使用許多Unity的程式功能 <br> ---------------------------------------- <br> ## 按鍵偵測與人物移動 ```csharp= using System.Collections; using System.Collections.Generic; using UnityEngine; public class test : MonoBehaviour{ Transform m_transform; //Transform是Unity內建的class 她記錄著玩家的座標 可以透過更改Transform.position更改我的位置 Rigidbody2D m_rigidbody; //Rigidbody是Unity內建的物理系統 , Rigidbody2D.velocity 能更改玩家移動速度 float velocity_x, velocity_y; //宣告變數來告訴系統 我的移動速度應該是多少((見Update() void Start() { m_transform = gameObject.GetComponent<Transform>(); //雖然第七行把m_transform宣告出來 但是系統並不會知道這個Transform是屬於誰的座標 //gameObject默認代表我自己 .GetComponent表示取得我自己的<Transform>物件 這樣便能告訴系統m_transform是我自己的Transform物件 m_rigidbody = gameObject.GetComponent<Rigidbody2D>(); //同上理 告訴系統這是我的Rigidbody2D } void Update() { if(Input.GetKey (KeyCode.W)){ //Unity專有語法 如果滑鼠W按著時為True //Input.GetKey 表示持續按著 //Input.GetKeyDown 表示按鍵按下瞬間 //Input.GetKeyUp 表示按鍵放開瞬間 velocity_y = 1f; //將 velocity_y 變數 轉為 1 }else if(Input.GetKey (KeyCode.S)){ //如果滑鼠S按著時為True velocity_y = -1f; //將 velocity_y 變數 轉為 -1 }else{ velocity_y = 0f; } if(Input.GetKey (KeyCode.D)){ velocity_x = 1f; }else if(Input.GetKey (KeyCode.A)){ velocity_x = -1f; }else{ velocity_x = 0f; } m_rigidbody.velocity = new Vector3(velocity_x, velocity_y, 0f); //將數值轉為Vector3形式並存入m_rigidbody.velocity } } ``` <br> ------------------------------------------------- <br> ## Unity動畫教學與語法 ```csharp= private Animator m_animator; m_animator = gameObject.GetComponent<Animator>(); m_animator.SetBool("running", false); ``` <br> ------------------------------------------------- <br> ## Unity雷射偵測 ```csharp= RaycastHit2D hit = Physics2D.Raycast(Vector3 OriginPosition, Vector3 MoveDirection, float lenght, 1 << LayerMask.NameToLayer("可被雷射偵測的層數")); if(hit.collider != null){ //如果雷射有撞到東西 if (hit.collider.gameObject.tag = "xxx"){ //而且那個東西的tag是"xxx" } } ``` <br> ------------------------------------------------- <br> ## Unity碰撞箱偵測 ```csharp= void OnTriggerEnter2D(Collider2D collision){ //如果有東西進入我的偵測箱裏頭觸發該function if(collision.gameObject.tag == "xxxx"){ 而且該物件的tag為xxx則... // } } ``` <br> ------------------------------------------------- <br> ## Unity生成物件 ```csharp= public GameObject generatedObject; //宣告被生成物體 Instantiate(generatedObject,Vector3 generatedPosition, Vector3 Rotation, parent.Transform); ```