教材編撰團隊李昭賢助理教授 ( 北科大電子系 ) 侯易佑副教授 ( 南台科大電子系 ) 姚智原助理教授 ( 台科大資工系 ) 陳彥霖教授 ( 北科大資工系 ) 智慧終端整合應用開發模組 微型感測裝置軟硬設計模組 擴增實境創新應用開發模組 穿戴式視覺處理與運算模組 智慧終端與人機互動跨校資源中心
擴增實境創新應用開發模組 Unity 基礎介紹 Unity 介面設計 擴增實境 (Augmented Reality,AR) 應用開發
Unity 基礎介紹
程式腳本 用以描述較複雜的關係及動作 可以直譯執行 Unity 可使用的腳本語言 JavaScript C# Boo 開發環境 MonoDevelop 設置中斷點逐行執行等常用除錯功能 Unity 程式腳本介紹 59
Unity 程式腳本介紹 官方參考文件 離線版 Unity 目錄 / /Editor/Data/Documentation/Documentation/ScriptReference/index.html 或從選單 [Help] [Scripting Reference] 網路版 http://docs.unity3d.com/documentation/scriptreference/index.html 問答區 http://answers.unity3d.com 討論版 http://forum.unity3d.com/ 60
Hello World! Step 1: 建立腳本 第一個腳本程式 在 [Project] 視窗 [Create] [C#Script] 並為腳本命名 在腳本上雙擊, 會自動以 MonoDevelop 開啟 新創建的 C#Script 會自動產生跟 Script 檔同名的類別, 並且繼承 MonoBehaviour 類別 61
Hello World! Step 2: 撰寫 第一個腳本程式 在新創建的類別內會自動產生 2 個函數 Start 和 Update 在 void Start () { 的大括號 { 間輸入 print ( Hello World! ); or Debug.Log(" Hello World "); 點選 [File] [Save] 或快速鍵 [Ctrl]+[S] 存檔 62
第一個腳本程式 相當於 C++ 裡的 include 檔名和類別名一定要相同繼承 63
執行腳本程式 第一個腳本程式 切回 Unity, 將 Project 視窗中的腳本拖曳至 Hierarchy 視窗中的 Main Camera 上 點選 Main Camera, 在 Inspector 視窗中會出現新增的腳本項目 在 Unity 中按下播放鍵, 左下角可看到 Hello World! 在 Hello World 訊息上點擊可叫出 Console 視窗 64
第一個腳本程式 65
第一個腳本程式 66
Unity 基本功能函式語法介紹 MonoBehaviour 的函數 函數名 被呼叫時機 Awake() 在脚本 (Script) 檔被創建並載入場景的時候呼叫 Start() 在創建後的下一個 Update() 被呼叫前執行 Update() 每個禎 (frame) 更新時呼叫 FixedUpdate() 在固定的時間呼叫 OnUI() 用於處理 UI 事件, 每個禎 (Frame) 更新時執行 OnCollisionEnter() 碰撞體 (Collider)/ 剛體 (Rigidbody) 和其他的碰撞體 (Collider)/ 剛體 (Rigidbody) 接觸的一開始執行 OnCollisionExit() 當碰撞體 (Collider)/ 剛體 (Rigidbody) 和其他的碰撞體 (Collider)/ 剛體 (Rigidbody) 終止接觸的瞬間執行 OnCollisionStay() 當碰撞體 (Collider)/ 剛體 (Rigidbody) 和其他的碰撞體 (Collider)/ 剛體 (Rigidbody) 終止接觸的瞬間執行 OnTriggerEnter() 當本身碰撞體進入觸發器 (Trigger) 時執行 OnTriggerExit() 當本身碰撞體離開觸發器 (Trigger) 的瞬間執行 OnTriggerStay() 本身碰撞體與觸發器 (Trigger) 持續接觸的情況下, 每個禎 (Frame) 執行 67
Unity 基本功能函式語法介紹 Unity 程式執行順序 http://docs.unity3d.com/manual/executionorder.html 68
Unity 基本功能函式語法介紹 69
Unity 基本功能函式語法介紹 70
Unity 基本功能函式語法介紹 71
Unity 基本功能函式語法介紹 72
Awake and Start Unity 基本功能函式語法介紹 using UnityEngine; using System.Collections; public class AwakeAndStart : MonoBehaviour { void Awake () { Debug.Log("Awake called."); void Start () { Debug.Log("Start called."); 73
基本規則語法 大小寫有別 Print, print 以分號作為指令結尾 print( XD ); 字串使用 而非 依前後順序執行 C# 不自動做轉型 74
基本規則語法 註解 給人看的, 並不會被編譯執行 單行後方註解 // 連續多行註解 /* */ 75
類別 Class C# script 中都使用類別的方式存在 在類別中, 函式外宣告的變數相當於 java script 中用的全域變數, 同個 class 內的函式都能存取 存取限制 public 公開 在 class 外部可以存取使用 private 私人 只限 class 內部使用, 若是沒宣告都會是 private 76
繼承 Tip 類別能夠繼承其他 class, 例如 A 繼承 B,A 就能使用 B 的 function 和參數, 通常我們稱 B 為父類別,A 為子類別 新建的 script 將自動繼承 MonoBehaviour, 裡面包含基本的 function 如 Start 或 Update 對任何物件或函式按下 F12 可以自動跳到定義的地方 Unity 腳本須成為元件的項目才會被執行 記得 拖曳 到 Hierarchy 的某個元件上 77
變數宣告 不能使用 var (javascript 才使用 ) 宣告方式 型別名稱 ; 或型別名稱 = 初始值 ; int count; int count2 = 0; 78
變數宣告 常用型別 整數 int 浮點數 float, double ( 具有小數點 ) 字串 string 布林值 bool (true, false) 物件 Object 79
全域變數 宣告方式 public 型別變數名稱 ; 初始皆為 預設值 程式中全域變數修改只作用在之後套用的元件 全域變數的元件中的腳本項目可直接修改全域變數值 在播放模式中的修改也將不被保存 80
數學運算 指定運算子 =, +, -, *, /, % int i = 2; string str = Hello! ; string str2 = str+i; //str2 為 Hello!2 int j = 12 - i; //j 為 10 int k = 2 * i; //k 為 4 k = j / i ; //k 為 5 k = j / 3; //k 為 3 int m = 11 % i; //m 為 1 數值在指定後都會受限於原本的型別 將整數變數設為帶小數的值會無條件捨去小數 81
數學運算 遞增 遞減運算子 ++, -- int n = 5; // 將 n 設為 5 print (n++); // 印出 n(5) 之後,n 遞增 ( 變成 6) print (n); // 印出 n (6) print (++n); //n 遞增 ( 變為 7), 之後印出 n (7) print (n); // 印出 n (7) int p = 10; // 將 p 設為 10 print (p--); // 印出 p(10), 之後遞減 ( 變成 9) print (p); // 印出 p(9) print (--p); //p 遞減 ( 變成 8), 之後印出 p(8) print (p); // 印出 p(8) 82
數學運算 常用縮寫法 +=, -=, *=, /= int n = 5; n += 3; // 相當於 n = n + 3; print (n); n -= 4; // 相當於 n = n - 4; print (n); n *= 5; // 相當於 n = n * 5; print (n); n /= 6; // 相當於 n = n / 6; print (n); 83
比較及邏輯運算 比較運算子 >, >=, ==, <=, <,!= int one = 1; print(one > one); print(one >= one); print(one < one); print(one <= one); print(one == one); print(one!= one); 84
比較及邏輯運算 邏輯運算子 && (and), (or) print( true && true ); print( true && false ); print( false && false ); print( true true ); print( true false ); print( false false ); 85
數值字串型別轉換 字串轉數值 轉整數 : int.tryparse (in 字串,out 目標變數 ) 轉浮點數 : float.tryparse(in 字串,out 目標變數 ) int a int.tryparse( 123, out a); // 字串轉整數 print (a); float b; float.tryparse( 3.1415926, out b); // 字串轉浮點數 print (b); 86
數值字串型別轉換 數值轉字串 數字.ToString() 數字 + string c = (2.71).ToString(); // 數值轉字串 print (c); print (a+b); // 單純數字相加 print ( a.tostring() + b.tostring() );// 數字轉字串後相加 87
轉型 C# script 不做自動轉型 未轉型而產生的錯誤 int a = 0; float b = a; 正確的轉型方式 為 目標變數 = ( 目標型態 ) 來源變數 int a = 0; float b = (float) a; 浮點數使用錯誤 float a = 0.0; (X) float a = 0.0f; (O) 88
條件語法 如果 ( 條件 ) 我就 { if( 條件敘述 ) { // 成立時要執行的程式 如果 ( 條件 ) 就 { 不然 { if( 條件敘述 ) { // 成立時要執行的程式 else { // 不成立時要執行的程式 89
條件語法 -if 如果 ( 條件 1), 就執行 { 條件 1 區塊 ; 不是的話, 那如果 ( 條件 2) 就執行 { 條件 2 區塊 ; 不是的話, 那如果 ( 條件 3) 就執行 { 條件 3 區塊 都不是的話, 就執行 {else 區塊 if( 條件 1) { // 條件 1 成立時要執行的程式 else if( 條件 2) { // 條件 1 不成立, 但條件 2 成立時執行的程式 else if( 條件 3) { // 條件 1,2 皆不成立, 但條件 3 成立時執行的程式 // 後續可再串接多個 else if else { // 皆不成立時要執行的程式 90
// 等第制轉換程式 Public int grade ; // 成績 void Update () { if(grade < 50) { // 如果分數小於 50 分 print(' 恭喜你得到一個 E!'); else if(grade < 60) { // 如果小於 50 分不成立 // 且小於 60 分 print(' 恭喜你得到一個 D!'); else if(grade < 70) { // 如果大於 60 分不成立 // 且小於 70 分 print(' 恭喜你得到一個 C!'); else if(grade < 80) { // 如果大於 70 分不成立 // 且小於 80 分 print(' 恭喜你得到一個 B!'); else if(grade <= 100) { // 大於 80 分不成立 // 又小於等於 100 分 print(' 恭喜你得到一個 A!'); else { // 分數大於 100.. print(' 你的分數爆表啦!!!'); 91
放在 Update() 中, 配合 Play 可即時觀察結果 92
條件語法 -switch int intelligence = 5; switch (intelligence) { case 3: print ("Whadya want?"); break; case 2: print ("rog SMASH!"); break; case 1: print ("Ulg, glib, Pblblblblb"); break; default: print ("Incorrect intelligence level."); break; 93
迴圈語法 -while 反覆檢查 ( 條件 ) 成立, 則執行 { 可搭配 break; 強制跳出迴圈 ( 單層 ) while( 條件 ) { // 成立時要執行的程式 void Start () { int count: = 0; // 計算執行次數 while(count < 10) { count++; // 執行次數 +1 print(' 執行 '+count+' 次 '); 94
迴圈語法 -for 包含初始設定 執行條件 每次執行後執行區塊 for( 初始設定 ; 執行條件 ; 區塊執行完後指令 ) { // 成立時要執行的程式 void Start () { for(int count = 0 ; count < 10 ; count++) { print( 執行 +count+ 次 ); 95
陣列物件 -Array 一連串的變數, 可透過迴圈進行大量操作 可動態變動長度 可在任意位置新增或刪除資料 得到長度時用 etlength 需要設定維度,0 為第一維度 int[] arr1 = new int[5]; int[] arr2 = new int[]{1, 3, 5, 7, 9; Int[,] arr3 = new int[2, 3]; Int[,] arr4 = { {1, 2, 3, {4, 5, 6 ; print( arr1.length ); // 印出陣列長度, 5 print( arr3. etlength(0) ); // 印出陣列第一維度的長度, 2 print( arr3. etlength(1) ); // 印出陣列第一維度的長度, 3 96
陣列物件 -ArrayList 一種動態更新的陣列型態 不限型態, 可以同時存入多種不同形態 元素 0 為陣列的第一個 ArrayList arr = new ArrayList(); arr.add( abc ); // 加入新的元素字串 abc arr.add(1); // 加入新的元素數值 1 print( arr.count ); // 印出 arr 長度 arr.insert(0, 10); // 在位置 0 的地方插入 10 print(arr[0]); // 印出陣列 0 的元素, 10 arr.remove( abc ) // 從 arr 中移除元素 abc arr.clear(); // 清空 arr 中的元素 97
迴圈語法 -foreach 適用於 Array ArrayList List 等各種陣列物件 int arr[10]; foreach (int element in arr[10]) { print(element); 98
數學函式 : 包含常用數學公式及常數, 開頭都是 System.Math. 絕對值 PI 兩個數值的最大值 兩個數值的最小值 指數 (x 的 y 次方 ) int i = System.Math.Abs(-199); float pi = System.Math.PI; int maxnum = System.Math.Max( numbera, numberb ); int minnum= System.Math.Min( numbera, numberb); float i = System.Math.Pow( x, y ); 99
數學函式 : 開根號 四捨五入 三角函數 float l = System.Math.Sqrt( n ); float i = System.Math.Round(4.6); // i = 5 float a = System.Math.Sin(0.5 * System.Math.PI); float b = System.Math.Cos(0.5 * System.Math.PI); float c = System.Math.Tan(0.5 * System.Math.PI); float d = System.Math.Asin(0.5); float e = System.Math.Acos(0.5); float f = System.Math.Atan(0.5); 100
隨機物件 -Random 產生隨機數值 可用在寶物掉落 抽獎 攻擊力變動值上 設定種子值 Random.seed = seedvalue; 取得 0~1 間隨機小數值 ( 含邊界值 ) float rnd = Random.value; 取得 min 與 max 間隨機浮點數值 ( 含 min, 不含 max) float rnd = Random.Range(min,max); 101
自訂函式 (Function) 將部分常用的程式碼獨立出來 程式較易閱讀 維護較方便 變數的有效範圍僅在各別函式中 可避免變數名稱重複 可傳遞參數程式碼更活用 傳值 (pass by value)/ 傳參照 (pass by reference) 102
回傳值型別函式名稱 ( 參數 1: 型別, 參數 2: 型別, ) { // 函數內容 return 回傳值 ; // 可加可不加 int addforme(int num1, int num2) { // 函數內容 var sum:int = num1 + num2; return sum; // 回傳值 void Start () { print(addforme(1,1)); 103
// 取得能夠承受的總傷害量 //hp: 角色血量,def: 角色防禦力 //resist: 角色抗性,monsterLevel: 怪物等級 float geteh(float hp, float def, float resist, float monsterlevel() { if(hp<=0) { // 血量小於 0 print(" 血量不得小於等於 0"); return -1; // 回傳 -1 以表示錯誤 if(def<0) { // 防禦值小於 0 print(" 防禦不得小於 0"); return -1; // 回傳 -1 以表示錯誤 if(resist<0) { // 抗性小於 0 print(" 抗性不得小於 0"); return -1; if(monsterlevel<=0) { // 怪物等級小於等於 0 // 回傳 -1 以表示錯誤 print(" 怪物等級不得小於等於 0"); return -1; // 回傳 -1 以表示錯誤 //EH = HP * ( 護甲參數 ) * ( 抗性參數 ) // 護甲參數 = ( 1 + 護甲 / (50*MLVL) ) // 抗性參數 = ( 1 + 抗性 / (5*MLVL) ) float EH; float deffactort; // 護甲參數 float resfactort; // 抗性參數 deffactor=(1+def / (50*monsterLevel)); resfactor=(1+resist/(5*monsterlevel)); EH = hp * deffactor * resfactor; return EH; 104