实验要求:
由于我的原版作业实现运动是用物理运动,所以这次我需要实现运动学运动。
修改说明:
1.增添了接口IActionManager,用于统一调用物理运动和运动学运动。
2.对于物理运动,我增添了PhysicsActionManager来实现物理运动的细节。
3.对于运动学运动,根据课程ActionManager的框架,增添了CCActionManager,SSAction和CCAction来实现运动学运动的细节。
UML图:
完整代码:
1.UserInterface:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class UserInterface : MonoBehaviour {
GameObject cam;
Camera ca;
float time = 0;
public ParticleSystem explosion;
public Text scoreText;
public Text roundText;
//public Text DiskNumText;
public Text TotalScore;
public Text TimeText;
SceneController Controller;
// Use this for initialization
void Awake () {
cam = GameObject.Find ("Camera");
ca = cam.GetComponent<Camera> ();
//explosion = Instantiate (Resources.Load ("Prefabs/explosion")) as ParticleSystem;
Controller = SceneController.getControllerInstance ();
Controller.nextRound ();
}
// Update is called once per frame
void Update () {
if (Input.GetMouseButtonDown (0)) {
Vector3 mp = Input.mousePosition;
Ray ray = ca.ScreenPointToRay (Input.mousePosition);
RaycastHit hit;
if (Physics.Raycast (ray, out hit, Mathf.Infinity) && hit.collider.gameObject.tag == "Disk") {
print ("I hit " + hit.transform.gameObject.name);
hit.collider.gameObject.SetActive (false);
PlayExplosion (hit.collider.gameObject);
Controller.getRecorder ().getScore (hit.collider.gameObject);
}
}
if (Input.GetKeyDown("space")) {
Debug.Log ("Space Down");
if (time <= 0) {
time = 3;
if (Controller.getRound () == 2) {
Controller.emitDisk ();
}
Controller.emitDisk ();
}
}
if (time > 0) {
time -= Time.deltaTime;
TimeText.text = "Next Disk Time : " + (int)(time + 0.5);
} else {
TimeText.text = "Disk Ready!";
}
scoreText.text = "TempScore : " + Controller.getRecorder ().returnScore ();
roundText.text = "Round : " + Controller.getRound ();
TotalScore.text = "TotalScore : " + Controller.getRecorder ().returnTScore ();
}
void PlayExplosion(GameObject t) {
Debug.Log (explosion);
explosion.transform.position = t.transform.position;
explosion.GetComponent<Renderer>().material.color = t.GetComponent<Renderer>().material.color;
explosion.Play ();
}
}
2.SceneController:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SceneController : System.Object {
private static SceneController Controller_instance;
private ScoreRecorder Recorder_instance;
private DiskFactory Factory_instance;
private int RoundNow = 0;
private IActionManager IAction;
private CCActionManager ccAction; //注册一个CCAction
private PhysicsActionManager physicsAction; //注册一个PhysicsAction
private int turn = 1; //用来交替使用物理和运动学动作,1位物理,-1为运动学
Vector3 emitPos = new Vector3(-1.5f, 0.5f, 0.5f);
Vector3 emitDir = new Vector3(10f, 50.0f, 67f);
float emitSpeed = 0.5f;
Color color;
public static SceneController getControllerInstance () {
if (Controller_instance == null) {
Controller_instance = new SceneController();
}
return Controller_instance;
}
public ScoreRecorder getRecorder() {
return Recorder_instance;
}
public void setRecorder(ScoreRecorder R) {
Recorder_instance = R;
}
public DiskFactory getFactory() {
return Factory_instance;
}
public void setFactory(DiskFactory F) {
Factory_instance = F;
}
public void setCCActionManager(CCActionManager ca) {
ccAction = ca;
}
public void emitDisk() {
GameObject temp = Factory_instance.getDisk();
if (temp == null) {
Debug.Log ("No disk, Please wait!");
return;
}
temp.transform.position = emitPos;
if (turn == 1) {
physicsAction = new PhysicsActionManager ();
physicsAction.setPhysicsAction (temp, emitDir, emitSpeed);
turn = -turn;
IAction = physicsAction;
//物理运动
} else if (turn == -1) {
ccAction.setCCAction (temp, emitSpeed);
turn = -turn;
IAction = ccAction;
//运动学运动
}
IAction.playDisk ();
}
public void nextRound() {
Factory_instance.DisableDisk ();
if (RoundNow == 1) {
RoundNow = 2;
} else if (RoundNow == 2) {
RoundNow = 1;
} else {
RoundNow = 1;
}
Round (RoundNow);
}
public void Round(int R) {
Debug.Log ("Round = " + R);
switch(R) {
case 1:
emitPos = new Vector3 (-1.5f, 0.5f, 0.5f);
emitSpeed = 0.5f;
color = Color.green;
Factory_instance.setDisk (color, emitSpeed, 1f, 1);
break;
case 2:
emitPos = new Vector3 (1.5f, 0.5f, 0.5f);
emitSpeed = 0.7f;
color = Color.red;
Factory_instance.setDisk (color, emitSpeed, 0.8f, 2);
break;
}
}
public int getRound() {
return RoundNow;
}
}
3.IActionManager:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public interface IActionManager {
void playDisk();
}
4.CCActionManager:
这个代码结合了课程的CCActionManager和SSActionManager。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CCActionManager : MonoBehaviour ,IActionManager {
private GameObject temp;
private float speed;
private Vector3 target;
private CCAction ccAction;
private Dictionary <int, SSAction> actions = new Dictionary<int, SSAction> ();
private List<SSAction> waitingAdd = new List<SSAction> ();
private List<int> waitingDelete = new List<int> ();
public void Start() {
SceneController.getControllerInstance ().setCCActionManager (this);
}
public void setCCAction(GameObject t, float s) {
temp = t;
speed = s;
target = new Vector3 (-2, 20, 65);//飞碟飞向的目标
}
public void playDisk() {
//if (temp.GetComponent<DiskData> ().getType ())
temp.GetComponent<Rigidbody>().useGravity = false;
ccAction = CCAction.GetSSAction (target, speed);
RunAction (temp, ccAction);
}
protected void Update () {
foreach (SSAction ac in waitingAdd)
actions [ac.GetInstanceID ()] = ac;
waitingAdd.Clear ();
foreach (KeyValuePair <int, SSAction> kv in actions) {
SSAction ac = kv.Value;
if (ac.destory) {
waitingDelete.Add (ac.GetInstanceID ());
} else if (ac.enable) {
//Debug.Log ("This foreach!");
ac.Update();
}
}
foreach (int key in waitingDelete) {
SSAction ac = actions [key];
actions.Remove (key);
DestroyObject (ac);
}
waitingDelete.Clear ();
}
public void RunAction (GameObject gameobject, SSAction action) {
Debug.Log ("RunAction success");
action.gameobject = gameobject;
action.transform = gameobject.transform;
waitingAdd.Add (action);
action.Start ();
}
}
5.SSAction:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SSAction : ScriptableObject {
public bool enable = true;
public bool destory = false;
public GameObject gameobject { get; set; }
public Transform transform{ get; set; }
protected SSAction() {
}
public virtual void Start() {
throw new System.NotImplementedException();
}
public virtual void Update() {
throw new System.NotImplementedException();
}
}
6.CCAction:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CCAction : SSAction {
public Vector3 target;
public float speed;
public static CCAction GetSSAction(Vector3 target, float speed) {
CCAction action = ScriptableObject.CreateInstance<CCAction> ();
action.target = target;
action.speed = speed;
return action;
}
public override void Update() {
this.transform.position = Vector3.MoveTowards (this.transform.position, target, speed);
if (this.transform.position == target) {
this.destory = true;
}
}
public override void Start() {
}
}
7.PhysicsActionManager:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PhysicsActionManager : IActionManager {
GameObject temp;
Vector3 Force;
Vector3 Dir;
float emitSpeed;
public void setPhysicsAction(GameObject t, Vector3 nextDir, float speed) {
emitSpeed = speed;
temp = t;
nextDir.x *= Random.Range (-4f, 4f);
Dir = nextDir;
Force = nextDir * Random.Range (emitSpeed * 5, emitSpeed * 7) / 10;
}
public void playDisk() {
temp.GetComponent<Rigidbody>().AddForce (Force, ForceMode.Impulse);
}
}
8.DiskFactory:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DiskFactory : MonoBehaviour {
private SceneController Controller;
private List<GameObject> Used;
private List<GameObject> Free;
// Use this for initialization
void Awake () {
Used = new List<GameObject> ();
Free = new List<GameObject> ();
Controller = SceneController.getControllerInstance ();
Controller.setFactory (this);
//loadResource ();
}
public void setDisk(Color c, float speed, float size, int t) {
for (int i = 0; i < Free.Count; i++) {
Free [i].GetComponent<DiskData> ().setDisk (c, speed, size, t);
}
for (int i = 0; i < Used.Count; i++) {
Used [i].GetComponent<DiskData> ().setDisk (c, speed, size, t);
}
}
// Update is called once per frame
void Update () {
freeDisk ();
}
public void DisableDisk() {
for (int i = 0; i < Used.Count; i++) {
Used [i].SetActive (false);
}
}
public GameObject getDisk() {
GameObject temp;
if (Free.Count != 0) {
temp = Free [0];
temp.SetActive (true);
Free.RemoveAt (0);
} else {
temp = Instantiate (Resources.Load ("Prefabs/disk")) as GameObject;
DiskData data = temp.GetComponent<DiskData> ();
if (Controller.getRound() == 1)
data.setDisk (Color.green, 0.5f, 1f, 1);
else
data.setDisk (Color.red, 0.7f, 0.8f, 2);
temp.SetActive (true);
}
temp.GetComponent<Rigidbody>().velocity = new Vector3(0, 0, 0);
temp.GetComponent<Rigidbody> ().useGravity = true;
Used.Add (temp);
return temp;
}
void freeDisk() {
int R = Controller.getRound ();
for (int i = 0; i < Used.Count; i++) {
GameObject temp = Used [i];
//Debug.Log (Used [i].transform.position.y);
if (!Used [i].activeInHierarchy) {
temp.SetActive (false);
Used.RemoveAt (i);
Free.Add (temp);
} else if (Used [i].transform.position.y < 0.5f || Used [i].transform.position.z > 60f) {
Controller.getRecorder ().lostScore (temp);
temp.SetActive (false);
Used.RemoveAt (i);
Free.Add (temp);
}
}
}
}
9.DiskData:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DiskData : MonoBehaviour {
Color color;
float speed;
float size;
int DiskType;
public void setDisk(Color c, float sp, float s, int t) {
color = c;
speed = sp;
size = s;
DiskType = t;
Debug.Log (this.name);
this.GetComponent<MeshRenderer>().material.color = c;
Debug.Log ("SetDisk");
this.transform.localScale = new Vector3 (1f * size, 0.1f, 1f * size);
}
public int getType() {
return DiskType;
}
}
10.ScoreRecorder:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ScoreRecorder : MonoBehaviour {
private SceneController Controller;
private int Score;
private int TotalScore;
// Use this for initialization
void Start () {
Score = 0;
TotalScore = 0;
Controller = SceneController.getControllerInstance ();
Controller.setRecorder (this);
}
// Update is called once per frame
void Update () {
}
public void getScore(GameObject d) {
Score += 10 * d.GetComponent<DiskData> ().getType();
Debug.Log (d.GetComponent<DiskData> ().getType ());
TotalScore += 10 * d.GetComponent<DiskData> ().getType();
if (Score >= 100) {
Score = 0;
Controller.nextRound ();
}
Debug.Log (Score);
}
public void lostScore(GameObject d) {
Score -= 10 * d.GetComponent<DiskData> ().getType();
TotalScore -= 10 * d.GetComponent<DiskData> ().getType();
}
public int returnScore() {
return Score;
}
public int returnTScore() {
return TotalScore;
}
}