天天看點

3D遊戲程式設計——離散仿真基礎

HW2

1. 簡答題

  • 解釋遊戲對象(GameObjects)和資源(Assets)的差別與聯系。

答:

  1. GameObjects是我們制作遊戲時,遊戲中運作的主體(主角)。而Assets指的是我們在制作遊戲時,可以用于豐富GameObjects的東西。比如我們建立一個Script腳本,并将其挂在Scene中的一個Cube上,那麼這個Cube就是遊戲主體,而這個用于使Cube有自己的動作的腳本就成為了Assets。
  2. 其次,舉Unity作為例子。GameObjects的建立是在界面的左上方create,而Assets的建立是在界面的左下方。(其中,Prefabs可以通過拖拽GameObjects到下方Assets框實作,這也是一種建立Assets的過程)
  • 下載下傳幾個遊戲案例,分别總結資源、對象組織的結構(指資源的目錄組織結構與遊戲對象樹的層次結構)

答:

在逗分享上下載下傳幾個unity3d的小遊戲。

http://www.idoubi.net/category/unity3d/complete-project

資源的目錄組織結構:

3D遊戲程式設計——離散仿真基礎

​ 建立不同的檔案夾,對不同的資源進行分類。簡單的有Material、Scenes、Scirpt三類。

遊戲對象樹的層級結構:

3D遊戲程式設計——離散仿真基礎

​ 子遊戲對象存在于父遊戲對象之下。比如table有4個子遊戲對象。四個chair就會跟着table移動。

  • 編寫一個代碼,使用debug語句來驗證MonoBehaviour基本行為或時間觸發的條件
    • 基本行為包括Awake() Start() Update() FixedUpdate() LateUpdate()
    • 常用事件包括 OnGUI() OnDisable() OnEnable()
    答: 編寫debug語句,舉Awake()為例子:
    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. 程式設計實踐,小遊戲

  • 遊戲内容: 井字棋
  • 制作大緻過程:
  1. 使用既有的cube拼成棋盤和棋盤上的線。
  2. 使用Sphere作為圓,使用兩個交叉的cube組成叉,并将其作為預設。
  3. 編寫圓和叉的腳本,并将其挂在到Main Camera上。
  4. 将所有的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 對象屏蔽了遊戲循環的細節,并使用一組虛方法讓繼承者完成它們,我們稱這種設計為“模闆方法模式”。
    • 為什麼是“模闆方法”模式而不是“政策模式”呢?
    答: 微軟的XNA引擎提供虛方法讓繼承者完成,就是提供了一個模闆來讓需要用到這個東西的繼承者按照模闆來編寫自己的代碼,這是”模闆方法“。至于”政策模式“,指的是所有的方法都是一個”實“方法,而不存在提供虛方法來讓别人實作的,”政策模式“應該提供一個可以直接用的方法供以替換。
  • 将遊戲對象組成樹型結構,每個節點都是遊戲對象(或數)。
    • 嘗試解釋組合模式(Composite Pattern / 一種設計模式)。
    答: 組合模式就是要分類,将一組相似對象作為單一對象,并按照某種規則将這些對象進行分層組合,使其成為一個樹形結構。另外,在對象之間要留有接口,友善各個對象進行連接配接組合。
    • 使用 BroadcastMessage() 方法,向子對象發送消息。你能寫出 BroadcastMessage() 的僞代碼嗎?

    答:

    foreach(Transform child in tranform)

    child.test();

  • 一個遊戲對象用許多部件描述不同方面的特征。我們設計坦克(Tank)遊戲對象不是繼承于GameObject對象,而是 GameObject 添加一組行為部件(Component)。
    • 這是什麼設計模式?
    答: 裝飾器模式(Decorator)。
    • 為什麼不用繼承設計特殊的遊戲對象?
    答: 用裝飾模式可以更加靈活的設計”子類“(并非子類)。若是使用繼承,那麼就不友善我們随時添加功能。

最後附上github位址:https://github.com/yaody7/unity3d-learning/tree/master/HW2

繼續閱讀