空間與運動 -- MVC架構學習

空間與運動 -- MVC架構學習

簡答並用程序驗證【建議作】

  • 遊戲對象運動的本質是什麼?
  • 請用三種方法以上方法,實現物體的拋物線運動。(如,修改Transform屬性,使用向量Vector3的方法…)
  • 寫一個程序,實現一個完整的太陽系, 其餘星球圍繞太陽的轉速必須不同,且不在一個法平面上。

解答:html

  • 運動的本質就是改變 transform 三個屬性的(Position, Rotation, Scale)值,使物體進行運動

拋物線運動實現的三種方法:git

  • 改變物體 position 的方法,因爲要實現拋物線運動,咱們知道在unity的界面中,垂直方向的改變也就是對y軸進行改變,根據拋物線的公式 $y=v_0t+\frac{1}{2}at^2$,拋物線是向下運動就能夠在公式中添加負號,便可實現物體的想下運動github

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    public class NewBehaviourScript : MonoBehaviour
      {
          public float vx = 0.5f; // x軸方向上的速度
          public float v0 = 0; // y軸方向上的初始速度
          const float a = 9.8f; //加速度a
          // Start is called before the first frame update
          void Start()
          {
          }
      
      // Update is called once per frame
      void Update()
      {
          this.transform.position += new Vector3(vx * Time.deltaTime, (float)(-v0 * Time.deltaTime - 0.5 * a * (Time.deltaTime) * (Time.deltaTime)), 0);
          v0 += a * Time.deltaTime; // 每一幀改變的時候v0的速度是不同的
      }
    }
    • 使用transform的translate函數,此函數使得物體的position移動相應的位置,具體的公式仍是拋物線的公式:$y=v_0t+\frac{1}{2}at^2$
    using System.Collections;
      using System.Collections.Generic;
      using UnityEngine;
      
      public class NewBehaviourScript : MonoBehaviour
      {
          public float vx = 0.5f; // x軸方向上的速度
          public float v0 = 0; // y軸方向上的初始速度
          const float a = 9.8f; //加速度a
          // Start is called before the first frame update
          void Start()
          {
      
          }
      
          // Update is called once per frame
          void Update()
          {
              this.transform.Translate(new Vector3(vx * Time.deltaTime, (float)(-v0 * Time.deltaTime - 0.5 * a * (Time.deltaTime) * (Time.deltaTime)), 0));
              v0 += a * Time.deltaTime;
          }
      }
    • transform中能夠調用一個函數 SetPositionAndRotation,此函數能夠設置物體的position和rotation,rotation能夠不須要設置,position設置的數值和上面基本一致,可是此時須要額外設置時間的變化,以及,初始物體的高度也就是y值
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class NewBehaviourScript : MonoBehaviour
    {
        public float vx = 0.5f; // x軸方向上的速度
        const float a = 9.8f; //加速度a
        public float t = 0;
        public float y = 10.0f; // 初始y的位置
        // Start is called before the first frame update
        void Start()
        {
            
        }
    
        // Update is called once per frame
        void Update()
        {
            this.transform.SetPositionAndRotation(new Vector3(vx * t, y - (float)(0.5 * a * t * t), 10), this.transform.rotation);
            t += Time.deltaTime;
        }
    }
    • 作太陽系,首先從老師給的網址太陽系貼圖,將全部行星的圖片都拖到桌面,而後再拖入unity中,便可在assets中使用,而後將這些圖片拖到大小不一的球星就夠,就能夠造成各大行星編程

      在這裏插入圖片描述

      根據老師上課給的代碼,進行必定的修改,便可完成整個太陽系的行星圍繞太陽轉動的景象c#

      在這裏插入圖片描述

      也能夠看到幾大行星並非在一個法平面上,因此完成了要求segmentfault

      using System.Collections;
      using System.Collections.Generic;
      using UnityEngine;
      
      public class Rotate : MonoBehaviour
      {
          public int v; // 旋轉的速度
          public Vector3 e;
          float x, y; // 法向量
          // Start is called before the first frame update
          void Start()
          {
              // 因爲在不一樣的法平面因此生成的法向量應該是隨機的
              x = Random.Range(1, 10); y = Random.Range(10, 20);
              e = new Vector3(x, y, 0);
          }
          // Update is called once per frame
          void Update()
          {
              Quaternion q = Quaternion.AngleAxis(v * Time.deltaTime, e);
              this.transform.localPosition = q * this.transform.localPosition;
          }
      }

      上面代碼的法向量是隨機生成的故不在同一個法平面,速度能夠本身設置故能夠行星繞着太陽旋轉的速度不同數組

    編程實踐

    • 閱讀如下游戲腳本
    Priests and Devils

    Priests and Devils is a puzzle game in which you will help the Priests and Devils to cross the river within the time limit. There are 3 priests and 3 devils at one side of the river. They all want to get to the other side of this river, but there is only one boat and this boat can only carry two persons each time. And there must be one person steering the boat from one side to the other side. In the flash game, you can click on them to move them and click the go button to move the boat to the other direction. If the priests are out numbered by the devils on either side of the river, they get killed and the game is over. You can try it in many > ways. Keep all priests alive! Good luck!架構

    程序須要知足的要求:dom

    • play the game ( http://www.flash-game.net/gam... )
    • 列出遊戲中說起的事物(Objects)
    • 用表格列出玩家動做表(規則表),注意,動做越少越好
    • 請將遊戲中對象作成預製
    • 在場景控制器 LoadResources 方法中加載並初始化長方形、正方形、球及其色彩表明遊戲中的對象。
    • 使用 C# 集合類型有效組織對象
    • 整個遊戲僅主攝像機和一個 Empty 對象, 其餘對象必須代碼動態生成!!。 整個遊戲不準出現 Find 遊戲對象, SendMessage 這類突破程序結構的 通信耦合 語句。 違背本條準則,不給分
    • 請使用課件架構圖編程,不接受非 MVC 結構程序
    • 注意細節,例如:船未靠岸,牧師與魔鬼上下船運動中,均不能接受用戶事件!

    遊戲規則

    牧師與魔鬼:這是一款經典的遊戲,遊戲很簡單,玩家須要操控船隻、牧師和魔鬼,而後使得一個岸邊的三個牧師和三個魔鬼都移動到另外一個岸邊。而且須要在遊戲限定的時間60秒內進行操做。 ide

    注意

    • 要想使船移動,船上必須有牧師或魔鬼
    • 船上最多有兩我的物
    • 無論哪一個岸上,只要魔鬼數大於牧師數遊戲失敗(數量包括船隻停靠時船上的人物數量)

    遊戲資源

    github地址

    遊戲截圖和視頻

    因爲遊戲過程比較長,因此只截取部分過程圖,具體遊戲的過程在視頻連接中

    視頻連接
    在這裏插入圖片描述
    在這裏插入圖片描述
    在這裏插入圖片描述

    遊戲Assets結構

    設計的結構徹底是按照標準的結構構建的,以下圖所示

    • Materials:存放遊戲中的Material
    • Resources:存放遊戲中的對象的預製
    • Scenes:存放遊戲的場景
    • Scripts:存放遊戲的c#代碼
    • Texture:存放關於物體的一些圖片

    遊戲中的事物

    • Water:水,也就是牧師與魔鬼須要渡過的,由長方體構成,並掛上網上找的圖片
    • Devil:魔鬼,由黑色的長方體構成
    • Priest:牧師,由綠色的長方體構成
    • ground:兩個岸邊,由長方體構成,並掛上圖片
    • Boat:木船,由長方體構成,並掛上圖片

    MVC結構編程

    在進行編程前,須要瞭解MVC的大致結構

    在這裏插入圖片描述

    MVC是界面人機交互程序設計的一種架構模式。它把程序分爲三個部分:

    • 模型(Model):數據對象及關係

      • 遊戲對象、空間關係
    • 控制器(Controller):接受用戶事件,控制模型的變化

      • 一個場景一個主控制器
      • 至少實現與玩家交互的接口(IPlayerAction)
      • 實現或管理運動
    • 界面(View):顯示模型,將人機交互事件交給控制器處理

      • 處收 Input 事件
      • 渲染 GUI ,接收事件

    本實驗也是嚴格按照了MVC結構進行編寫代碼,代碼的大體構成,以下圖所示:

    類中的變量因爲權限不一樣設置成了不一樣的類型,public,private, readonly(只讀變量不能夠對它的值進行修改)

    接下來分別介紹各個代碼實現的具體功能:

    • Director:屬於最高層的控制器,保持運行時始終有一個實例,這樣方便了類與類之間的通訊。

      主要的職責有:

      • 獲取當前遊戲的場景
      • 控制場景運行、切換、入棧與出棧
      • 暫停、恢復、退出
      • 管理遊戲全局狀態
      • 設定遊戲的配置
      • 設定遊戲全局視圖

    能夠經過一個抽象的場景接口訪問不一樣場景的控制器

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    // 負責實例化
    public class Director : System.Object {
        private static Director _instance;
        public SceneController currentSceneController { get; set; }
    
        public static Director getInstance() {
            if (_instance == null)  _instance = new Director ();
            return _instance;
        }
    }
    • SceneController:場景控制器:

      職責:

      • 管理本次場景全部的遊戲對象
      • 協調遊戲對象(預製件級別)之間的通信
      • 響應外部輸入事件
      • 管理本場次的規則(裁判)
      • 各類雜務

    能夠看到它是由interface實現的,說明不能直接來建立對象,咱們經過以前的學習能夠知道,interface的使用須要一個類去繼承它,這樣纔可使用。

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    // 場景管理:加載全部的資源
    public interface SceneController {
        void LoadResources ();
    }
    • RoleController:由類的名字就能夠知道,這是對遊戲人物的控制器,能夠控制人物的移動,而且能夠獲得人物的相關信息,好比該遊戲人物是牧師仍是魔鬼,在船上仍是在岸上,該遊戲人物的名字是什麼等等。不光須要以上的功能,因爲人物是能夠操控的因此咱們還須要監控鼠標對人物的點擊功能。
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    // 對遊戲人物的控制器
    public class RoleController {
        readonly GameObject obj;
        readonly Moving mov;
        readonly ClickGUI clickGUI;
        readonly int PorD; // 判斷是牧師(0)仍是魔鬼(1)
    
        bool _isOnBoat;
        GroundController gController;
    
        public RoleController(string r) {
            
            if (r == "priest") {
                obj = Object.Instantiate (Resources.Load ("Perfabs/Priest", typeof(GameObject)), Vector3.zero, Quaternion.identity, null) as GameObject;
                PorD = 0;
            } else {
                obj = Object.Instantiate (Resources.Load ("Perfabs/Devil", typeof(GameObject)), Vector3.zero, Quaternion.identity, null) as GameObject;
                PorD = 1;
            }
            mov = obj.AddComponent (typeof(Moving)) as Moving;
    
            clickGUI = obj.AddComponent (typeof(ClickGUI)) as ClickGUI;
            clickGUI.setController (this);
        }
    
        public void setName(string n) {
            obj.name = n;
        }
    
        public void setPosition(Vector3 p) {
            obj.transform.position = p;
        }
    
        public void Movingto(Vector3 dest) {
            mov.setDestination(dest);
        }
    
        public int getRole() {
            return PorD;
        }
    
        public string getName() {
            return obj.name;
        }
    
        public void getOnBoat(BoatController b) {
            gController = null;
            obj.transform.parent = b.getGameobj().transform;
            _isOnBoat = true;
        }
    
        public void getGround(GroundController coastCtrl) {
            gController = coastCtrl;
            obj.transform.parent = null;
            _isOnBoat = false;
        }
    
        public bool isOnBoat() {
            return _isOnBoat;
        }
    
        public GroundController getGroundController() {
            return gController;
        }
    
        public void reset() {
            mov.reset ();
            gController = (Director.getInstance ().currentSceneController as FirstController).g1;
            getGround (gController);
            setPosition (gController.getEmptyPosition ());
            gController.getGround (this);
        }
    }
    • GroundController:對地面的控制器,兩個只讀變量sPosition、ePosition記錄了兩個地面的位置, 而後pos數組記錄了陸地上的可存放人物的位置;上陸地和下陸地的動做對變量的修改;有上陸地以前,須要判斷陸地上的空位置的索引,而後才能夠修改變量的內容
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    // 陸地的控制器
    public class GroundController {
        readonly GameObject ground;
        readonly Vector3 sPosition = new Vector3(9, 1, 0);
        readonly Vector3 ePosition = new Vector3(-9, 1, 0);
        readonly Vector3[] pos;
        readonly int st_pos;
    
        RoleController[] roles;
    
        public GroundController(string ss) {
            pos = new Vector3[] {new Vector3(6.5F,2.25F,0), new Vector3(7.5F,2.25F,0), new Vector3(8.5F,2.25F,0), 
                new Vector3(9.5F,2.25F,0), new Vector3(10.5F,2.25F,0), new Vector3(11.5F,2.25F,0)};
    
            roles = new RoleController[6];
    
            if (ss == "from") {
                ground = Object.Instantiate (Resources.Load ("Perfabs/Ground", typeof(GameObject)), sPosition, Quaternion.identity, null) as GameObject;
                ground.name = "from";
                st_pos = 1;
            } else {
                ground = Object.Instantiate (Resources.Load ("Perfabs/Ground", typeof(GameObject)), ePosition, Quaternion.identity, null) as GameObject;
                ground.name = "to";
                st_pos = -1;
            }
        }
    
        public int getEmptyIndex() {
            for (int i = 0; i < roles.Length; i++) {
                if (roles [i] == null) return i;
            }
            return -1;
        }
    
        public Vector3 getEmptyPosition() {
            Vector3 p = pos [getEmptyIndex ()];
            p.x *= st_pos;
            return p;
        }
    
        public void getGround(RoleController r) {
            int ii = getEmptyIndex ();
            roles [ii] = r;
        }
    
        public RoleController getOffGround(string pname) {    // 0->priest, 1->devil
            for (int i = 0; i < roles.Length; i++) {
                if (roles [i] != null && roles [i].getName () == pname) {
                    RoleController r = roles [i];
                    roles [i] = null;
                    return r;
                }
            }
            return null;
        }
    
        public int get_st_pos() {
            return st_pos;
        }
    
        public int[] getRoleNum() {
            int[] cnt = {0, 0};
            for (int i = 0; i < roles.Length; i++) {
                if (roles [i] == null) continue;
    
                if (roles [i].getRole () == 0) cnt[0]++;
                else cnt[1]++;
            }
            return cnt;
        }
    
        public void reset() {
            roles = new RoleController[6];
        }
    }
    • BoatController:對船的控制器,有兩個只讀變量sPosition,ePosition,來表示船的起始和終止位置,而且經過變量st_pos來判斷是起點仍是終點,還須要對船進行控制運動,因此須要監聽鼠標的點擊功能。還須要判斷該船是否爲空,還有空的位置所對應的索引,還須要獲得上船下船等動做的通知;該類的實現和上面的陸地控制器的實現類似,因此設計起來也比較簡單
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    // 船的控制器
    public class BoatController {
        readonly GameObject boat;
        readonly Moving mov;
        readonly Vector3 sPosition = new Vector3 (5, 1, 0); // 起始位置
        readonly Vector3[] sPositions;
        readonly Vector3 ePosition = new Vector3 (-5, 1, 0); // 到達位置
        readonly Vector3[] ePositions;
    
        int st_pos; // 起始點仍是終點:-1:終點 1:起點
        RoleController[] member = new RoleController[2];
    
        public BoatController() {
            st_pos = 1;
    
            sPositions = new Vector3[] { new Vector3 (4.5F, 1.5F, 0), new Vector3 (5.5F, 1.5F, 0) };
            ePositions = new Vector3[] { new Vector3 (-5.5F, 1.5F, 0), new Vector3 (-4.5F, 1.5F, 0) };
    
            boat = Object.Instantiate (Resources.Load ("Perfabs/Boat", typeof(GameObject)), sPosition, Quaternion.identity, null) as GameObject;
            boat.name = "boat";
    
            mov = boat.AddComponent (typeof(Moving)) as Moving;
            boat.AddComponent (typeof(ClickGUI));
        }
    
    
        public void Move() {
            if (st_pos == -1) {
                mov.setDestination(sPosition);
                st_pos = 1;
            } else {
                mov.setDestination(ePosition);
                st_pos = -1;
            }
        }
    
        public int getEmptyIndex() {
            for (int i = 0; i < member.Length; i++) {
                if (member [i] == null) return i;
            }
            return -1;
        }
    
        public bool isEmpty() {
            for (int i = 0; i < member.Length; i++) {
                if (member [i] != null) return false;
            }
            return true;
        }
    
        public Vector3 getEmptyPosition() {
            Vector3 p;
            int ii = getEmptyIndex ();
            if (st_pos == -1) p = ePositions[ii];
            else p = sPositions[ii];
            
            return p;
        }
    
        public void GetOnBoat(RoleController r) {
            int ii = getEmptyIndex ();
            member [ii] = r;
        }
    
        public RoleController GetOffBoat(string member_name) {
            for (int i = 0; i < member.Length; i++) {
                if (member [i] != null && member [i].getName () == member_name) {
                    RoleController r = member [i];
                    member [i] = null;
                    return r;
                }
            }
            return null;
        }
    
        public GameObject getGameobj() {
            return boat;
        }
    
        public int get_st_pos() {
            return st_pos;
        }
    
        public int[] getRoleNum() {
            int[] cnt = {0, 0};
            for (int i = 0; i < member.Length; i++) {
                if (member [i] == null) continue;
    
                if (member [i].getRole () == 0) cnt[0]++;
                else cnt[1]++;
            }
            return cnt;
        }
    
        public void reset() {
            mov.reset ();
            if (st_pos == -1) Move ();
            
            member = new RoleController[2];
        }
    }
    • Moving:是一個關於對象運動的類,該類能夠控制物體的移動速度speed,還能夠設置物體的目的地,以達到物體能夠移動。因爲岸上的人物要想到達船上須要通過兩個步驟,不然可能會穿模,也就是人物會穿過地表面,這樣會不嚴謹,因此我設置了 cur 變量來判斷當前物體運行的位置,而後再根據位置設置相應的目的地(mid, dest),來解決此類問題。
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    // 關於對象運動的實現
    public class Moving: MonoBehaviour {
            
        readonly float speed = 20;
    
        int cur; // 當前運行的位置
        Vector3 dest, mid; // 設置一箇中間位置,使得運動不會穿模
    
        public void setDestination(Vector3 d) {
            dest = d; mid = d;
    
            if (d.y == transform.position.y) cur = 2;
            else if (d.y < transform.position.y) mid.y = transform.position.y;
            else mid.x = transform.position.x;
            
            cur = 1;
        }
    
        public void reset() {
            cur = 0;
        }
    
        void Update() {
            if (cur == 1) {
                transform.position = Vector3.MoveTowards (transform.position, mid, speed * Time.deltaTime);
                if (transform.position == mid) cur = 2;
            } else if (cur == 2) {
                transform.position = Vector3.MoveTowards (transform.position, dest, speed * Time.deltaTime);
                if (transform.position == dest) cur = 0;
            }
        }
    }
    • FirstController:高一層的控制器,控制着這個場景中的全部對象,包括其加載、通訊、用戶輸入。

      繼承了SceneControllerUserAction,說明該控制器實現了對兩個接口的繼承並實現;該控制器還實現了加載遊戲資源和加載遊戲人物,而且有控制人物運動和船隻的運動;遊戲的運行時間的控制;判斷遊戲是否結束,和遊戲結束的條件,若是結束了進行重置遊戲,從新設置各個變量

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    // 總控制器
    public class FirstController : MonoBehaviour, SceneController, UserAction {
    
        readonly Vector3 p_water = new Vector3(0,0.5F,0); // 水的位置
        
        UserGUI uGUI;
    
        public GroundController g1;
        public GroundController g2;
        public BoatController boat;
        private RoleController[] roles; 
        private float time; // 遊戲運行的時間
    
        void Awake() {
            Director d = Director.getInstance ();
            d.currentSceneController = this;
            uGUI = gameObject.AddComponent <UserGUI>() as UserGUI;
            roles = new RoleController[6];
            LoadResources();
            time = 60;
        }
    
        // 遊戲時間的運行
        void Update() {
            time -= Time.deltaTime;
            this.gameObject.GetComponent<UserGUI>().time = (int) time;
            uGUI.isWin = isfinished ();
        }
    
        private void loadRole() {
            for (int i = 0; i < 3; i++) {
                RoleController r = new RoleController ("priest");
                r.setName("priest" + i);
                r.setPosition (g1.getEmptyPosition ());
                r.getGround (g1); g1.getGround (r);
    
                roles [i] = r;
            }
    
            for (int i = 0; i < 3; i++) {
                RoleController r = new RoleController ("devil");
                r.setName("devil" + i);
                r.setPosition (g1.getEmptyPosition ());
                r.getGround (g1); g1.getGround (r);
    
                roles [i+3] = r;
            }
        }
    
        public void LoadResources() {
            GameObject water = Instantiate (Resources.Load ("Perfabs/Water", typeof(GameObject)), p_water, Quaternion.identity, null) as GameObject;
            water.name = "water";
    
            g1 = new GroundController ("from");
            g2 = new GroundController ("to");
            boat = new BoatController ();
    
            loadRole ();
        }
    
        public void MoveBoat() {
            if (boat.isEmpty ()) return;
            boat.Move ();
            uGUI.isWin = isfinished ();
        }
    
        public void MoveRole(RoleController r) {
            if (r.isOnBoat ()) {
                GroundController which_g;
                if (boat.get_st_pos () == -1) which_g = g2;
                else which_g = g1;
                
                boat.GetOffBoat (r.getName());
                r.Movingto (which_g.getEmptyPosition ());
                r.getGround (which_g);
                which_g.getGround (r);
            } else {                                    
                GroundController which_g = r.getGroundController ();
    
                if (boat.getEmptyIndex () == -1) return; // 船是空的        
                if (which_g.get_st_pos () != boat.get_st_pos ()) return;
    
                which_g.getOffGround(r.getName());
                r.Movingto (boat.getEmptyPosition());
                r.getOnBoat (boat);
                boat.GetOnBoat (r);
            }
            uGUI.isWin = isfinished ();
        }
    // 判斷是否結束 0:沒有結束 1:輸 2:贏
        int isfinished() {    
            if (time < 0) return 1;
            int p1 = 0; int d1 = 0; // 起始點牧師與魔鬼數量
            int p2 = 0; int d2 = 0; // 終點牧師與魔鬼數量
    
            int[] cnt1 = g1.getRoleNum (); // 起始點的人數
            p1 += cnt1[0]; d1 += cnt1[1];
    
            int[] cnt2 = g2.getRoleNum (); // 終點的人數
            p2 += cnt2[0]; d2 += cnt2[1];
    
            if (p2 + d2 == 6) return 2;
    
            int[] cnt3 = boat.getRoleNum (); // 船上人的數量
            if (boat.get_st_pos () == -1) {    
                p2 += cnt3[0]; d2 += cnt3[1];
            } else {    
                p1 += cnt3[0]; d1 += cnt3[1];
            }
    
            if (p1 < d1 && p1 > 0) return 1;
            if (p2 < d2 && p2 > 0) return 1;
            return 0;            
        }
    
        public void restart() {
            time = 60;
            boat.reset ();
            g1.reset (); g2.reset ();
            for (int i = 0; i < roles.Length; i++) roles [i].reset ();
        }
    }
    • UserAction:接口,定義了玩家能夠進行的操做MoveBoat() 移動船隻、MoveRole 移動人物、restart從新開始遊戲。該接口經過別的類來繼承,這樣就能夠實現獲得用戶的輸入而後做出反應
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    // 用戶或玩家能夠進行的操做
    public interface UserAction {
        void MoveBoat();
        void MoveRole(RoleController r);
        void restart();
    }
    • UserGUI:用戶交互,來設置整個用戶界面,判斷遊戲是否勝利,若是勝利則顯示Win,並有一個按鈕表示是否須要從新玩這個遊戲;若是失敗則會顯示GameOver,而後也能夠進行遊戲重置。在此我還設置了字體的大小和按鈕的大小,方便觀看,也不失美感
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    public class UserGUI : MonoBehaviour {
        private UserAction u;
        public int isWin = 0;// 1:Gameover 2:Win
        public int time; // 遊戲運行時間
        GUIStyle ssize, buttons, tsize;
    
        void Start() {
            u = Director.getInstance ().currentSceneController as UserAction;
    
            // 設置字體大小
            ssize = new GUIStyle(); tsize = new GUIStyle();
            ssize.fontSize = 45; tsize.fontSize = 20;
            ssize.alignment = TextAnchor.MiddleCenter;
    
            // 設置按鈕大小
            buttons = new GUIStyle("button");
            buttons.fontSize = 30;
    
            // 設置遊戲的時長
            time = 60;
        }
        // 判斷是否勝利或失敗,而後重置
        void OnGUI() {
            GUI.Label(new Rect(0, 0, 100, 50), "Time:  " + time, tsize);
            if (isWin == 1) {
                GUI.Label(new Rect(Screen.width / 2 - 50, Screen.height / 2 - 80, 100, 50), "Gameover!", ssize);
                if (GUI.Button(new Rect(Screen.width / 2-65, Screen.height / 2, 140, 70), "Restart", buttons)) {
                    isWin = 0; u.restart ();
                }
            } else if(isWin == 2) {
                GUI.Label(new Rect(Screen.width / 2 - 50, Screen.height / 2 - 80, 100, 50), " Win!", ssize);
                if (GUI.Button(new Rect(Screen.width / 2 - 65, Screen.height / 2, 140, 70), "Restart", buttons)) {
                    isWin = 0; u.restart ();
                }
            }
        }
    }
    • ClickGUI:用來監聽鼠標的點擊功能,而且調用RoleController實現對人物的控制
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    // 鼠標點擊的控制
    public class ClickGUI : MonoBehaviour {
        UserAction u;
        RoleController roleController;
    
        public void setController(RoleController rc) {
            roleController = rc;
        }
    
        void Start() {
            u = Director.getInstance ().currentSceneController as UserAction;
        }
    
        void OnMouseDown() {
            if (gameObject.name == "boat") u.MoveBoat ();
            else u.MoveRole (roleController);
        }
    }

    思考題【選作】

    • 使用向量與變換,實現並擴展 Tranform 提供的方法,如 Rotate、RotateAround 等

    解答:

    • Rotate:

      Rotates the object around the given axis by the number of degrees defined by the given angle.

      Rotate has an axis, angle and the local or global parameters. The rotation axis can be in any direction.

      須要實現繞v軸旋轉角度x,獲得了旋轉以後,就能夠改變t的position和rotation

      void Rotate(Transform t, Vector3 axis, float angle)
      {
          var r = Quaternion.AngleAxis(angle, axis);
          t.position = r * t.position; t.rotation *= r;
      }
    • RotateAround:

      Rotates the transform about axis passing through point in world coordinates by angle degrees.

      此函數是圍繞中心旋轉,咱們須要獲得物體的位移,求完以後,將它進行旋轉而後加上中心的位移便可。

    void RotateAround(Transform t, Vector3 center, Vector3 axis, float angle)
    {
        var r = Quaternion.AngleAxis(angle, axis);
        var dis = t.position - center;
        dis *= r; t.position = center + dis; t.rotation *= r ;
    }
    相關文章
    相關標籤/搜索