Unity3DGame学习笔记:飞碟修改(homework6)

修改说明:

本次修改主要是增加接口IActionManager,并由CCActionManager和PhysicsActionManager分别实现接口,控制飞碟的运动学发射和物理发射

UML图:


UserGUI类:

Update函数中检测鼠标的点击,键盘z和空格输入,分别对应飞碟的点击,以运动学方式发射飞碟和以物理方式发射飞碟

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class UserGUI : MonoBehaviour {
	SceneController MySceneController;

	void Start () {
		if (MySceneController == null) {
			MySceneController = (SceneController)FindObjectOfType (typeof(SceneController));
		}
	}

	void Update() {
		Vector3 mp = new Vector3 ();
		if (Input.GetButtonDown ("Fire1")) {
			mp = Input.mousePosition;

			Camera ca = GetComponent<Camera> ();
			Ray ray = ca.ScreenPointToRay (Input.mousePosition);

			RaycastHit hit;
			//ignore the object whose value of layer is 1
			if (Physics.Raycast (ray, out hit, Mathf.Infinity, 1)) {
				if (hit.collider.gameObject.tag.Contains ("Disk")) {
					Debug.Log (hit.collider.gameObject.name);
					MySceneController.hitTheDisk (hit.collider.gameObject);
				}
			}
		}

		//press space to use PhysicsActionManager to send a disk
		if (Input.GetKeyDown ("space")) {
			Debug.Log ("space down!");
			MySceneController.setSendWay (1);
			if (MySceneController.myFactory.Used_list.Count == 0 && MySceneController.num_send<= 5) {
				MySceneController.sendDisk ();
				Debug.Log ("sendDisk");
			}
		}
		//press z to use CCActionManager to send a disk
		if (Input.GetKeyDown ("z")) {
			Debug.Log ("z down!");
			MySceneController.setSendWay (2);
			if (MySceneController.myFactory.Used_list.Count == 0 && MySceneController.num_send<= 5) {
				MySceneController.sendDisk ();
				Debug.Log ("sendDisk");
			}
		}
	}

	void OnGUI () {
		GUIStyle fontStyle = new GUIStyle();
		fontStyle.normal.textColor = new Color(223, 112, 62);
		fontStyle.fontSize = 30;

		GUIStyle fontStyle2 = new GUIStyle ();
		fontStyle2.fontSize = 20;

		//showing the round and score
		GUI.Label (new Rect (10, 10, 300, 100), "Round" + MySceneController.getRound (), fontStyle);
		GUI.Label (new Rect (200, 10, 300, 100), "Your Score: " + MySceneController.getScore (), fontStyle);
		if (MySceneController.getUserListCount () == 0 && MySceneController.getGameState () == 1) {
			GUI.Label (new Rect (200, 200, 500, 100), "Please press space or z to send a disk", fontStyle);
		}

		//restart
		if (MySceneController.getGameState () == 0) {
			GUI.Label (new Rect (250, 200, 500, 100), "Your Final Score: " + MySceneController.getScore (), fontStyle);
			if (GUI.Button (new Rect (300, 250, 100, 50), "Restart Game")) {
				MySceneController.Restart ();
			}
		}
		GUI.Button(new Rect(800, 10, 30, 30), "q?");
		if (Input.GetKey("q")) {
			//show the rule
			GUI.Label (new Rect (600, 10, 160, 300), "Rules: There are two rounds, each round has 5 disks to be shoot, after that you will get your final score");
		}
	}
}
SceneController类:

