Unity实战之打靶游戏

Unity实战之打飞碟游戏

项目源码

整体描述

利用unity实现简单的打飞碟游戏,射中相应的靶即得分。一轮游戏共五发箭。





设计思路

UML图如下

在这里插入图片描述





定义组件

  1. 弓箭

    由两部分组成:箭头和箭身。

    箭头是一个比较小的胶囊体,挂载碰撞器。箭身是从Assets Store中下载的免费素材

    在这里插入图片描述



  1. 由五个同心、高度不同的圆柱组成,每个圆柱体挂载RingData,对应不同的分数

    在这里插入图片描述





代码实现

CCShootAction: 实现箭的发射事件

public class CCShootAction : SSAction
{
    Vector3 force;
    Vector3 wind;

    private CCShootAction(){}

    // Start is called before the first frame update
    public override void Start()
    {
        gameObject.transform.parent = null;
        gameObject.GetComponent<Rigidbody>().velocity = Vector3.zero;

        // force = new Vector3(0, 0, 30);
        // Impulse:向此刚体添加瞬时力冲击,考虑其质量。
        gameObject.GetComponent<Rigidbody>().AddForce(force, ForceMode.Impulse);
        gameObject.GetComponent<Rigidbody>().AddForce(wind, ForceMode.Impulse);
        gameObject.GetComponent<Rigidbody>().isKinematic = false;
    }

    // Update is called once per frame
    public override void Update()
    {

    }

    public override void FixedUpdate(){
        // 箭飞到场外或者中靶
        if(this.transform.position.z > 35 || this.transform.tag == "onTarget"){
            Debug.Log("回调");
            this.destroy = true;
            this.enable = false;
            this.callback.SSActionEvent(this, SSActionEventType.Completed, 0, null, gameObject);
        }
    }

    public static CCShootAction GetSSAction(Vector3 wind){
        CCShootAction shoot = CreateInstance<CCShootAction>();
        shoot.force = new Vector3(0, 0, 40);
        shoot.wind = wind;
        return shoot;
    }
}


CCShootActionManager: 实现射箭动作管理

public class CCShootActionManager : SSActionManager
{
    public FirstController firstController;
    public CCShootAction shoot;

    // Start is called before the first frame update
    protected void Start()
    {
        firstController = (FirstController)SSDirector.GetInstance().CurrentScenceController;
        firstController.actionManager = this;
    }

    public void Shoot(GameObject arrow, Vector3 wind){
        Debug.Log("Shoot");
        shoot = CCShootAction.GetSSAction(wind);
        this.RunAction(arrow, shoot, this);
    }
}


TrembleAction: 箭射中后的颤抖动作,在回调函数中调用

public class TrembleAction : SSAction
{
    float tremble_radius = 0.05f;
    float tremble_time = 0.5f; 
    GameObject arrow;

    Vector3 arrow_pos;

    private TrembleAction(){}
    public static TrembleAction GetSSAction()
    {
        TrembleAction tremble_action = CreateInstance<TrembleAction>();
        return tremble_action;

    }

    // Start is called before the first frame update
    public override void Start()
    {
        //得到箭中靶时的位置
        arrow_pos = gameObject.transform.position;
        // this.transform.Translate(new Vector3(0, 0, 0.5f));
        Debug.Log(gameObject.transform.name);
    }

    // Update is called once per frame
    public override void Update()
    {   
        tremble_time -= Time.deltaTime;
        //需要继续颤抖
        if(tremble_time > 0){
            // gameObject.transform.Translate(new Vector3(0.02f, 0, 0));
           
            Vector3 head_pos = gameObject.transform.position;

            float x = arrow_pos.x + Random.RandomRange(-0.05f, 0.05f);
            float y = arrow_pos.y + Random.RandomRange(-0.05f, 0.05f);
            float z = arrow_pos.z;
            gameObject.transform.position = new Vector3(x, y, z);
        }
        else{
            gameObject.transform.position = arrow_pos;
        }
        // else{
        //     transform.position = arrow_pos;
        //     this.destroy = true;
        //     this.callback.SSActionEvent(this);
        // }
    }
}

具体应用在SSActionManager

