Unity3d-打飞碟工厂模式
Unity3d打飛碟學習記錄
花了九牛二虎之力,終于完成了打飛碟的游戲,寫個博客記錄一下。
游戲涉及的類:
DiskData();飛碟數據
DiskFactory();飛碟的生產和銷毀的工廠類;
RoundActionManager();動作管理類;
RoundController();場景控制類;
ScoreRecorder();分數記錄;
SSDirector();導演類;
UserGUI();用戶交互類;
類的解析:
關于導演類和用戶交互類我就不做過多解釋了,畢竟都是老師上課的代碼和之前的一些模板。
動作管理類
我們就從動作管理類中的管理實例RoundActionManager()開始解析:
public class RoundActionManager : SSActionManager, ISSActionCallback {public RoundController scene;public MoveToAction action1, action2;public SequenceAction saction;float speed;public void addRandomAction(GameObject gameObj){int[] X = { -20, 20 };int[] Y = { -5, 5 };int[] Z = { -20, -20 };// 隨機生成起始點和終點Vector3 starttPos = new Vector3(UnityEngine.Random.Range(-20, 20),UnityEngine.Random.Range(-5, 5),UnityEngine.Random.Range(50, 10));gameObj.transform.position = starttPos;Vector3 randomTarget = new Vector3(X[UnityEngine.Random.Range(0, 2)],Y[UnityEngine.Random.Range(0, 2)],Z[UnityEngine.Random.Range(0, 2)]);MoveToAction action = MoveToAction.getAction(randomTarget, gameObj.GetComponent<DiskData>().speed);RunAction(gameObj, action, this);}protected void Start(){scene = (RoundController)SSDirector.getInstance().currentScenceController;scene.actionManager = this;}protected new void Update(){base.Update();}public void actionDone(SSAction source){Debug.Log("Done");} }在這個類中唯一值得注意的函數是addRandomAction(),該函數設置了起點和終點的坐標,然后就像是牧師與魔鬼動作分離版 中的船的動作從起點到終點一樣設置飛碟的運動軌跡,沒有拋物線,只因本人太菜不懂怎么設計。
飛碟數據類:
using System.Collections; using System.Collections.Generic; using UnityEngine;public class DiskData : MonoBehaviour {public float size;public Color color;public float speed; }沒什么好說的,就是給飛碟設置必要時可以改變的屬性。
飛碟工廠類:
using System.Collections; using System.Collections.Generic; using UnityEngine;public class DiskFactory : MonoBehaviour {private List<GameObject> used = new List<GameObject>();//存儲正在使用的飛碟private List<GameObject> free = new List<GameObject>();//存儲使用完了被回收的飛碟//顏色數組用于隨機分配顏色private Color[] color = { Color.red, Color.green, Color.blue, Color.yellow };//生產飛碟,先從回收部分取,若回收的部分為空,才從資源加載新的飛碟public GameObject GetDisk(int ruler){GameObject a_disk;if (free.Count > 0){a_disk = free[0];free.Remove(free[0]);}else{a_disk = GameObject.Instantiate(Resources.Load("prefabs/Disk")) as GameObject;Debug.Log(a_disk);}a_disk.GetComponent<DiskData>().size = UnityEngine.Random.Range(0, 7-ruler);a_disk.GetComponent<DiskData>().color = color[UnityEngine.Random.Range(0, 4)];a_disk.GetComponent<DiskData>().speed = UnityEngine.Random.Range(10+ruler, 18+ruler);a_disk.transform.localScale = new Vector3(a_disk.GetComponent<DiskData>().size * 2, a_disk.GetComponent<DiskData>().size * 0.1f, a_disk.GetComponent<DiskData>().size * 2);a_disk.GetComponent<Renderer>().material.color = a_disk.GetComponent<DiskData>().color;a_disk.SetActive(true);used.Add(a_disk);return a_disk;}//回收飛碟public void FreeDisk(GameObject disk){for(int i = 0; i < used.Count; i++){if(used[i] == disk){disk.SetActive(false);used.Remove(used[i]);free.Add(disk);}}} }采用兩個鏈表分別表示生產的飛碟庫和回收的飛碟庫,在生產飛碟時先判斷回收庫中是否有可利用的飛碟,若有,則重新利用飛碟,若沒有則生產新的飛碟。回收飛碟時,在生產庫中刪除飛碟,然后將該飛碟的數據添加到回收庫中循環利用。
分數記錄類:
using System.Collections; using System.Collections.Generic; using UnityEngine;public class ScoreRecorder : MonoBehaviour {private float score;public float getScore(){return score;}public void Record(GameObject disk){//size越小、速度越快,分越高score += (100 - disk.GetComponent<DiskData>().size *(20 - disk.GetComponent<DiskData>().speed));//根據顏色加分Color c = disk.GetComponent<DiskData>().color;switch (c.ToString()){case "red":score += 50;break;case "green":score += 40;break;case "blue":score += 30;break;case "yellow":score += 10;break;}}public void Reset(){score = 0;} }這個也沒什么好說的,記錄擊中的飛碟類型給予相應的分數。關鍵是這個給分也是隨機的,會根據飛碟的速度和大小對應相應分數。
場景當單實例模板:
using System.Collections; using System.Collections.Generic; using UnityEngine;public class Singleton<T> where T : MonoBehaviour {private static T instance;public static T Instance{get{if (instance == null){instance = (T)Object.FindObjectOfType(typeof(T));if (instance == null){Debug.LogError("Can't find instance of " + typeof(T));}}return instance;}} }為飛碟工廠,分數以及動作提供實例。
diskFactory = Singleton<DiskFactory>.Instance; scoreRecorder = Singleton<ScoreRecorder>.Instance; actionManager = Singleton<RoundActionManager>.Instance;場景控制類:
重頭戲來了!!!!!
在這個類中,我先實現了在ISceneController接口中定義的函數和枚舉類型:
在Resume和Pause兩個函數中,我是用了協程的知識,簡單來說協程就類似于Python中的掛起,關鍵字是yield。指的是在一個線程內,一個程序中斷去執行另一個程序,有點類似于CPU中斷。這樣減少了切換線程帶來的負擔,同時不需要多線程中的鎖機制,因為不存在同時寫的問題。當程序執行到StopAllCoroutines()函數時,程序執行中斷并掛起,這時執行的yield return語句,停止計時,等到StartCoroutines()時再從當前中斷的地方繼續執行。這就要在StartCoroutines()中加入另一個返回IEnumerator(協程)的函數作為參數:
IEnumerator DoCountDown() {while (leaveSeconds >= 0){if (leaveSeconds >= 60) {GameText.text = (leaveSeconds - 60).ToString ();} else {GameText.text = "";}yield return new WaitForSeconds(1);leaveSeconds--;} }該函數采用秒來跳幀便于計時,在最開始的3秒我用于游戲開始之前的倒數,因此每一回合的游戲時間實際為60秒。每一秒生產一個飛碟。
public void shoot()//用戶在游戲狀態為開始或者繼續時,才能左鍵射擊 {if (Input.GetMouseButtonDown(0) && (state == State.START || state == State.CONTINUE)){Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);RaycastHit hit;if (Physics.Raycast(ray, out hit)){if ((SSDirector.getInstance().currentScenceController.state == State.START || SSDirector.getInstance().currentScenceController.state == State.CONTINUE)){shootAtSth = hit.transform.gameObject;explosion.transform.position = hit.collider.gameObject.transform.position;explosion.GetComponent<Renderer>().material = hit.collider.gameObject.GetComponent<Renderer>().material;explosion.GetComponent<ParticleSystem>().Play();}}} }在這個函數中我采用射線來判斷是否集中飛碟,并設置了爆炸效果。
public void LaunchDisk()//每秒自動發射飛碟{if(count - leaveSeconds== 1){count = leaveSeconds;GameObject disk = diskFactory.GetDisk(round);//從飛碟工廠得到飛碟Debug.Log(disk);disks.Add(disk);//飛碟進入場景actionManager.addRandomAction(disk);//讓動作管理者設計軌跡}}每一秒生產并發射飛碟。
public void RecycleDisk()//檢查需不需要回收飛碟{for(int i = 0; i < disks.Count; i++){if( disks[i].transform.position.z < -18){diskFactory.FreeDisk(disks[i]);//讓飛碟工廠回收disks.Remove(disks[i]);}}}檢查飛碟的回收。
public void Judge()//判斷游戲狀態,是否射中以及夠不夠分數進入下一回合 {if(shootAtSth != null && shootAtSth.transform.tag == "Disk" && shootAtSth.activeInHierarchy)//射中飛碟{scoreRecorder.Record(shootAtSth);//計分diskFactory.FreeDisk(shootAtSth);//回收飛碟shootAtSth = null;//點擊的物體重置為空,避免計分出錯}if(scoreRecorder.getScore() > 500 * round)//每關500分才能進入下一關,重新倒數60秒{round++;leaveSeconds = count = 60;}if (round == 4) {StopAllCoroutines();state = State.WIN;}else if (leaveSeconds == 0 && scoreRecorder.getScore() < 500 * round) //時間到,分數不夠,輸了{StopAllCoroutines();state = State.LOSE;} elsestate = State.CONTINUE;}判斷游戲進程。
在以上每個函數中都有枚舉類型:
用來記錄游戲狀態。
傳送門
總結
以上是生活随笔為你收集整理的Unity3d-打飞碟工厂模式的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: unity实现鼠标打飞碟(Hit UFO
- 下一篇: 3D游戏编程 作业五 枪打恶鬼(打飞碟)