小言_互联网的博客

3D游戏编程与设计第二次作业

294人阅读  评论(0)

作业内容

简答题

1.游戏对象运动的本质是什么?

游戏对象运动的本质是游戏对象每一帧在空间上的变化,例如位置发生变化(Position),或者发生了旋转(Rotation)。

2.请用三种方法以上方法,实现物体的抛物线运动。(如,修改Transform属性,使用向量Vector3的方法…)

平抛运动:水平方向速度保持不变,竖直方向速度公式为vt = gt

  1. 新建一个Vector3变量,为change,水平方向上的变化每一帧都是固定的,水平速度 * 时间间隔,竖直方向上为竖直速度 * 时间间隔,z方向为0。
     using System.Collections;
     using System.Collections.Generic;
     using UnityEngine;
     
     public class HPM2 : MonoBehaviour {
     
     	// Use this for initialization
     	void Start () {
     		
     	}
     	private float verticalSpeed = 0.00f;
     	public float horizontalSpeed = 5.00f;
     	const float g = 0.098f;
     	// Update is called once per frame
     	void Update () {
     		Vector3 change = new Vector3 (Time.deltaTime * horizontalSpeed, -Time.deltaTime * verticalSpeed, 0.0f);
     		this.transform.position += change;
     		verticalSpeed += g;
     	}
     }
    
  2. 与1类似,但是不调用position,而是调用Translate函数
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class HPM3 : MonoBehaviour {
    
    	// Use this for initialization
    	void Start () {
    		
    	}
    	private float verticalSpeed = 0.00f;
    	public float horizontalSpeed = 5.00f;
    	const float g = 0.098f;
    	// Update is called once per frame
    	void Update () {
    		Vector3 change = new Vector3 (Time.deltaTime * horizontalSpeed, -Time.deltaTime * verticalSpeed, 0.0f);
    		this.transform.Translate (change);
    		verticalSpeed += g;
    	}
    }
    
  3. 直接运用position的加减来完成
     using System.Collections;
     using System.Collections.Generic;
     using UnityEngine;
     
     public class HPM1 : MonoBehaviour {
     
     	// Use this for initialization
     	void Start () {
     		
     	}
     	private float verticalSpeed = 0.00f;
     	public float horizontalSpeed = 5.00f;
     	const float g = 0.098f;
     	// Update is called once per frame
     	void Update () {
     		this.transform.position += Vector3.right * Time.deltaTime * horizontalSpeed;
     		this.transform.position += Vector3.down * Time.deltaTime * verticalSpeed;
     		verticalSpeed += g;
     		Debug.Log (verticalSpeed);
     	}
     }
    
    

