【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...\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();
    }
}

 

转载于:https://www.cnblogs.com/xieyuanzhen-Feather/p/6666586.html

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值