解答: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的速度是不同的 } }
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; } }
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 DevilsPriests 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
LoadResources
方法中加載並初始化長方形、正方形、球及其色彩表明遊戲中的對象。牧師與魔鬼:這是一款經典的遊戲,遊戲很簡單,玩家須要操控船隻、牧師和魔鬼,而後使得一個岸邊的三個牧師和三個魔鬼都移動到另外一個岸邊。而且須要在遊戲限定的時間60秒內進行操做。 ide
注意:
因爲遊戲過程比較長,因此只截取部分過程圖,具體遊戲的過程在視頻連接中
設計的結構徹底是按照標準的結構構建的,以下圖所示
在進行編程前,須要瞭解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 (); }
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); } }
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]; } }
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]; } }
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; } } }
繼承了SceneController
和 UserAction
,說明該控制器實現了對兩個接口的繼承並實現;該控制器還實現了加載遊戲資源和加載遊戲人物,而且有控制人物運動和船隻的運動;遊戲的運行時間的控制;判斷遊戲是否結束,和遊戲結束的條件,若是結束了進行重置遊戲,從新設置各個變量
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 (); } }
MoveBoat()
移動船隻、MoveRole
移動人物、restart
從新開始遊戲。該接口經過別的類來繼承,這樣就能夠實現獲得用戶的輸入而後做出反應using System.Collections; using System.Collections.Generic; using UnityEngine; // 用戶或玩家能夠進行的操做 public interface UserAction { void MoveBoat(); void MoveRole(RoleController r); void restart(); }
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 (); } } } }
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); } }
解答:
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 throughpoint
in world coordinates byangle
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 ; }