3.写一个程序,实现一个完整的太阳系, 其他星球围绕太阳的转速必须不一样,且不在一个法平面上。

  • 下载所需要的贴图资源,添加到Assets中

    太阳系贴图下载链接

  • 创建游戏对象

    这里这里建议使用2D操作,比较好调整星球间的位置关系,调整好后,只需要将Assets中对应的图片拖到对应星球上即可。

  • 建立游戏对象关系树

    这里说明一下,EarthClone是一个空对象,和Earth一样,有公转行为,但是没有自转行为。Moon做为EarthClone的子对象,是因为如果作为Earth的子对象,将会影响Moon的公转行为:此时Moon的旋转位置的移动是自身的公转叠加Earth的自转。Sun与SunClone是同理的。

  • 编写代码
    • 作用在SunClone上的代码

      using System.Collections;
      using System.Collections.Generic;
      using UnityEngine;
      
      public class SolarSystem : MonoBehaviour {
      
      	// Use this for initialization
      	void Start () {
      		
      	}
      	
      	// Update is called once per frame
      	void Update () {
      		//Rotation
      		float rotationStandarTime = 20.0f;
      		GameObject.Find ("Mercury").transform.Rotate (Vector3.down * Time.deltaTime * (rotationStandarTime / 58.65f));
      		GameObject.Find ("Venus").transform.Rotate (Vector3.up * Time.deltaTime * (rotationStandarTime / 224.7f));
      		GameObject.Find ("Earth").transform.Rotate (Vector3.down * Time.deltaTime * (rotationStandarTime / 1.0f));
      		GameObject.Find ("Moon").transform.Rotate (Vector3.down * Time.deltaTime * (rotationStandarTime / 27.32f));
      		GameObject.Find ("Mars").transform.Rotate (Vector3.down * Time.deltaTime * (rotationStandarTime / 1.0f));
      		GameObject.Find ("Jupiter").transform.Rotate (Vector3.down * Time.deltaTime * (rotationStandarTime / 0.24f));
      		GameObject.Find ("Saturn").transform.Rotate (Vector3.down * Time.deltaTime * (rotationStandarTime / 0.24f));
      		GameObject.Find ("Uranus").transform.Rotate (Vector3.up * Time.deltaTime * (rotationStandarTime / 0.71f));
      		GameObject.Find ("Neptune").transform.Rotate (Vector3.down * Time.deltaTime * (rotationStandarTime / 0.67f));
      
      		//Orbital revolution
      		Transform center = this.transform;
      		float reStandarTime = 360.0f;
      		GameObject.Find ("Mercury").transform.RotateAround(center.position, new Vector3(0.1f, -1, 0), reStandarTime / 88.0f);
      		GameObject.Find ("Venus").transform.RotateAround(center.position, new Vector3(0.2f, -1, 0), reStandarTime / 224.7f);
      		GameObject.Find ("Earth").transform.RotateAround(center.position, new Vector3(0.3f, -1, 0), reStandarTime / 365.25f);
      		GameObject.Find ("EarthClone").transform.RotateAround(center.position, new Vector3(0.3f, -1, 0), reStandarTime / 365.25f);
      		GameObject.Find ("Moon").transform.RotateAround(GameObject.Find("EarthClone").transform.position, new Vector3(0, -1, 0), reStandarTime / 27.32f);
      		GameObject.Find ("Mars").transform.RotateAround(center.position, new Vector3(0.5f, -1, 0), reStandarTime / 686.98f);
      		GameObject.Find ("Jupiter").transform.RotateAround(center.position, new Vector3(0.6f, -1, 0), reStandarTime / 4328.9f);
      		GameObject.Find ("Saturn").transform.RotateAround(center.position, new Vector3(0.7f, -1, 0), reStandarTime / 10767.5f);
      		GameObject.Find ("Uranus").transform.RotateAround(center.position, new Vector3(0.8f, -1, 0), reStandarTime / 30776.8f);
      		GameObject.Find ("Neptune").transform.RotateAround(center.position, new Vector3(0.9f, -1, 0), reStandarTime / 60152.0f);
      	}
      }
      

      这里说明一下:GameObject.Find ("name")函数是找到拥有“name”的名字对象;Rotate函数是用来实现物体自转的函数,参数里面的Vector3.down 表示逆时针方向进行旋转;在RotateAround函数里,第一个参数是中心点所在的位置,第二个参数是法平面,第三个参数是转速。

    • 作用在Sun上的代码

      using System.Collections;
      using System.Collections.Generic;
      using UnityEngine;
      
      public class Sun : MonoBehaviour {
      
      	// Use this for initialization
      	void Start () {
      		
      	}
      
      	// Update is called once per frame
      	void Update () {
      		float rotationStandarTime = 20.0f;
      		this.transform.Rotate (Vector3.down * Time.deltaTime * (rotationStandarTime / 25.05f));
      	}
      }
      
  • 运行效果

