打靶遊戲:dom
1.靶對象爲 5 環,按環計分;
2.箭對象,射中後要插在靶上;
3.遊戲僅一輪,無限 trials;ide
加強要求:函數
添加一個風向和強度標誌,提升難度優化
遊戲成品圖:this
UML圖:spa
遊戲設計思路&大體過程&核心代碼
遊戲對象主要由三個,靶、弓和箭,射出去的箭能夠複用(利用簡單工廠),將箭從弓的位置加上常力向某個方向射出。最後實現加強功能——添加常力做爲風向而且在界面中顯示出風向(只設置了界面上的左右兩個不一樣方向)以及風力(0~50)。設計
1.首先設置遊戲對象——靶子、弓和箭。
爲了實現識別不一樣的環,經過五個共圓心的圓柱體(高度不一樣——經過設置Transform)來識別箭首先碰到的環(小環厚度較大)。3d
遊戲的弓和箭——剛開始用圓柱體(箭身)+膠囊(箭頭)實現箭,在後來進行界面優化時下載了模型。將模型直接做爲預製便可。調試
2.大體明確類——創建在以前實驗的基礎上code
2.1複用以前的類:不須要修改
SSDirector,Singleton,動做類——CCSequenceAction,SSAction,SSActionEvetType,SSActionManager
2.2須要修改的類:CCActionManager,FirstController,SceneController,UserGUI
3.設計基本UML圖,調試好基本代碼,只有空函數——不具體實現。
4.根據課堂實驗5實現自由移動弓
在Bow的預製對象上掛上下述代碼便可。利用方向控制鍵(鍵盤)能夠控制弓的移動。
5.實現UI界面
6.實現箭的工廠類
7.實現射出箭的動做
8.實現箭插在靶上和分數識別計算
9.添加風力和風的方向
關鍵設置——在上述的第8點算是此次實驗的一大難點,其他的基本在以前的實驗都已經實現過相似的操做。
詳細代碼:
SSDirector.cs
using System.Collections; using System.Collections.Generic; using UnityEngine; using Com.Mygame; public class SSDirector : System.Object { private static SSDirector _instance; public ISceneController currentSceneController { get; set; } public bool running{ get; set; } public static SSDirector getInstance() { if (_instance == null) { _instance = new SSDirector (); } return _instance; } public int getFPS() { return Application.targetFrameRate; } public void setFPS(int fps) { Application.targetFrameRate = fps; } }
FirstController.cs
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; using Com.Mygame; public class FirstController : MonoBehaviour, ISceneController, IUserAction { public IshootArrow actionManager {get; set;} public ArrowFactory arrowfactory {get; set;} public GameObject Arrow; public GameObject Bow; public Text ScoreText; // 顯示得分 public int score; void Awake() { SSDirector director = SSDirector.getInstance (); director.setFPS (60); director.currentSceneController = this; director.currentSceneController.LoadResources (); actionManager = gameObject.AddComponent<CCActionManager>(); arrowfactory = gameObject.AddComponent<ArrowFactory>(); } public void hit(Vector3 dir) { actionManager.playArrow(Bow.transform.position); } void Update() { ScoreText.text = "Score:" + score.ToString(); } public float getWindforce() { return actionManager.getforce(); } public void StartGame() { // } public void ShowDetail() { GUI.Label(new Rect(220, 50, 350, 250), "you can controll the bow and click mouse to emit arrow"); } // 接口具體實現-------------------------------------------------------------------- public void LoadResources() { Debug.Log ("load...\n"); Instantiate(Resources.Load("prefabs/Target")); Bow = Instantiate(Resources.Load("prefabs/Bow")) as GameObject; Arrow.transform.position = Bow.transform.position; } public void Pause(){ } public void Resume(){ } }
SceneController.cs
using System.Collections; using System.Collections.Generic; using UnityEngine; using Com.Mygame; namespace Com.Mygame { public interface ISceneController { void LoadResources (); float getWindforce(); } public interface IUserAction { void ShowDetail(); void StartGame(); void hit(Vector3 dir); } }
UserGUI.cs
using UnityEngine; using UnityEngine.UI; using System.Collections; using Com.Mygame; public class UserGUI : MonoBehaviour { private IUserAction action; // 用戶動做接口 private ISceneController queryInt; // 場景接口 public bool isButtonDown = false; public Camera camera; public Text WindForce; public Text WindDirection; void Start() { // 實例化對象 action = SSDirector.getInstance().currentSceneController as IUserAction; queryInt = SSDirector.getInstance().currentSceneController as ISceneController; } void Update() { float force = queryInt.getWindforce (); if (force < 0) { WindDirection.text = "Wind Direction : Left"; } else if (force > 0) { WindDirection.text = "Wind Direction : Right"; } else { WindDirection.text = "Wind Direction : No Wind"; } WindForce.text = "Wind Force : " + queryInt.getWindforce(); //顯示風力 } void OnGUI() { GUIStyle fontstyle1 = new GUIStyle(); fontstyle1.fontSize = 50; fontstyle1.normal.textColor = new Color(255, 255, 255); if (GUI.RepeatButton(new Rect(0, 0, 120, 40), "Rule")) { action.ShowDetail(); } if (GUI.Button(new Rect(0, 60, 120, 40), "Start")) { action.StartGame(); } if (Input.GetMouseButtonDown(0) && !isButtonDown) { Ray mouseRay = camera.ScreenPointToRay (Input.mousePosition); Debug.Log("RayDir = " + mouseRay.direction); action.hit(mouseRay.direction); isButtonDown = true; } else if(Input.GetMouseButtonDown(0) && isButtonDown) { isButtonDown = false; } } }
Singleton.cs
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("Cant find instance of "+typeof(T)); } } return instance; } } }
Data.cs
using System.Collections; using System.Collections.Generic; using UnityEngine; [System.Serializable] public class Data : MonoBehaviour { public Vector3 size; public Color color = Color.red; public float speed = 5f; public Vector3 director; public play Action; public bool hit; }
ArrowFactory.cs
using System.Collections; using System.Collections.Generic; using UnityEngine; public class ArrowFactory : MonoBehaviour { private static ArrowFactory _instance; private List<GameObject> freeArrow; // 空閒的箭頭 private List<GameObject> usedArrow; private GameObject arrowTemplate; public FirstController sceneControler { get; set; } void Awake() { if (_instance == null) { _instance = Singleton<ArrowFactory>.Instance; _instance.usedArrow = new List<GameObject>(); _instance.freeArrow = new List<GameObject>(); } } public GameObject GetArrow1() { GameObject newArrow; if (freeArrow.Count == 0) { newArrow = GameObject.Instantiate(Resources.Load("Prefabs/arrow")) as GameObject; } else { newArrow = freeArrow[0]; freeArrow.Remove(freeArrow[0]); } newArrow.transform.position = arrowTemplate.transform.position; newArrow.transform.localEulerAngles = new Vector3(90, 0, 0); usedArrow.Add(newArrow); return newArrow; } public void FreeArrow1(GameObject arrow1) { for (int i = 0; i < usedArrow.Count; i++) { if (usedArrow[i] == arrow1) { usedArrow.Remove(arrow1); arrow1.SetActive(true); freeArrow.Add(arrow1); } } return; } // Use this for initialization void Start () { sceneControler = (FirstController)SSDirector.getInstance().currentSceneController; sceneControler.arrowfactory = this; arrowTemplate = Instantiate(Resources.Load("prefabs/arrow")) as GameObject; arrowTemplate.SetActive (false); //arrowTemplate.transform.parent = sceneControler.Bow.transform; arrowTemplate.transform.localEulerAngles = new Vector3(90, 0, 0); freeArrow.Add(sceneControler.Arrow); } // Update is called once per frame void Update () { } }
joystick.cs
using System.Collections; using System.Collections.Generic; using UnityEngine; public class joystick : MonoBehaviour { public float speedY = 10.0F; public float speedX = 10.0F; //public GameObject cam; // Use this for initialization void Start () { } // Update is called once per frame void Update () { //Debug.Log("p"); float translationY = Input.GetAxis("Vertical")*speedY; float translationX = Input.GetAxis("Horizontal")*speedX; translationY *= Time.deltaTime; translationX *= Time.deltaTime; transform.Translate(0, translationY, 0); transform.Translate(translationX, 0, 0); /*if (Input.GetButtonDown("Fire1")) { Debug.Log("Fired Pressed"); Debug.Log(Input.mousePosition); Vector3 mp = Input.mousePosition; //Camera ca = cam.GetComponent<Camera>(); Ray ray = ca.ScreenPointToRay(Input.mousePosition); RaycastHit hit; if (Physics.Raycast(ray, out hit)) { print(hit.transform.gameObject.name); if (hit.collider.gameObject.tag.Contains("Finish")) { Debug.Log("hit "+hit.collider.gameObject.name+"!"); } } }*/ } }
target.cs
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Target : MonoBehaviour { public int num;//每一個靶都有特定的分數 public play EmitDisk; public FirstController sceneController;//場記 //private ScoreRecorder recorder; public void Start() { Debug.Log("target"); sceneController = (FirstController)SSDirector.getInstance().currentSceneController; } void OnTriggerEnter(Collider other) { Debug.Log("jizhong"); Debug.Log(other.gameObject); if (other.gameObject.tag == "Arrow") { if (!other.gameObject.GetComponent<Data>().hit) { other.gameObject.GetComponent<Data>().hit = true; Debug.Log(num); sceneController.score += num;//加分 } EmitDisk = (play)other.gameObject.GetComponent<Data>().Action; other.gameObject.GetComponent<Rigidbody>().velocity = Vector3.zero;//插在箭靶上 EmitDisk.Destory();//動做完成 } } }
Aciton(動做類代碼)
CCActionManager.cs
using System.Collections; using System.Collections.Generic; using UnityEngine; using Com.Mygame; public class CCActionManager : SSActionManager, ISSActionCallback, IshootArrow { public FirstController sceneController; public ArrowFactory arrowFactory; public play EmitArrow; public GameObject Arrow; public float force = 0f; int count = 0; //public CCMoveToAction moveToA, moveToB, moveToC, moveToD; // Use this for initialization protected new void Start () { sceneController = (FirstController)SSDirector.getInstance().currentSceneController; sceneController.actionManager = this; arrowFactory = sceneController.arrowfactory; } // Update is called once per frame protected new void Update () { base.Update(); } public float getforce() { return force; } public void playArrow(Vector3 dir) { force = Random.Range(-50,50); //獲取隨機的風力 EmitArrow = play.GetSSAction(); //force = play.getWindForce(); //Debug.Log("play"); Arrow = arrowFactory.GetArrow1(); //Arrow.transform.position = new Vector3(0, 2, 0); Arrow.transform.position = dir; Arrow.GetComponent<Rigidbody>().AddForce(new Vector3(force, 0.3f, 2), ForceMode.Impulse); this.RunAction(Arrow, EmitArrow, this); Arrow.GetComponent<Data>().Action = EmitArrow; } // public void SSActionEvent(SSAction source, SSActionEventType events = SSActionEventType.Competeted, int intParam = 0, string strParam = null, Object objectParam = null) { arrowFactory.FreeArrow1(source.gameobject); Debug.Log("free"); source.gameobject.GetComponent<Data>().hit = false; } }
CCSequenceAction.cs
using System.Collections; using System.Collections.Generic; using UnityEngine; public class CCSequenceAction : SSAction, ISSActionCallback { public List<SSAction> sequence; public int repeat = -1; public int start = 0; public static CCSequenceAction GetSSAction(int repeat, int start, List<SSAction> sequence) { CCSequenceAction action = ScriptableObject.CreateInstance<CCSequenceAction>(); action.repeat = repeat; action.sequence = sequence; action.start = start; return action; } public override void Update() { if (sequence.Count == 0) return; if (start < sequence.Count) { sequence [start].Update(); } } // Use this for initialization public override void Start () { foreach (SSAction action in sequence) { action.gameobject = this.gameobject; action.transform = this.transform; action.callback = this; action.Start(); } } void OnDestory() { // } public void SSActionEvent(SSAction source, SSActionEventType events = SSActionEventType.Competeted, int intParam = 0, string strParam = null, Object objectParam = null) { source.destroy = false; this.start++; if (this.start >= sequence.Count) { this.start = 0; if (repeat > 0) repeat--; if (repeat == 0) { this.destroy = true; this.callback.SSActionEvent(this); } } } }
IshootArrow.cs
using System.Collections; using System.Collections.Generic; using UnityEngine; using Com.Mygame; public interface IshootArrow { void playArrow(Vector3 dir); float getforce(); }
play.cs
using System.Collections; using System.Collections.Generic; using UnityEngine; public class play : SSAction { int count = 0; bool enableEmit = true; Vector3 force; public FirstController sceneControler = (FirstController)SSDirector.getInstance().currentSceneController; public static play GetSSAction() { play action = ScriptableObject.CreateInstance<play>(); return action; } // Use this for initialization public override void Start() { force = new Vector3(0, 0.3f, 2); } // Update is called once per frame public override void Update() { gameobject.GetComponent<Rigidbody>().velocity = Vector3.zero; gameobject.GetComponent<Rigidbody>().AddForce(force, ForceMode.Impulse); } public void Destory() { this.destroy = true; this.callback.SSActionEvent(this); Destroy(gameobject.GetComponent<BoxCollider>()); } }
SSAction.cs
using System.Collections; using System.Collections.Generic; using UnityEngine; 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;} protected SSAction() {} public virtual void Start() { throw new System.NotImplementedException(); } public virtual void Update() { throw new System.NotImplementedException(); } public virtual void FixedUpdate() { throw new System.NotImplementedException(); } }
SSActionEventType.cs
using System.Collections; using System.Collections.Generic; using UnityEngine; public enum SSActionEventType:int {Started, Competeted} public interface ISSActionCallback { void SSActionEvent(SSAction source, SSActionEventType events = SSActionEventType.Competeted, int intParam = 0, string strParam = null, Object objectParam = null); }
SSActionManager.cs
using System.Collections; using System.Collections.Generic; using UnityEngine; public class SSActionManager : MonoBehaviour { private Dictionary <int, SSAction> actions = new Dictionary <int, SSAction>(); private List<SSAction> waitingAdd = new List<SSAction>(); private List<int> waitingDelete = new List<int> (); // Use this for initialization protected void Start () { } // Update is called once per frame 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.destroy) { waitingDelete.Add(ac.GetInstanceID()); } else if (ac.enable) { 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, ISSActionCallback manager) { action.gameobject = gameobject; action.transform = gameobject.transform; action.callback = manager; waitingAdd.Add(action); action.Start(); } }