目錄:
1. 宣告
2. 讀取元件GetComponent<>()
3. 創造、消除及啟用 Instantiate() & Destroy() & SetActive()
4. 子程式宣告OnTrigger & OnMouse
5. 全域變數PlayerPrefs
6. 隨機Random.Range()
7. 移動縮放及時間
8. 輸入
9. 小技巧
10. switch
11. enum枚舉
12. Animation不重複播放
13. 2D射線
14. Input.GetTouch()事件
15. SetActive()簡便寫法
16. SceneManager.LoadScene()場景轉換
17. 將物件帶入下一個場景
18. UI與攝影機畫面綁定
一、宣告
GameObject 名稱; //物件宣告
int[] = { 0, 0 }; //整數的陣列宣告方式
Sprite 名稱; //Sprite(圖片)宣告
Sprite[,] 名稱 = { { a1, a2 }, { b1, b2 }}; //Sprite的雙陣列宣告方式
enum 名稱 { a, b, c}; //枚舉宣告
基本的宣告還有float, bool等等。
在前方加入public代表可以在編輯畫面中的Inspector欄(參數設定欄位)拖曳物件作為預設宣告,例如:
public GameObject a;
另外,已經存在的程式語言也可以做為宣告,假設我已經擁有一個叫做"code.cs"的程式檔案,那麼可以宣告為:
code co;
假設code.cs這個程式碼裡面,有宣告一個enum(枚舉):
public enum en { a, b, c};
en type = en.a;
則宣告過code的這個程式,就可以利用"code.cs"中"名稱B"的枚舉,像是這樣:
code co;
GameObject ga;
ga.GetComponent<code>.type = co.type.a;
如此就能宣告ga的type參數為a了。
二、讀取元件GetComponent<>()
物件.GetComponent<SpriteRenderer>().sprite = sprite_a; //更改物件的圖片
物件.GetComponent<Animator>().SetInteger("in", int); //設定動畫狀態(整數)
物件.GetComponent<Animator>().SetBool("bo", bool); //設定動畫狀態(布林)
物件.GetComponent<Animator>().SetTrigger("ti"); //設定動畫狀態(播放一次開關)
物件.GetComponent<程式名稱>().參數 = 1; //更改物件程式的參數
物件.GetComponent<AudioSource>().volume = float; //更改音效播放器音量
物件.GetComponent<AudioSource>().clip = AudioClip; //更改音效播放器的音效
物件.GetComponent<AudioSource>().play; //播放音效
物件.GetComponent<AudioSource>().stop; //停止音效
物件.GetComponent<AudioSource>().PlayOneShot(AudioClip); //放出一次音效
如果是使用預置物件,可能會有父子階層的問題(預置物件中包含子物件,子物件無法單獨拖曳至Inspector欄位作為參數),因此需對預置元件使用GetCompnentInChildren<>()函數(取得子物件元件)。
反之如果子物件想要對父物件做更動,則要使用GetComponentInParent<>(),例如更改動畫的<Animator>。
若使用InChildren、InParent仍無法得到子或父物件,使用以下方法直接得到該物件。
gameObject.transform.GetChild(int 第幾個).gameObject //取得子物件
gameObject.transform.parent.gameObject //取得父物件
三、創造、消除及啟用 Instantiate() & Destroy() & SetActive()
Instantiate(物件名稱, 位置, 方向); //創造物件
Instantiate(GameObject, new Vector3( x, y, z), Quaternion.identity);
註:x,y,z為float數,Quaternion.identity = Quaternion.Euler (x, y, z)。Vector3(x, y, z)也可以使用Vector3(x, y)忽略z值為0。
Destroy(gameObject); //消除指定物件
Destroy(gameObject, float); //float:幾秒後執行消除動作
物件.SetActive(bool); //將隱藏的物件啟用
四、子程式宣告OnTrigger & OnMouse
void OnTriggerEnter2D(Collider2D c){} //一接觸到範圍發生
void OnTriggerStay2D(Collider2D c){} //在範圍內移動時觸發(靜止時例外)
void OnTriggerExit2D(Collider2D c){} //一離開範圍觸發
註:將Trigger改成Collision、Collider2D改成Collision2D則是非Trigger的碰撞器使用。
void OnMouseDown(){} //點擊瞬間執行一次。
void OnMouseDrag(){} //按住時不斷執行。
void OnMouseUp(){} //放開時執行一次。
void OnMouseEnter(){} //滑鼠游標移動到物件內時執行一次。
void OnMouseExit(){} //滑鼠游標離開物件時執行一次。
五、全域變數PlayerPrefs
PlayerPrefs.SetInt("變數名稱", int); //將整數設定到全域變數中
PlayerPrefs.SetString("變數名稱", String); //將字串設定到全域變數中
PlayerPrefs.GetInt("變數名稱"); //取讀全域變數
PlayerPrefs.GetString("變數名稱");
PlayerPrefs.DeleteKey("變數名稱"); //清除指定的全域變數
PlayerPrefs.DeleteAll(); //清除所有全域變數
全域變數不需要宣告,一但輸入一個不曾用過的名稱就表示宣告完成。
六、隨機Random.Range()
Random.Range(0, 100) //生產一個從0到99的隨機數值。
Random.Range(5, 51) //從5到50的隨機數值。
Random.Range(0.1f, 100.0f) //生產一個從0.1到99的隨機浮點數。
Random.value //可以直接隨機產生一個0到1之間的浮點數。
七、移動縮放及時間
物件.transform.position += new Vector3(0.1f, 0); //向右移動0.1浮點數
物件.transform.localScale = new Vector3(0.5f, 1); //物件大小變瘦一半
物件.transform.rotation = new Vector3(180, 0); //物件水平翻轉
float = 物件.transform.position.x; //float為物件的x值
float += Time.deltaTime; //增加每偵經過的秒數
if(float > 1)float = 0; //如果超過一秒的話該數變為零
Time.timeScale = 0.2f; //遊戲速度為正常的0.2倍
如果要讓遊戲完全停止(例如遊戲暫停),可以讓Time.timeScale值為0,所有Update()都將不會運行(Update()為每偵執行一次),但如果要在完全暫停之下做出動畫時,就須在設為0以前如下:
float time = Time.deltaTime;
物件.GetComponent<Animator>().PlayInFixedTime("動畫名稱", 0, time);
Time.timeScale = 0;
PlayInFixedTime()方法為無視偵率狀態以固定速率執行動畫,因此需先記錄每偵經過時間(Time.deltaTime),強制播放以後再將每偵經過時間設為0倍。
八、輸入
Input.mousePosition //滑鼠或手指按住的位置
Camera.main.ScreenToWorldPoint(Input.mousePosition) //讓點選在鏡頭真正的位置而非UI座標
註:遊戲互動中Input.mousePosition都必須與Camera.main.ScreenToWorldPoint()搭配使用。
if(Input.GetKeyDown(KeyCode.F)); //偵測是否按下F鍵
九、小技巧
1. 在Update()中使用return;能夠截斷後面的語法,可用於程式開關(if條件式)。
2. 註解除了"//"以外,也可以使用"/*文字*/"註解在程式碼之間。
3. 除了"++"也可以用"--"來做減1的動作。
4. print("文字訊息");會在遊戲測試時最下方欄位出現,可用於測試。
5. GameObject.Find("物件名稱")用來讀取場景上的物件。
6. GetComponent<SpriteRenderer>().sprite = null;能夠讓圖片消失。
7. Application.LoadLevel("場景名稱");是舊的更換場景方法。
8. 手機遊戲的建議尺寸為16:9。
9. 上述語法提到的"物件"如果是執行程式本身的物件,則不需要輸入。
十、switch
switch(參數名稱)
{
case 0:
...程式內容...
break;
case 1:
...程式內容...
break;
}
記得使用break做每個case的結尾。
十一、enum枚舉
enum是用於宣告可自訂義的變數,它就像是一個類別名稱自訂而內容為固定常數的int陣列,比方說,名為int可以使用的內容為-2,147,483,648 ~ 2,147,483,647的數字,名為bool可以使用的內容僅true、false兩者,而使用enum宣告你可以取一個像是int或是bool的名字,並定義它的內容有什麼,而其內容可以取常數名字,例如:
enum Days {Sat, Sun, Mon, Tue, Wed, Thu, Fri};
如此就可以使用Day來宣告新的變數:
Days 自訂名稱 = Sun;
自訂名稱 = Mon;
不過事實上,枚舉定義的內容是常數,每個常數在被定義時都被佈置一個整數,從0開始遞增1。以上面的例子來說,Sat=0、Sun=1、Mon=2...依此類推,不過也可以要求定義的常數為指定的整數,例如:
enum Days {Sat=1, Sun, Mon, Tue, Wed, Thu, Fri};
如此就會從1開始遞增了。
十二、Animation不重複播放
點選「.anim」的動畫檔,編輯窗格Inspector會出現「Loop Time」等選項,Loop Time就是控制此動畫檔是否會重複播放。如果需要動畫結束直接切換到下一個動畫,這個選項必須禁用(取消),否則在設定Animator「Has Exit Time」下的Settings即使設定為98% ~ 100%完成時切換至下一個動畫,仍有可能發生結束時跳回第一偵才轉換的錯誤。
十三、2D射線
指的是從物件放出一道隱形射線,去偵測射線接觸到的物件,配置在攝影機上並配合點擊座標可以做出點選事件。
宣告方法如下:
RaycastHit2D 名稱 = Physics2D.Raycast(Vector3 起點, Vector3 方向, Vector3 距離 );
起點:射線發射的起點座標,若是以2D螢幕偵測為主則設為點擊座標。
方向:射線發射的方向,像Rotation轉動角度,若以2D偵測為主則設為Vector2.zero。
距離:射線的長度,可以忽視此參數。
如果要實作一個滑鼠觸控的偵測,宣告方法如下:
RaycastHit2D ray = Physics2D.Raycast(Camera.main.ScreenToWorldPoint(Input.mousePosition), Vector2.zero);
if (ray && Input.GetMouseButton(0))
{
print(ray.collider.gameObject.name)
}
特別要注意,須被偵測的物件需要設定Coillder 2D元件。以上為例,if中的ray為一個bool值,代表是否偵測到物件,而print中的ray.collider.gameObject則代表射線偵測到的物件。
除了Input.mousePosition之外,也可以使用Input.GetTouch(手指順序).position取代為手指偵測。
十四、Input.GetTouch()事件
Input.touchCount //手指按住的數量
Input.GetTouch(順序) //取得第幾順序手指的觸碰,最早接觸的值為0。
Input.GetTouch(順序).fingerID //得到接觸順序的int值
Input.GetTouch(順序).position //接觸座標
Input.GetTouch(順序).rawPostion //在手指點下未放開時,會保持接觸最剛開始的座標
Input.GetTouch(順序).deltaPosition //每偵座標移動的距離(Vector2)
Input.GetTouch(順序).phase //目前手指的狀態,有以下幾種:
TouchPhase.Began //手指接觸的第一偵
TouchPhase.Stationary //手指座標維持停留狀態
TouchPhase.Moved //手指座標正在移動TouchPhase.Ended //未被啟用的狀態
以下為自製的觸控模擬滑鼠偵測程序:
public class Touch_detect : MonoBehaviour {
public Touch finger;
public GameObject[] record_go = new GameObject[8];
public bool active;
void Update()
{
if (Input.touchCount > 0)
{
for (int i = 0; i < Input.touchCount; i++)
{
RaycastHit2D ray = Physics2D.Raycast(Camera.main.ScreenToWorldPoint(Input.GetTouch(i).position), Vector2.zero, 0);
if (ray)
{
if (Input.GetTouch(i).phase == TouchPhase.Began) //按下
{
if (ray.collider.gameObject.GetComponent<Button>() != null)
ray.collider.gameObject.GetComponent<Button>().OnTouchDown();
}
else if (Input.GetTouch(i).phase == TouchPhase.Ended) //放開
{
if (ray.collider.gameObject.GetComponent<Button>() != null)
ray.collider.gameObject.GetComponent<Button>().OnTouchUp();
}
else if (Input.GetTouch(i).phase == TouchPhase.Stationary) //按住
{
if (ray.collider.gameObject.GetComponent<Button>() != null)
{
ray.collider.gameObject.GetComponent<Button>().OnTouchDrag();
record_go[i] = ray.collider.gameObject;
}
}
}
else if(record_go[i] != null) //修復手指移開按鈕會卡在按住的狀態
{
record_go[i].GetComponent<Button>().OnTouchExit();
record_go[i] = null;
}
}
}
}
}
註:<Button>為自定義按鈕專用的Script,OnTouchDown()、OnTouchUp()、OnTouchDrag()、OnTouchExit()也都是自定義的方法,名字都能夠更動。
在OnTouchDown()可以設置SE播放,OnTouchDrag()可以讓按鈕顏色維持變暗狀態,OnTouchUp()、OnTouchExit()可以讓顏色恢復。
record_go是用來記錄目前這隻手指選中的目標,因此當手指移開時,會將剛剛記錄的物件運行OnTouchExit()事件。
十五、SetActive()簡便寫法
如果有一個條件函式if來判斷SetActive(bool)是否開啟,則需要寫兩行,舉例如下:
if(a > b)gameObject.SetActive(true);
else gameObject.SetActive(false);
但其實有更簡單的方法,就是直接把if的條件式寫入SetActive的括號內,如下:
gameObject.SetActive(a > b);
並不複雜,只是有沒有想到而已。
十六、SceneManager.LoadScene()場景轉換
由於過去的Application.LoadLevel(string 場景名稱)已經過時了,雖然還是可以用,但為了求系統穩定,需使用Unity正規的場景轉換方法。
在使用此函式之前,需在最上方載入:
using UnityEngine.SceneManagement;
場景轉換的方法如下:
SceneManager.LoadScene(string 場景名稱);
要注意的是,需要將會載入的場景都匯入遊戲設定中:選擇要目標的場景,然後點選上方選項File/Build Settings.../Add Open Scenes將場景匯入,而匯入的編號也可以將場景轉換的方法(string 場景名稱)用(int 編號)來取代。
十七、將物件帶入下一個場景
DontDestroyOnLoad(gameObject) //轉換場景後,該物件會被帶入下一個場景
以創建一個音效播放器為例,先建一個audio player音效播放器預制物件,在需要有音效播放器的場景插入以下Script:
public GameObject audio_player;
void Start () {
if(GameObject.Find(audio_player.name+"(Clone)") == null)
Instantiate(audio_player);
}
※預制物件被 Instantiate()呼叫後名字後方會增加"(Clone)"。
表示如果這個場景偵測到沒有audio player則就建立一個。
而在audio player設置以下Script內容:
void Start () {
DontDestroyOnLoad(gameObject);
}
代表一旦被製造出來就不會被銷毀,會不斷地在各個場景使用該同一個物件。
之所以會利用在創建audio player上,主要是怕BGM在場景轉換間被終止,如果利用了DontDestroyOnLoad()就能阻止被銷毀而讓場景共用一個物件。還要再寫一個創建audio player的腳本,為的是讓有複製特性的audio player不會與別的場景的相同物件重複,視情況而被創造。
十八、UI與攝影機畫面綁定
假設需要建立一個Text顯示在畫面上,建立UI元件時都會生成一個Canvas作為UI的座標容器,但時往往Canvas的範圍與攝影機相差甚大,雖然輸出後會顯示在一樣的畫面,但會有在編輯場景與攝影機沒對到的問題,僅能在預覽畫面中看到湊合後的狀態,為了方便編輯及安定,可以到Inspector將Canvas的Render Mode設定為「World Space」,並把攝影機拖曳至「Event Camera」中,可以讓Canvas成為一張與攝影機畫面相等的平面圖,UI將會準確的顯示在上面。
補充一下,在腳本中若要使用UI的函式,例如GetComponent<Text>().text,需載入:
using UnityEngine.UI;
其實就只是在原有的"using UnityEngine"後面多了一個".UI",不難記。
Unity雜記Part5遺失內容:
1. Animator的替換
2. 音效移調
3. 設定偵數(fps)
4. Mask遮罩
5. 偽Loading
6. 任何解析度全螢幕化