用一个int变量sendWay保存当前发射飞碟的方式,在sendDisk()函数调用时根据该变量的值调用相应的动作管理类进行飞碟的发射

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SceneController : MonoBehaviour {
	public RoundController roundController;
	public ScoreController scoreController;
	public DiskFactory myFactory;
	public GameObject camera;
	//1 for playing and 0 for over
	private int GameState;
	//record the number of disks sent
	public int num_send;

	private int sendWay; //1 for PhysicsActionManager , 2 for CCActionManager
	public IActionManager iActionManager;
	public CCActionManager ccActionManager;
	public PhysicsActionManager pActionManager;

	void Start() {
		init_controller ();
		init_myFactory ();
		loadResource ();

		if (ccActionManager == null) {
			ccActionManager = (CCActionManager)FindObjectOfType (typeof(CCActionManager));
		}
		if (pActionManager == null) {
			pActionManager = (PhysicsActionManager)FindObjectOfType (typeof(PhysicsActionManager));
		}
	}

	void Update() {
		myFactory.recycleDisk ();
		roundCheck ();
	}

	public void sendDisk() {
		if (GameState == 1 && sendWay == 1) {
			//pass the information to PhysicsActionManager
			iActionManager = pActionManager;
			GameObject disk = myFactory.getDisk ();
			pActionManager.setGameObject (disk);
			myFactory.Used_list.Add (disk);
			pActionManager.setSpeed (roundController.speed);
			pActionManager.setSize (roundController.size);
			pActionManager.setColor (roundController.color);
			pActionManager.setAngle (roundController.angle);

			iActionManager.playDisk ();
		}
		else if (GameState == 1 && sendWay == 2) {
			//pass the information to CCAtionManager
			iActionManager = ccActionManager;
			GameObject disk = myFactory.getDisk ();
			ccActionManager.setGameObject (disk);
			myFactory.Used_list.Add (disk);
			ccActionManager.setSpeed (roundController.speed);
			ccActionManager.setSize (roundController.size);
			Debug.Log ("roundController speed is " + roundController.speed);
			ccActionManager.setColor (roundController.color);

			iActionManager.playDisk ();
		}
		num_send++;
	}

	public void setSendWay(int i) {
		sendWay = i;
	}

	//initial
	public void loadResource() {
		myFactory.plane = GameObject.Instantiate (Resources.Load ("Prefabs/Plane")) as GameObject;
		myFactory.plane.GetComponent <Renderer> ().material.color = roundController.plane_color;
		myFactory.plane.layer = 2;
		num_send = 0;
		GameState = 1;
		roundController.round = 1;
		scoreController.score = 0;
	}

	public void init_controller() {
		if (roundController == null) {
			roundController = RoundController.getInstance();
		}
		if (scoreController == null) {
			scoreController= ScoreController.getInstance();
		}
	}

	public void init_myFactory() {
		if (myFactory == null) {
			myFactory = new DiskFactory ();
		}
	}

	public void roundCheck() {
		int result = roundController.roundCheck (num_send, myFactory, GameState, myFactory.Used_list.Count);
		if (result == 0) {
			num_send = 0;
		}
		else if (result == 1) {
			num_send = 0;
			GameState = 0;
		}
	}

	public int getRound() { return roundController.getRound ();}
	public int getScore() { return scoreController.getScore ();}
	public int getUserListCount() { return myFactory.Used_list.Count;}
	public int getGameState() { return GameState;}

	//hit the disk and add score
	public void hitTheDisk(GameObject obj) {
		myFactory.hitTheDisk (obj);
		scoreController.AddScore (roundController.getRound ());
	}

	//reset some data
	public void Restart() {
		num_send = 0;
		GameState = 1;
		roundController.round = 1;
		scoreController.score = 0;
	}
}
RoundController类:

控制关卡的切换并保存当前关卡的一些属性

public class RoundController  {
	public static RoundController _instance;
	public int round;
	public Color color;
	public Color plane_color;
	public float size;
	public float speed;
	public float angle;

	public static RoundController getInstance() {
		if (_instance == null) {
			_instance = new RoundController();
			if (_instance == null) {
				Debug.Log ("An instance of RoundController is needed");
			}
		}
		return _instance;
	}

	public int getRound() {return round;}

	public void loadRoundData() {
		switch (round) 
		{
		//the property of round 1
		case 1:
			color = Color.green;
			size = 2f;
			speed = 1f;
			angle = 4f;
			plane_color = Color.white;
			break;
		//the property of round 2
		case 2:
			color = Color.red;
			size = 1.3f;
			speed = 1.5f;
			angle = 8f;
			plane_color = Color.blue;
			break;
		}
	}

