【Unity3D】射箭打靶遊戲(簡單工廠+物理引擎編程)

打靶遊戲: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();
    }
}
相關文章
相關標籤/搜索