修改说明:
本次修改主要是增加接口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;
}
}
}
定义一个动作管理类的接口
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> ());
}
}
效果图如下: