Unity3D学习之打飞碟游戏
生活随笔
收集整理的這篇文章主要介紹了
Unity3D学习之打飞碟游戏
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
首先,先上設計圖:
效果圖:
預設設置:
簡單說一下設計思路。對于飛碟的運動:運動學運動,有點類似牧師惡魔里面的過河;物理運動,則類似射箭小游戲的設計。所以,對于這兩種動作分別實現即可。
運動學實現: public void playDisk(GameObject disk){temp = disk;//隨機選取起始坐標float x = Random.Range(-1.5f, 1.5f);float z = Random.Range(-2f, 2f);Vector3 initialPos = new Vector3(x, -3.7f, z);disk.transform.position = initialPos;//隨機選取發射方向float xEnd = Random.Range(-2f, 2f);float yEnd = Random.Range(6f, 8f);float zEnd = Random.Range(0f, 5f);Vector3 dir = new Vector3(xEnd, yEnd, zEnd);//隨機設置速度float speed = Random.Range(10f,50f);action = MoveToAction.getAction(dir, speed);RunAction(disk, action, this);}//飛碟運動到指定地點后,添加重力,方便其落回地面public void actionDone(SSAction source){if(source == action){temp.GetComponent<Rigidbody>().useGravity = true;}}
物理學實現:
public void playDisk(GameObject disk) {//隨機選取起始坐標float x = Random.Range(-1.5f, 1.5f);float z = Random.Range(0f, 0.5f);Vector3 initialPos = new Vector3(x, -3.7f, z);disk.transform.position = initialPos;//隨機選取發射方向float xEnd = Random.Range(-2f, 2f);float yEnd = Random.Range(6f, 8f);float zEnd = Random.Range(0f, 5f);Vector3 dir = new Vector3(xEnd, yEnd, zEnd);disk.transform.up = dir;disk.GetComponent<Rigidbody>().velocity = dir * speed; //設置速度disk.GetComponent<Rigidbody>().useGravity = true;//Force = UnityEngine.Random.Range(-20, 20); //獲取隨機的風力 //disk.GetComponent<Rigidbody>().AddForce(new Vector3(Force, 0, 0), ForceMode.Force); }接下來,實現飛碟兩種運動的組合:
public void EmitDisk() {if (count - leftTime == 2){count = leftTime;for(int i = 0; i < _diskNum; i++)//第一關,發射一個飛碟每次;第二關發射兩個飛碟每次{GameObject disk = factory.getDisk();//從飛碟工廠得到飛碟Debug.Log(disk);usedDisk.Add(disk);//飛碟進入場景disk.SetActive(true);disk.GetComponent<Renderer>().material.color = _color;disk.transform.localScale = _scale;if (mode == 1)iactionmanager.Normalplay(disk);//讓普通動作管理者設計軌跡elseiactionmanager.Physicplay(disk);//物理運動管理者設計}mode = 3 - mode;//更換下一次運動模式} }public class IActionManager : MonoBehaviour {public PhysicActionManager physicaction;public CCActionManager ccaction;void Awake(){physicaction = Singleton<PhysicActionManager>.Instance;ccaction = Singleton<CCActionManager>.Instance;}public void Normalplay(GameObject disk){ccaction.playDisk(disk);}public void Physicplay(GameObject disk){physicaction.playDisk(disk);} }這樣,就完成了兩種運動的組合。接下來,就是計分。因為兩種運動,在其完成之前,我都添加了重力。所以,飛碟都會下落。因此,飛碟落地則會扣分;若未落地被擊中,則會得分:
public void RecycleDisk()//檢查需不需要回收飛碟 {for (int i = 0; i < usedDisk.Count; i++){if (usedDisk[i].activeInHierarchy == false ){if (usedDisk[i].transform.position.y <= -2)_judge.failAdisk();//失分usedDisk[i].GetComponent<Rigidbody>().useGravity = false;factory.free(usedDisk[i]);//讓飛碟工廠回收usedDisk.Remove(usedDisk[i]);//移除}} }public void shoot() {if (Input.GetMouseButtonDown(0) && (state == State.START || state == State.CONTINUE)){Debug.Log("shoot");Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);RaycastHit hit;if (Physics.Raycast(ray, out hit)){hit.transform.gameObject.SetActive(false);_judge.scoreADisk();//得分}} } //************************* void Update() {RecycleDisk(); }接著,完善細節就可以完成整個游戲了。
附上完整代碼
Singleton.cs
using System.Collections; using System.Collections.Generic; using UnityEngine;public class Singleton<T> : MonoBehaviour where T : MonoBehaviour {protected static T instance;public static T Instance{get{if (instance == null){instance = (T)FindObjectOfType(typeof(T));if (instance == null){Debug.LogError("An instance of" + typeof(T) +"is need in the scene, but there is none.");}}return instance;}} }UserInterface.cs
using System.Collections; using System.Collections.Generic; using UnityEngine;public class UserInterface : MonoBehaviour {private IUserAction action;float width, height;// Use this for initializationvoid Awake(){Debug.Log("UserInterface");}void Start(){Debug.Log("UserInterface");action = Singleton<SceneController>.Instance as IUserAction;}float castw(float scale){return (Screen.width - width) / scale;}float casth(float scale){return (Screen.height - height) / scale;}void OnGUI(){width = Screen.width / 12;height = Screen.height / 12;//倒計時GUI.Label(new Rect(castw(2f) + 20, casth(6f) - 20, 50, 50), Singleton<SceneController>.Instance.leftTime.ToString());//分數GUI.Button(new Rect(castw(2f) +400, casth(6f) -20, 80, 30),"分數"+ Singleton<Judge>.Instance.getPoint().ToString());GUI.Button(new Rect(castw(2f) + 400, casth(6f) -60, 80, 30), "關卡" + Singleton<RoundController>.Instance.getRound().ToString());if (Singleton<SceneController>.Instance.state != State.WIN && Singleton<SceneController>.Instance.state != State.LOSE&& GUI.Button(new Rect(10, 10, 80, 30), Singleton<SceneController>.Instance.countDownTitle)){if (Singleton<SceneController>.Instance.countDownTitle == "Start"){Debug.Log(Singleton<SceneController>.Instance.state);action.Resume();//用戶繼續Debug.Log(Singleton<SceneController>.Instance.state);Singleton<SceneController>.Instance.countDownTitle = "Pause";Singleton<SceneController>.Instance.onCountDown = true;StartCoroutine(Singleton<SceneController>.Instance.WaitFourSecond());}else{Debug.Log(Singleton<SceneController>.Instance.state);action.Pause();//用戶暫停Debug.Log(Singleton<SceneController>.Instance.state);Singleton<SceneController>.Instance.countDownTitle = "Start";Singleton<SceneController>.Instance.onCountDown = false;StopAllCoroutines();}}if (Singleton<SceneController>.Instance.state == State.WIN)//勝利{StopAllCoroutines();if (GUI.Button(new Rect(castw(2f), casth(6f), width+20, height), "Win!")){action.Restart();}}else if (Singleton<SceneController>.Instance.state == State.LOSE)//失敗{StopAllCoroutines();if (GUI.Button(new Rect(castw(2f), casth(6f), width+20, height), "Lose!")){action.Restart();}}}}SceneController.cs
using System; using System.Collections; using System.Collections.Generic; using UnityEngine; /*** 所有的分數通過調用Judge實現* 所有的關卡控制通過RoudController實現* 所有的動作通過IActionManger實現* SceneControler負責調度,實現加載場景,暫停,重新開始等* */ public enum State { WIN, LOSE, PAUSE, CONTINUE, START }; public interface IUserAction {void EmitDisk();//射擊void Pause();//用戶選擇暫停游戲void Resume();//繼續void Restart();//重來 }public class SceneController : MonoBehaviour, IUserAction {public Camera camera;public Color _color;public Vector3 _scale;public int _diskNum;public GameObject bullet;public static Judge _judge;public DiskFactory factory;public IActionManager iactionmanager;public RoundController roundcontroller;public Director director;public State state { get; set; }//游戲狀態//計時器, 每關60秒倒計時public int totalTime;public int leftTime;public bool onCountDown = false;public string countDownTitle = "Start";public int count; //用來計數,每4秒自動發射一次飛碟public int mode;//用于輪流選擇使用普通動作還是物理運動,1是普通,2是物理public static List<GameObject> usedDisk;void Awake(){director = Director.getInstance();director.setFPS(60);state = State.PAUSE;factory = DiskFactory.getInstance();roundcontroller = Singleton<RoundController>.Instance;_judge = Singleton<Judge>.Instance;iactionmanager = Singleton<IActionManager>.Instance;usedDisk = new List<GameObject>();totalTime = 60;countDownTitle = "Start";leftTime = totalTime;count = leftTime;}void Start(){Debug.Log("SceneController");loadScene();mode = 1;}void Update(){if(roundcontroller.getRound() == 3){state = State.WIN;}if(leftTime == 0 && _judge.getPoint() < 100){state = State.LOSE;}EmitDisk();shoot();RecycleDisk();}//********************飛碟的調度*****************//協程 倒計時public IEnumerator WaitFourSecond(){while (leftTime > 0){yield return new WaitForSeconds(1f);leftTime--;}}//設置飛碟屬性public void setting(Color color, Vector3 scale, int diskNum){_color = color;_scale = scale;_diskNum = diskNum;}//飛碟發射public void EmitDisk(){if (count - leftTime == 2){count = leftTime;for(int i = 0; i < _diskNum; i++)//第一關,發射一個飛碟每次;第二關發射兩個飛碟每次{GameObject disk = factory.getDisk();//從飛碟工廠得到飛碟Debug.Log(disk);usedDisk.Add(disk);//飛碟進入場景disk.SetActive(true);disk.GetComponent<Renderer>().material.color = _color;disk.transform.localScale = _scale;if (mode == 1)iactionmanager.Normalplay(disk);//讓普通動作管理者設計軌跡elseiactionmanager.Physicplay(disk);//物理運動管理者設計}mode = 3 - mode;//更換下一次運動模式}}//飛碟回收//只回收落地飛碟//利用事件觸發解決//在飛碟的腳本里實現具體回收public void RecycleDisk()//檢查需不需要回收飛碟{for (int i = 0; i < usedDisk.Count; i++){if (usedDisk[i].activeInHierarchy == false ){if (usedDisk[i].transform.position.y <= -2)_judge.failAdisk();usedDisk[i].GetComponent<Rigidbody>().useGravity = false;factory.free(usedDisk[i]);//讓飛碟工廠回收usedDisk.Remove(usedDisk[i]);//移除}}}//用戶在游戲狀態為開始或者繼續時,才能左鍵射擊,返回射擊的對象public void shoot(){if (Input.GetMouseButtonDown(0) && (state == State.START || state == State.CONTINUE)){Debug.Log("shoot");Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);RaycastHit hit;if (Physics.Raycast(ray, out hit)){hit.transform.gameObject.SetActive(false);_judge.scoreADisk();}}}//********************加載場景*********************//加載場景public void loadScene(){Instantiate(Resources.Load("Plane"), new Vector3(0, -4, 0), Quaternion.identity);}//********************游戲控制****************//暫停public void Pause(){state = State.PAUSE;for (int i = 0; i < usedDisk.Count; i++){usedDisk[i].SetActive(false);//暫停后飛碟不可見;通過DiskFactory實現}}//繼續public void Resume(){state = State.CONTINUE;for (int i = 0; i < usedDisk.Count; i++){usedDisk[i].SetActive(true);//恢復后飛碟可見}}//重新開始public void Restart(){_judge.ResetPoint();//Judge實現,分數清零roundcontroller.setRound(0);roundcontroller.nextRound();state = State.START;}public void setTime(){totalTime = 60;countDownTitle = "Start";leftTime = totalTime;count = leftTime;} }RoundController.cs
using System.Collections; using System.Collections.Generic; using UnityEngine;public class RoundController : MonoBehaviour {public SceneController scene;int round;// Use this for initializationvoid Start(){scene = Singleton<SceneController>.Instance;round = 0;}//下一個關卡public void nextRound(){scene.setTime();round++;loadRound(round);}//設置關卡public void setRound(int round){this.round = round;}//獲取關卡public int getRound(){return round;}//轉換關卡public void loadRound(int round){float r, g, b;Color color;Vector3 scale;float d;//飛碟的直徑r = Random.Range(0f, 0.1f);g = Random.Range(0f, 0.1f);b = Random.Range(0f, 0.1f);color = new Color(r, g, b);d = Random.Range(2.1f, 3.0f);scale = new Vector3(d, 0.01f, d);switch (round){case 1:scene.setting(color, scale, 1);break;case 2:scene.setting(color, scale, 2);break;}} }Judge.cs
using System.Collections; using System.Collections.Generic; using UnityEngine;public class Judge : MonoBehaviour {public int point;public int oneDiskPoint;private RoundController roundcontroller;private SceneController scene;void Awake(){point = 0;oneDiskPoint = 10;roundcontroller = Singleton<RoundController>.Instance;}//默認開始第一關void Start(){roundcontroller.nextRound();}void Update(){if(point == 100){roundcontroller.nextRound();point = 0;}}//*************************游戲分數***************//擊中飛碟得分public void scoreADisk(){point += oneDiskPoint;}//掉落飛碟失去分數public void failAdisk(){point -= oneDiskPoint;}//獲取分數public int getPoint(){return point;}//***********************游戲控制輔助函數***************public void ResetPoint(){point = 0;} }CCActionManager.cs
using System.Collections.Generic; using UnityEngine;public interface ISSActionCallback {void actionDone(SSAction source); }public class SSAction : ScriptableObject {public bool enable = true;public bool destroy = false;public GameObject gameObject { get; set; }public Transform transform { get; set; }public ISSActionCallback callback { get; set; }public virtual void Start(){throw new System.NotImplementedException();}public virtual void Update(){throw new System.NotImplementedException();} }public class MoveToAction : SSAction {public Vector3 target;public float speed;private MoveToAction() { }public static MoveToAction getAction(Vector3 target, float speed){MoveToAction action = ScriptableObject.CreateInstance<MoveToAction>();action.target = target;action.speed = speed;return action;}public override void Update(){this.transform.position = Vector3.MoveTowards(this.transform.position, target, speed * Time.deltaTime);if (this.transform.position == target){this.destroy = true;this.callback.actionDone(this);}}public override void Start() { }}public class SequenceAction : SSAction, ISSActionCallback {public List<SSAction> sequence;public int repeat = -1; //-1表示無限循環,0表示只執行一遍,repeat> 0 表示重復repeat遍public int currentAction = 0;//當前動作列表里,執行到的動作序號public static SequenceAction getAction(int repeat, int currentActionIndex, List<SSAction> sequence){SequenceAction action = ScriptableObject.CreateInstance<SequenceAction>();action.sequence = sequence;action.repeat = repeat;action.currentAction = currentActionIndex;return action;}public override void Update(){if (sequence.Count == 0) return;if (currentAction < sequence.Count){sequence[currentAction].Update();}}public void actionDone(SSAction source){source.destroy = false;this.currentAction++;if (this.currentAction >= sequence.Count){this.currentAction = 0;if (repeat > 0) repeat--;if (repeat == 0){this.destroy = true;this.callback.actionDone(this);}}}public override void Start(){foreach (SSAction action in sequence){action.gameObject = this.gameObject;action.transform = this.transform;action.callback = this;action.Start();}}void OnDestroy(){foreach (SSAction action in sequence){DestroyObject(action);}} }public class SSActionManager : MonoBehaviour {private Dictionary<int, SSAction> actions = new Dictionary<int, SSAction>();private List<SSAction> waitingToAdd = new List<SSAction>();private List<int> watingToDelete = new List<int>();protected void Update(){foreach (SSAction ac in waitingToAdd){actions[ac.GetInstanceID()] = ac;}waitingToAdd.Clear();foreach (KeyValuePair<int, SSAction> kv in actions){SSAction ac = kv.Value;if (ac.destroy){watingToDelete.Add(ac.GetInstanceID());}else if (ac.enable){ac.Update();}}foreach (int key in watingToDelete){SSAction ac = actions[key];actions.Remove(key);DestroyObject(ac);}watingToDelete.Clear();}public void RunAction(GameObject gameObject, SSAction action, ISSActionCallback whoToNotify){action.gameObject = gameObject;action.transform = gameObject.transform;action.callback = whoToNotify;waitingToAdd.Add(action);action.Start();}}public class CCActionManager : SSActionManager, ISSActionCallback {public RoundController scene;public MoveToAction action;public SequenceAction saction;float speed;private GameObject temp;public void playDisk(GameObject disk){temp = disk;//隨機選取起始坐標float x = Random.Range(-1.5f, 1.5f);float z = Random.Range(-2f, 2f);Vector3 initialPos = new Vector3(x, -3.7f, z);disk.transform.position = initialPos;//隨機選取發射方向float xEnd = Random.Range(-2f, 2f);float yEnd = Random.Range(6f, 8f);float zEnd = Random.Range(0f, 5f);Vector3 dir = new Vector3(xEnd, yEnd, zEnd);//隨機設置速度float speed = Random.Range(10f,50f);action = MoveToAction.getAction(dir, speed);RunAction(disk, action, this);}protected void Start(){Debug.Log("CCactionmanger");}protected new void Update(){base.Update();}public void actionDone(SSAction source){if(source == action){temp.GetComponent<Rigidbody>().useGravity = true;}} }PhysicActionManager.cs
using System.Collections; using System.Collections.Generic; using UnityEngine;public class PhysicActionManager : MonoBehaviour {public RoundController scene;//public MoveToAction action1, action2;//public SequenceAction saction;private float speed = 5.0f;//初速//private float Force = 0f; //風力public void playDisk(GameObject disk){//隨機選取起始坐標float x = Random.Range(-1.5f, 1.5f);float z = Random.Range(0f, 0.5f);Vector3 initialPos = new Vector3(x, -3.7f, z);disk.transform.position = initialPos;//隨機選取發射方向float xEnd = Random.Range(-2f, 2f);float yEnd = Random.Range(6f, 8f);float zEnd = Random.Range(0f, 5f);Vector3 dir = new Vector3(xEnd, yEnd, zEnd);disk.transform.up = dir;disk.GetComponent<Rigidbody>().velocity = dir * speed; //設置速度disk.GetComponent<Rigidbody>().useGravity = true;} }IActionManager.cs
using System.Collections; using System.Collections.Generic; using UnityEngine;public class IActionManager : MonoBehaviour {public PhysicActionManager physicaction;public CCActionManager ccaction;void Awake(){physicaction = Singleton<PhysicActionManager>.Instance;ccaction = Singleton<CCActionManager>.Instance;}public void Normalplay(GameObject disk){ccaction.playDisk(disk);}public void Physicplay(GameObject disk){physicaction.playDisk(disk);} }DiskFactory.cs
using System; using System.Collections.Generic; using UnityEngine; /*** 儲存和free飛碟 * */ public class DiskFactory : System.Object {private static DiskFactory _instance;private static List<GameObject> unused;//飛碟隊列private static GameObject gameobject;public static DiskFactory getInstance(){if (_instance == null){_instance = new DiskFactory();unused = new List<GameObject>();}return _instance;}//獲取飛碟public GameObject getDisk(){if (unused.Count == 0){gameobject = GameObject.Instantiate(Resources.Load("Cylinder"), new Vector3(0, 0, 0), Quaternion.identity) as GameObject;gameobject.transform.Rotate(80f, 0, 0);return gameobject;}elsereturn unused[0];}//free飛碟public void free(GameObject obj){unused.Add(obj);} }Director.cs
using System; using System.Collections; using System.Collections.Generic; using UnityEngine;public class Director : System.Object {public static Director _instance;public IUserAction currentScenceController { get; set; }public bool running { get; set; }public static Director getInstance(){if (_instance == null){_instance = new Director();}return _instance;}public int getFPS(){return Application.targetFrameRate;}public void setFPS(int fps){Application.targetFrameRate = fps;}以上就是本次游戲的所有內容,希望對大家有所幫助。
總結
以上是生活随笔為你收集整理的Unity3D学习之打飞碟游戏的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【游戏开发】unity教程4 打飞碟小游
- 下一篇: 3d学习笔记(四)——打飞碟小游戏