zoukankan      html  css  js  c++  java
  • 【Unity3D】射箭打靶游戏(简单工厂+物理引擎编程)

    打靶游戏:

        1.靶对象为 5 环,按环计分;
        2.箭对象,射中后要插在靶上;
        3.游戏仅一轮,无限 trials;

    增强要求:

     添加一个风向和强度标志,提高难度


    游戏成品图:

     

    UML图:


    游戏设计思路&大致过程&核心代码
    游戏对象主要由三个,靶、弓和箭,射出去的箭可以复用(利用简单工厂),将箭从弓的位置加上常力向某个方向射出。最后实现增强功能——添加常力作为风向并且在界面中显示出风向(只设置了界面上的左右两个不同方向)以及风力(0~50)。

    1.首先设置游戏对象——靶子、弓和箭。
        为了实现识别不同的环,通过五个共圆心的圆柱体(高度不同——通过设置Transform)来识别箭首先碰到的环(小环厚度较大)。

        游戏的弓和箭——刚开始用圆柱体(箭身)+胶囊(箭头)实现箭,在后来进行界面优化时下载了模型。将模型直接作为预制即可。

     

    2.大致明确类——建立在之前实验的基础上

             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...
    ");
                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();
        }
    }
  • 相关阅读:
    智力题:砝码称重问题
    Java:Comparator接口
    机器学习中比较重要的几个概念
    NLP:Gensim库之word2vec
    Java遍历Map对象的四种方式
    给数据库减负刻不容缓:多级缓存设计
    CentOS6.10安装redis5.0
    Linux下安装whl文件
    Linux下安装Gensim
    Linux下安装jieba
  • 原文地址:https://www.cnblogs.com/xieyuanzhen-Feather/p/6666586.html
Copyright © 2011-2022 走看看