HW2
1. 簡答題
- 解釋遊戲對象(GameObjects)和資源(Assets)的差別與聯系。
答:
- GameObjects是我們制作遊戲時,遊戲中運作的主體(主角)。而Assets指的是我們在制作遊戲時,可以用于豐富GameObjects的東西。比如我們建立一個Script腳本,并将其挂在Scene中的一個Cube上,那麼這個Cube就是遊戲主體,而這個用于使Cube有自己的動作的腳本就成為了Assets。
- 其次,舉Unity作為例子。GameObjects的建立是在界面的左上方create,而Assets的建立是在界面的左下方。(其中,Prefabs可以通過拖拽GameObjects到下方Assets框實作,這也是一種建立Assets的過程)
- 下載下傳幾個遊戲案例,分别總結資源、對象組織的結構(指資源的目錄組織結構與遊戲對象樹的層次結構)
答:
在逗分享上下載下傳幾個unity3d的小遊戲。
http://www.idoubi.net/category/unity3d/complete-project
資源的目錄組織結構:
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIyZuBnLzAjM2ETN1cTM5ATOwkTMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
建立不同的檔案夾,對不同的資源進行分類。簡單的有Material、Scenes、Scirpt三類。
遊戲對象樹的層級結構:
子遊戲對象存在于父遊戲對象之下。比如table有4個子遊戲對象。四個chair就會跟着table移動。
- 編寫一個代碼,使用debug語句來驗證MonoBehaviour基本行為或時間觸發的條件
- 基本行為包括Awake() Start() Update() FixedUpdate() LateUpdate()
- 常用事件包括 OnGUI() OnDisable() OnEnable()
運作結果如下圖:private void Awake() { Debug.Log("Init Awake"); }
3D遊戲程式設計——離散仿真基礎 - Awake:這是在腳本最開始的時候調用的
- Start:開始調用Update函數之前調用
- Update:在動畫的每一幀逗調用一次
- FixedUpdate:遇到固定幀的時候調用
- LateUpdate:在Update調用的最後調用一次
- OnEnable:當對象激活的時候調用一次,在上圖中是在Awake後調用
- OnDisable:當對象非激活的時候調用一次,再上圖中是OnDisable後調用
- OnGui:在使用Unity的GUI時進行調用。
- 查找腳本手冊,了解 GameObject,Transform,Component 對象
- 分别翻譯官方對三個對象的描述(Description)
答:
Game Object: 遊戲對象是Unity中的基本對象,它展示了遊戲角色,遊戲屬性,遊戲場景。 僅靠他們自己并不能做什麼,但他們可以扮演元件的容器,這些容器将實作他們的實體功能。
Transform: 轉換元件決定了每一個場景中對象的位置、旋轉以及比例。每一個遊戲對象都 有一個轉換元件。
Component: 元件是遊戲中對象和行為的小構成部分。他們是每一個遊戲對象的功能部分。
- 描述下圖中 table 對象(實體)的屬性、table 的 Transform 的屬性、 table 的部件
3D遊戲程式設計——離散仿真基礎 答:
Inspector: 這裡包含了table的基本屬性,比如名稱、Tag标記、Layer層次以及Prefab預設
TransForm: 這裡記錄table的位置資訊:
- Position (0,0,0) 表示位置
- Rotation (0,0,0) 表示旋轉
- Scale (1,1,1) 表示大小
Cube: 表示這個table是由Cube做成的
Box Collider: 碰撞器與觸發器,用來對物體之間的行為做出定義
Mesh Renderer: 網格渲染器,用來設定網格的狀态
Defaul-Material: 這是設定物體的顔色等資訊的Component
- 用 UML 圖描述 三者的關系(請使用 UMLet 14.1.1 stand-alone版本出圖)
3D遊戲程式設計——離散仿真基礎 - 整理相關學習資料,編寫簡單代碼驗證以下技術的實作:
-
查找對象
答:
var myfind = GameObject.Find("table");
- 添加子對象
答:GameObject son = GameObject.CreatePrimitive(PrimitiveType.Cube);
son.transform.parent = this.transform;
-
周遊對象樹
答:
foreach(Transform child in tranform) Debug.Log(child.name);
-
清除所有子對象
答:
foreach(Transform child in tranform) Destroy(child.gameObject);
-
- 資源預設(Prefabs)與 對象克隆 (clone)
-
預設(Prefabs)有什麼好處?
答: 預設可以将一個包含許多元件的遊戲對象作為資源使用。比如我要手工用磚頭搭一坐摩天大廈,我一定是将磚頭這個遊戲對象打包并直接使用,而不會再重新建立一個cube,再調節參數,再拿來用。這為我們建構遊戲對象提供了便利。
-
預設與對象克隆 (clone or copy or Instantiate of Unity Object) 關系?
答: 我們利用預設來更友善地克隆。從某種角度看,預設是将一個遊戲對象克隆到了資源庫中,當我們需要用的時候,又從資源庫中将對象克隆到場景中。
-
制作 table 預制,寫一段代碼将 table 預制資源執行個體化成遊戲對象
答:
代碼:
public class TableBeh : MonoBehaviour
{
public GameObject table;
// Start is called before the first frame update
void Start()
{
GameObject temp = (GameObject)Instantiate(table, transform.position, transform.rotation);
temp.name = "instance";
}
}
測試結果:3D遊戲程式設計——離散仿真基礎 3D遊戲程式設計——離散仿真基礎
-
2. 程式設計實踐,小遊戲
- 遊戲内容: 井字棋
- 制作大緻過程:
- 使用既有的cube拼成棋盤和棋盤上的線。
- 使用Sphere作為圓,使用兩個交叉的cube組成叉,并将其作為預設。
- 編寫圓和叉的腳本,并将其挂在到Main Camera上。
- 将所有的Assets分檔案夾裝好,完成遊戲。
- 關鍵代碼解釋:
void Update() { mousePosition = Input.mousePosition; float x, z; if (mousePosition.x < 314) x = -3.8f; else if (mousePosition.x < 440) x = 0; else x = 3.8f; if (mousePosition.y > 228) z = 3.8f; else if (mousePosition.y > 123) z = 0; else z = -3.8f; targetPosition = new Vector3(x, 0, z); //這裡是通過測量棋盤中間四個交叉點的值,為圓和叉配置設定9個格子正中間的位置。 //Camera.main.ScreenToWorldPoint(new Vector3(mousePosition.x, mousePosition.y, distance)); targetObject.position = targetPosition; if (Input.GetMouseButtonUp(0)) { if (judge == 1) { Instantiate(targetObject, targetObject.transform.position, targetObject.transform.rotation); if (x < 0 && z < 0) //這一段是給标記放上圓或叉的位置 x31 = true; else if (x < 0 && z == 0) x21 = true; else if (x < 0 && z > 0) x11 = true; else if (x == 0 && z < 0) x32 = true; else if (x == 0 && z == 0) x22 = true; else if (x == 0 && z > 0) x12 = true; else if (x > 0 && z < 0) x33 = true; else if (x > 0 && z == 0) x23 = true; else x13 = true; if ((x11 && x12 && x13) || (x21 && x22 && x23) || (x31 && x32 && x33) || (x11 && x21 && x31) || (x12 && x22 && x32) || (x13 && x23 && x33) || (x11 && x22 && x33) || (x13 && x22 && x31)) //判斷是否滿足遊戲結束要求 { over = true; } judge = 0; //judge用來決定己方回合還是對方回合 } else judge = 1; } }
private void OnGUI() { if (over == true) { GUIStyle bb = new GUIStyle(); //建立GUI的格式 bb.normal.background = null; bb.normal.textColor = new Color(1, 0, 0); bb.fontSize = 50; //建立GUI Label GUI.Label(new Rect(Screen.width * 0.32f, Screen.height * 0.33f, 300, 300), "Game Over", bb); GUI.Label(new Rect(Screen.width * 0.35f, Screen.height * 0.50f, 300, 300), "White Win", bb); // GameObject.Find("Main Camera").GetComponent<playball>().enabled = false; // GameObject.Find("Main Camera").GetComponent<playcha>().enabled = false; if (Input.GetMouseButtonDown(0)) Application.LoadLevel(0); //遊戲結束後,再點選一次重新開始。 } }
3. 思考題
- 微軟 XNA 引擎的 Game 對象屏蔽了遊戲循環的細節,并使用一組虛方法讓繼承者完成它們,我們稱這種設計為“模闆方法模式”。
- 為什麼是“模闆方法”模式而不是“政策模式”呢?
- 将遊戲對象組成樹型結構,每個節點都是遊戲對象(或數)。
- 嘗試解釋組合模式(Composite Pattern / 一種設計模式)。
- 使用 BroadcastMessage() 方法,向子對象發送消息。你能寫出 BroadcastMessage() 的僞代碼嗎?
答:
foreach(Transform child in tranform)
child.test();
- 一個遊戲對象用許多部件描述不同方面的特征。我們設計坦克(Tank)遊戲對象不是繼承于GameObject對象,而是 GameObject 添加一組行為部件(Component)。
- 這是什麼設計模式?
- 為什麼不用繼承設計特殊的遊戲對象?
最後附上github位址:https://github.com/yaody7/unity3d-learning/tree/master/HW2