游戏编程

  • 阅读以下游戏脚本

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!

  • 程序需要满足的要求:

  1. play the game (http://www.flash-game.net/game/2535/priests-and-devils.html )
  2. 列出游戏中提及的事物(Objects)
  3. 用表格列出玩家动作表(规则表),注意,动作越少越好
  4. 请将游戏中对象做成预制
  5. 在 GenGameObjects 中创建 长方形、正方形、球 及其色彩代表游戏中的对象。
  6. 使用 C# 集合类型 有效组织对象
  7. 整个游戏仅 主摄像机 和 一个 Empty 对象,其他对象必须代码动态生成!!! 。 整个游戏不许出现 Find 游戏对象, SendMessage 这类突破程序结构的 通讯耦合 语句。 违背本条准则,不给分
  8. 请使用课件架构图编程,不接受非 MVC 结构程序
  9. 注意细节,例如:船未靠岸,牧师与魔鬼上下船运动中,均不能接受用户事件!
  • 游戏中提及的事物
    Priest、Devil、Boat、Two sides of the river(start、finish)、Go button
  • 用表格列出玩家动作表(规则表)
动作 发生条件
点击GO按钮 船上有人且船在某一岸边
牧师上船 牧师与船在同一岸,且船有空位
恶魔上船 恶魔与船在同一岸,且船有空位
牧师下船 船靠岸、有牧师在船上
恶魔下船 船靠岸、有恶魔在船上
  • 将游戏中对象做成预制

  • 编写代码

    代码由三个部分组成,Model.cs、View.cs、Controller.cs。其中Model.cs处理数据对象及关系;View.cs负责显示模型,提供用户交互的界面,将人机交互事件交给控制器处理等;Controller.cs负责接受用户事件,控制模型的变化,判断游戏胜负等等。

    Model.cs
     using System.Collections;
     using System.Collections.Generic;
     using UnityEngine;
     using game;
     
     public class Model : MonoBehaviour {
     	//存放左边的牧师
     	Stack<GameObject> leftPriests = new Stack<GameObject>();
     	//存放右边的牧师
     	Stack<GameObject> rightPriests = new Stack<GameObject>();
     	//存放左边的恶魔
     	Stack<GameObject> leftDevils = new Stack<GameObject>();
     	//存放右边的恶魔
     	Stack<GameObject> rightDevils = new Stack<GameObject>();
     
     	//船上的两个位置
     	GameObject[] ship = new GameObject[2];
     	GameObject ship_obj;
     	public float speed = 5.0f;
     
     	SSDirector s1;
     
     	Vector3 shipLeftPostion = new Vector3(-3f, 0.5f, 0.0f);
     	Vector3 shipRightPostion = new Vector3(3f, 0.5f, 0);
     	Vector3 sideLeftPostion = new Vector3(-14f, -5f, 0);
     	Vector3 sideRightPostion = new Vector3(14f, -5f, 0);
     	Vector3 priestsLeftPostion = new Vector3(-19f, 2.2f, 0);
     	Vector3 priestsRightPostion = new Vector3(16f, 2.2f, 0);
     	Vector3 DevilsLeftPostion = new Vector3(-12f, 2.0f, 0);
     	Vector3 DevilsRightPostion = new Vector3(7f, 2.0f, 0);
     	Vector3 waterPostion = new Vector3(0f, -5f, 0);
     
     	void load(){
     		//加载两岸
     		Instantiate(Resources.Load("Side"), sideLeftPostion, Quaternion.identity);
     		Instantiate(Resources.Load("Side"), sideRightPostion, Quaternion.identity);
     
     		//加载水
     		Instantiate(Resources.Load("Water"), waterPostion, Quaternion.identity);
     
     		//加载船
     		ship_obj = Instantiate(Resources.Load("Ship"), shipLeftPostion, Quaternion.identity) as GameObject;
     
     		//加载牧师和恶魔
     		for (int i = 0; i < 3; i++) {
     			leftPriests.Push (Instantiate (Resources.Load ("Priest")) as GameObject);
     			leftDevils.Push (Instantiate (Resources.Load ("Devil")) as GameObject);
     		}
     	}
     
     	//用于设置牧师和恶魔的位置
     	void setTargetPosition(Stack<GameObject> target, Vector3 position){
     		GameObject[] temp = target.ToArray ();
     		for (int i = 0; i < target.Count; i++) {
     			temp [i].transform.position = position + new Vector3 (2.0f * i, 0f, 0f);
     		}
     	}
     
     	//判断船上有没有空位以及空位的位置
     	int shipEmpty(){
     		int empty = 0;
     		for (int i = 0; i < 2; i++) {
     			if (ship [i] == null) {
     				empty++;
     			}
     		}
     		return empty;
     	}
     
     	//上船操作
     	void getOnShip(GameObject obj){
     		obj.transform.parent = ship_obj.transform;
     		if (shipEmpty () != 0) {
     			if (ship [0] == null) {
     				ship [0] = obj;
     				if (obj.name == "Priest(Clone)") {
     					obj.transform.localPosition = new Vector3 (-0.3f, 2.9f, 0);
     				} 
     				else {
     					obj.transform.localPosition = new Vector3 (-0.4f, 2.5f, 0);
     				}
     			} 
     			else {
     				ship [1] = obj;
     				if (obj.name == "Priest(Clone)") {
     					obj.transform.localPosition = new Vector3 (0.3f, 2.9f, 0);
     				} 
     				else {
     					obj.transform.localPosition = new Vector3 (0.4f, 2.5f, 0);
     				}
     			}
     		}
     	}
     
     	//船移动
     	public void shipMove(){
     		//有人在船上才能移动
     		if (shipEmpty () != 2) {
     			if (s1.state == State.Left) {
     				s1.state = State.LTR;
     			}
     			else if (s1.state == State.Right) {
     				s1.state = State.RTL;
     			}
     		}
     	}
     
     	//下船
     	public void offShip(int side){
     		if (ship [side] != null) {
     			ship [side].transform.parent = null;
     			if (s1.state == State.Left) {
     				if (ship [side].name == "Priest(Clone)") {
     					leftPriests.Push (ship [side]);
     				}
     				else{
     					leftDevils.Push (ship [side]);
     				}
     			}
     			else if(s1.state == State.Right){
     				if (ship [side].name == "Priest(Clone)") {
     					rightPriests.Push (ship [side]);
     				}
     				else{
     					rightDevils.Push (ship [side]);
     				}
     			}
     			ship [side] = null;
     		}
     	}
     
     	public void restart(){
     		s1.state = State.Left;
     		ship_obj.transform.position = shipLeftPostion;
     		int rightNumPriest = rightPriests.Count;
     		int rightNumDevil = rightDevils.Count;
     		for (int i = 0; i < rightNumPriest; i++) {
     			leftPriests.Push (rightPriests.Pop ());
     		}
     		for (int i = 0; i < rightNumDevil; i++) {
     			leftDevils.Push (rightDevils.Pop ());
     		}
     		offShip (0);
     		offShip (1);
     	}
     
     	//检查游戏是否结束
     	void check(){
     		//全都达到右岸
     		if (rightPriests.Count == 3 && rightDevils.Count == 3) {
     			s1.state = State.Win;
     			return;
     		}
     
     		//某一边恶魔多余牧师
     		int numShipPriest = 0;
     		int numLeftPriest = 0;
     		int numRightPriest = 0;
     		int numShipDevil = 0;
     		int numLeftDevil = 0;
     		int numRightDevil = 0;
     		for (int i = 0; i < 2; i++) {
     			if (ship [i] != null && ship [i].name == "Priest(Clone)") {
     				numShipPriest++;
     			}
     			else if (ship [i] != null && ship [i].name == "Devil(Clone)") {
     				numShipDevil++;
     			}
     		}
     		if (s1.state == State.Left) {
     			numLeftPriest = leftPriests.Count + numShipPriest;
     			numRightPriest = rightPriests.Count;
     			numLeftDevil = leftDevils.Count + numShipDevil;
     			numRightDevil = rightDevils.Count;
     		}
     		else if(s1.state == State.Right) {
     			numLeftPriest = leftPriests.Count;
     			numRightPriest = rightPriests.Count + numShipPriest;
     			numLeftDevil = leftDevils.Count;
     			numRightDevil = rightDevils.Count + numShipDevil;
     		}
     		if ((numLeftPriest != 0 && numLeftPriest < numLeftDevil) || (numRightPriest != 0 && numRightPriest < numRightDevil)) {
     			s1.state = State.Lose;
     		}
     	}
     
     	//从岸到船
     	public void priestLeftOnBoat (){
     		if (leftPriests.Count != 0 && shipEmpty() != 0 && s1.state == State.Left) {
     			getOnShip (leftPriests.Pop ());
     		}
     	}
     
     	public void priestRightOnBoat (){
     		if (rightPriests.Count != 0 && shipEmpty() != 0 && s1.state == State.Right) {
     			getOnShip (rightPriests.Pop ());
     		}
     	}
     
     	public void devilLeftOnBoat (){
     		if (leftDevils.Count != 0 && shipEmpty() != 0 && s1.state == State.Left) {
     			getOnShip (leftDevils.Pop ());
     		}
     	}
     
     	public void devilRightOnBoat (){
     		if (rightDevils.Count != 0 && shipEmpty() != 0 && s1.state == State.Right) {
     			getOnShip (rightDevils.Pop ());
     		}
     	}
     
     	// Use this for initialization
     	void Start () {
     		s1 = SSDirector.getInstance ();
     		s1.setModel (this);
     		load ();
     	}
     	
     	// Update is called once per frame
     	void Update () {
     		setTargetPosition (leftPriests, priestsLeftPostion);
     		setTargetPosition (rightPriests, priestsRightPostion);
     		setTargetPosition (leftDevils, DevilsLeftPostion);
     		setTargetPosition (rightDevils, DevilsRightPostion);
     
     		if (s1.state == State.LTR) {
     			ship_obj.transform.position = Vector3.MoveTowards (ship_obj.transform.position, shipRightPostion, Time.deltaTime * speed);
     			if (ship_obj.transform.position == shipRightPostion) {
     				s1.state = State.Right;
     			}
     		} 
     		else if (s1.state == State.RTL) {
     			ship_obj.transform.position = Vector3.MoveTowards (ship_obj.transform.position, shipLeftPostion, Time.deltaTime * speed);
     			if (ship_obj.transform.position == shipLeftPostion) {
     				s1.state = State.Left;
     			}
     		}
     		else {
     			check ();
     		}
     	}
     }
    
    View.cs
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using game;
    
    public class View : MonoBehaviour {
    
    	SSDirector s1;
    	Action action;
    	// Use this for initialization
    	void Start () {
    		s1 = SSDirector.getInstance ();
    		action = SSDirector.getInstance () as Action;
    	}
    	
    	// Update is called once per frame
    	void Update () {
    		
    	}
    
    	void OnGUI(){
    		GUI.skin.label.fontSize = 30;
    		if (s1.state == State.Win) {
    			if (GUI.Button (new Rect (235, 150, 300, 100), "You win!(*^_^*)\nClick here to restart")) {
    				action.restart ();
    			}
    		}
    		if (s1.state == State.Lose) {
    			if (GUI.Button (new Rect (235, 150, 300, 100), "You lose./(ㄒoㄒ)/~~\nClick here to restart")) {
    				action.restart ();
    			}
    		}
    		if (GUI.Button (new Rect (330, 40, 100, 50), "GO")) {
    			action.shipMove ();
    		}
    		if (GUI.Button (new Rect (300, 250, 80, 40), "Left OFF") && s1.state != State.LTR && s1.state != State.RTL) {
    			action.offShipLeft ();
    		}
    		if (GUI.Button (new Rect (400, 250, 80, 40), "Right OFF") && s1.state != State.LTR && s1.state != State.RTL) {
    			action.offShipRight ();
    		}
    		if (GUI.Button (new Rect (50, 90, 75, 40), "Priest ON")) {
    			action.priestLeftOnBoat ();
    		}
    		if (GUI.Button (new Rect (650, 90, 75, 40), "Priest ON")) {
    			action.priestRightOnBoat ();
    		}
    		if (GUI.Button (new Rect (190, 90, 75, 40), "Devil ON")) {
    			action.devilLeftOnBoat ();
    		}
    		if (GUI.Button (new Rect (500, 90, 75, 40), "Devil ON")) {
    			action.devilRightOnBoat ();
    		}
    	}
    }
    
    Controller.cs
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using game;
    
    namespace game{
    	public enum State{Left, Right, LTR, RTL, Win, Lose};
    
    	public interface Action{
    		//船移动
    		void shipMove ();
    		//角色在岸左边下船
    		void offShipLeft ();
    		//角色在岸右边下船
    		void offShipRight ();
    		//重新开始
    		void restart ();
    		//牧师在岸左边上船
    		void priestLeftOnBoat ();
    		//牧师在岸右边上船
    		void priestRightOnBoat ();
    		//恶魔在岸左边上船
    		void devilLeftOnBoat ();
    		//恶魔在岸右边上船
    		void devilRightOnBoat ();
    	}
    
    	public class SSDirector : System.Object, Action{
    		private static SSDirector instance;
    		private Model obj;
    		public Controller controller;
    		public State state = State.Left;
    
    		public static SSDirector getInstance(){
    			if (instance == null) {
    				instance = new SSDirector ();
    			}
    			return instance;
    		}
    
    		public Model getModel(){
    			return obj;
    		}
    
    		internal void setModel(Model obj2){
    			if(obj == null){
    				obj = obj2;
    			}
    		}
    
    		public void shipMove (){
    			obj.shipMove ();
    		}
    
    		public void offShipLeft (){
    			obj.offShip (0);
    		}
    
    		public void offShipRight (){
    			obj.offShip (1);
    		}
    
    		public void restart(){
    			obj.restart ();
    		}
    
    		public void priestLeftOnBoat (){
    			obj.priestLeftOnBoat ();
    		}
    
    		public void priestRightOnBoat (){
    			obj.priestRightOnBoat ();
    		}
    
    		public void devilLeftOnBoat (){
    			obj.devilLeftOnBoat ();
    		}
    
    		public void devilRightOnBoat (){
    			obj.devilRightOnBoat ();
    		}
    	}
    }
    
    public class Controller : MonoBehaviour {
    
    	// Use this for initialization
    	void Start () {
    		SSDirector s1 = SSDirector.getInstance ();
    	}
    	
    	// Update is called once per frame
    	void Update () {
    		
    	}
    }
    
  • 效果演示



本博客所有代码请查看GitHub:项目传送门


转载:https://blog.csdn.net/gzx1002/article/details/100824430
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场