解答: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 ; }