public void SSActionEvent(SSAction source,
        SSActionEventType events = SSActionEventType.Completed,
        int intParam = 0,
        string strParam = null,
        GameObject arrow = null){
            TrembleAction trembleAction = TrembleAction.GetSSAction();
            this.RunAction(arrow, trembleAction, this);
        }


ArrowFactory: 箭的工厂,用于生产、释放弓箭

public class ArrowFactory : MonoBehaviour
{
    private List<GameObject> used;
    private List<GameObject> free;
    public GameObject arrow;
    FirstController firstController;
    // Start is called before the first frame update
    void Start()
    {
        firstController = (FirstController)SSDirector.GetInstance().CurrentScenceController;
        used = new List<GameObject>();
        free = new List<GameObject>();
        arrow = null;
    }

    // Update is called once per frame
    void Update()
    {
        
    }

    public GameObject GetArrow(){
        if(free.Count > 0){
            arrow = free[0];
            free.Remove(free[0]);
            if(arrow.tag == "onTarget")//箭在靶子上
            {
                arrow.GetComponent<Rigidbody>().isKinematic = false;
                arrow.tag = "arrow";
                arrow.transform.GetChild(0).gameObject.SetActive(true);
            }
            arrow.SetActive(true);
        }
        else{
            arrow = Instantiate(Resources.Load<GameObject>("Prefabs/arrow1"));
            arrow.GetComponent<Rigidbody>().isKinematic = false;
            // arrow.AddComponent<Rigidbody>();
        }
        // firstController = (FirstController)SSDirector.GetInstance().CurrentScenceController;
        // Transform pos = firstController.bow.transform.GetChild(0);
        // arrow.transform.position = pos.transform.position;
        arrow.transform.parent = firstController.bow.transform;   // 把arrow附加在bow上,跟随着bow移动
        arrow.transform.position = firstController.bow.transform.position;
        used.Add(arrow);

        return arrow;
    }

    public void FreeArrow(GameObject arrow){
        foreach(GameObject aa in used){
            Debug.Log("befreed");
            if(aa.gameObject.GetInstanceID() == arrow.GetInstanceID()){
                arrow.SetActive(false);
                used.Remove(aa);
                aa.tag = "arrow";
                break;
            }
        }
    }

    public void Clear(){
        foreach(GameObject dd in used){
            dd.transform.position = new Vector3(0, 0, 100);
            Destroy(dd);
        }
        foreach(GameObject dd in free){
            dd.transform.position = new Vector3(0, 0, 100);
            Destroy(dd);
        }
        used.Clear();
        free.Clear();
    }
}



RingData: 挂载在每个环上,用于定义不同环的分数

public class RingData : MonoBehaviour {
    public int score;

    public void Start(){
        if(this.gameObject.name=="1"){
            score = 5;
        }
        else if(this.gameObject.name=="2"){
            score = 4;
        }
        else if(this.gameObject.name=="3"){
            score = 3;
        }
        else if(this.gameObject.name=="4"){
            score = 2;
        }
        else{
            score = 1;
        }
    }
}


RingController: 控制环的撞击事件、计分、回调颤抖动作

public class RingController : MonoBehaviour
{
    public ScoreRecorder scoreRecorder;
    public ISceneController sceneController;
    
    // Start is called before the first frame update
    void Start()
    {
        sceneController = SSDirector.GetInstance().CurrentScenceController as FirstController;
        scoreRecorder = Singleton<ScoreRecorder>.Instance;
        this.gameObject.AddComponent<RingData>();
    }

    // Update is called once per frame
    void OnTriggerEnter(Collider arrowCollider){
        Debug.Log("碰撞!");
        Transform arrow = arrowCollider.gameObject.transform.parent;
        Debug.Log(arrow.gameObject.name);
        if(arrow == null){
            Debug.Log("null");
            return;
        }
        scoreRecorder.RecordScore(this.gameObject.GetComponent<RingData>().score);
        Debug.Log("Score:"+this.gameObject.GetComponent<RingData>().score);

        
        arrow.GetComponent<Rigidbody>().isKinematic = true;
        arrow.GetComponent<Rigidbody>().velocity = new Vector3(0, 0, 0);
        arrowCollider.gameObject.SetActive(false);
        arrow.tag = "onTarget";
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_51930942/article/details/128179548
今日推荐