	public int roundCheck(int num_send, DiskFactory myFactory, int GameState, int count) {
		loadRoundData ();
		if (num_send >= 5 && getRound () == 1 && count == 0) { //round 1 is over
			round = 2;
			myFactory.plane.GetComponent <Renderer> ().material.color = plane_color;
			return 0;
} else if (num_send >= 5 && getRound() == 2 && count == 0) { //round 2 is over return 1; } return 2; } }

ScoreController类:

根据当前的关卡值在每次击中飞碟时进行相应的加分

public class ScoreController {
	public static ScoreController _instance;
	public int score;

	public static ScoreController getInstance() {
		if (_instance == null) {
			_instance = new ScoreController();
			if (_instance == null) {
				Debug.Log ("An instance of ScoreController is needed");
			}
		}
		return _instance;
	}

	public int getScore() {return score;}

	public void AddScore(int round) {
		if (round == 1) {
			score += 10;
		}
		else if (round == 2) {
			score += 20;
		}
	}
}


IActionManager类:

定义一个动作管理类的接口

public interface IActionManager {
	void playDisk();
}

CCActionManager类:

实现以运动学方式发射飞碟,由于只有一个发射飞碟的动作,因此直接在该类中实现具体操作

该类中保存了当前要发射的飞碟应该具有的属性,在playDisk()函数中改变飞碟的有关属性并发射

public class CCActionManager : MonoBehaviour, IActionManager {
	private GameObject disk;
	//the information of sending a disk
	private float speed;
	private Color color;
	private float size;
	private Vector3 send_position;
	public Vector3 target = new Vector3 (0, 0, 20);
	private bool move = false;

	public void playDisk() {
		move = true;
		disk.GetComponent <Renderer> ().material.color = color;
		disk.transform.localScale = new Vector3(1.5f * size, 0.1f * size, 1.5f * size);
		//initial a random position to send a disk
		send_position = new Vector3 (Random.Range (-8f, 8f), Random.Range (5f, 7f), -12f);
		disk.SetActive (true);
		disk.transform.position = send_position;
	}

	void Update() {
		if (disk != null) {
			if (move && disk.transform.position != target) {
				//move the disk to target
				disk.transform.position = Vector3.MoveTowards (disk.transform.position, target, speed/ 3);
			}
			//the disk reach the target, stop moving
			if (disk.transform.position == target) {
				disk.SetActive (false);
				move = false;
			}
		}
	}

	public void setGameObject(GameObject obj) {
		disk = obj;
	}

	public void setSpeed(float sp) {
		speed = sp;
	}

	public void setColor(Color c) {
		color = c;
	}

	public void setSize(float s) {
		size = s;
	}
}

PhysicsActionManager类:

与CCActionManager大致相同,但在发射飞碟前为其添加刚体属性,通过生成一个方向和添加一个冲力使其以物理形式发射飞碟

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PhysicsActionManager : MonoBehaviour, IActionManager {
	private GameObject disk;
	private float speed;
	private Color color;
	private float size;
	private float angle;
	private Vector3 send_position;
	public Vector3 target = new Vector3 (0, 0, 20);
	private bool move = false;

	public void playDisk() {
		disk.GetComponent <Renderer> ().material.color = color;
		disk.transform.localScale = new Vector3(1.5f * size, 0.1f * size, 1.5f * size);
		//initial a random position to send a disk
		Vector3 send_position = new Vector3 (Random.Range (-8f, 8f), Random.Range (5f, 7f), -12f);
		//initial a random direction of sending a disk
		Vector3 direction = new Vector3 (Random.Range (-angle, angle), 2f, 20f * speed);
		disk.transform.position = send_position;
		disk.transform.rotation = Quaternion.identity;
		disk.SetActive (true);
		disk.AddComponent<Rigidbody> ();
		disk.GetComponent<Rigidbody> ().AddForce (direction, ForceMode.Impulse);
	}

	public void setGameObject(GameObject obj) {
		disk = obj;
	}

	public void setSpeed(float sp) {
		speed = sp;
	}

	public void setColor(Color c) {
		color = c;
	}

	public void setSize(float s) {
		size = s;
	}

	public void setAngle(float a) {
		angle = a;
	}
}


DiskFactory类:

该类中主要是实现用List存放未使用和正在使用的飞碟,以及对正在使用的飞碟进行检测以便飞碟击中时灭活以及飞碟的回收

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class DiskFactory {

	public List<GameObject> Used_list = new List<GameObject> ();
	public List<GameObject> Free_list = new List<GameObject> ();

	Vector3 init_position = new Vector3(0, 5, -12);

	public GameObject plane;

	public GameObject getDisk() {
		//get a disk from the Free_list
		if (Free_list.Count != 0) {
			return Free_list [0];
		}
		//get a new disk
		else {
			GameObject new_one = GameObject.Instantiate (Resources.Load ("Prefabs/Disk")) as GameObject;
			Free_list.Add (new_one);
			return Free_list [0];
		}
	}

	public void hitTheDisk(GameObject obj) {
		obj.transform.position = init_position;
		obj.SetActive (false);
		Debug.Log ("hit the disk");
	}

	public void recycleDisk() {
		for (int i = 0; i < Used_list.Count; i++) {
			//recycle the disk be hit
			if (!Used_list [i].activeInHierarchy) {
				Free_list.Add (Used_list [i]);
				if (Used_list [i].GetComponent<Rigidbody> () != null) {
					Used_list [i].GetComponent<DiskScript> ().destroyRigidBody ();
				}
				Used_list.RemoveAt (i);
			} 
			//recycle the disk not be hit but fall to ground
			else if (Used_list [i].transform.position.y <= 0.1f) {
				Used_list [i].SetActive (false);
				if (Used_list [i].GetComponent<Rigidbody> () != null) {
					Used_list [i].GetComponent<DiskScript> ().destroyRigidBody ();
				}
				Free_list.Add (Used_list [i]);
				Used_list.RemoveAt (i);
				Debug.Log ("low");
			}
		}
	}
}


DiskScript类:

每个根据预设生成的Disk上都挂有该脚本,这次该脚本的功能较少,只提供了删除Disk刚体属性的函数

public class DiskScript : MonoBehaviour {

	public void destroyRigidBody() {
		Destroy (this.GetComponent<Rigidbody> ());
	}
		
}


效果图如下:


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值