美文网首页unity3D技术分享
小白贪狼做塔防(3)

小白贪狼做塔防(3)

作者: 貪狼大人 | 来源:发表于2017-10-20 14:23 被阅读0次

    现在我们来探讨怪物的相关事宜:
    首先我们给怪物加一个EnemyContrl脚本,用来储存怪物的各种属性以及寻路,各种动画。


    怪物身上的组件以及脚本设置

    话不多说,贴上代码先:

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.AI;
    using UnityEngine.UI;
    
    public class EnemyContrl : MonoBehaviour
    
    {
        /// <summary>
        /// 敌人的伤害值
        /// </summary>
        public float Destruction;
        /// <summary>
        /// 子弹的伤害
        /// </summary>
        private float Damage;
        /// <summary>
        /// 怪物血量
        /// </summary>
        public float Blood = 100f;
        private float b ;
        /// <summary>
        /// 怪物要到达的终点
        /// </summary>
        public GameObject Pos;
        /// <summary>
        /// 自动寻路组件
        /// </summary>
        private NavMeshAgent agt;
        /// <summary>
        /// 定义动画控制器
        /// </summary>
        private Animator Ani;
        /// <summary>
        /// 死亡后销毁时间
        /// </summary>
        private float DestryTime = 3f;
        /// <summary>
        /// 计时器
        /// </summary>
        private float Timer = 0;
    
        private Slider sd;
        void Awake()
        {
            sd = transform.GetChild(3).GetChild(0).GetComponent<Slider>();
            sd.value = sd.maxValue = 1;
            b = Blood;
        }
        void Start()
        {
            //获取自动寻路组件
            agt = this.GetComponent<NavMeshAgent>();
            //获取动画控制组件
            Ani = this.GetComponent<Animator>();
            //将终点位置传递进去
            agt.SetDestination(Pos.transform.position);
        }
    
        // Update is called once per framea
        void Update()
        {
            transform.GetChild(3).transform.forward = Camera.main.transform.forward;
            //监测生命值
            EnemyDead(Blood);
            //检测是否到达水晶
            Attack();
        }
        public void EnemyHurt(float Damage)
        {
            Blood -= Damage;
             
            sd.value = Blood /b;
            
        }
        public void EnemyDead(float Blood)
        {
            if (Blood <= 0)
            {
                this.gameObject.GetComponent<Collider>().enabled = false;
                Destroy(this.gameObject.GetComponent<Rigidbody>());
                //杀怪物获得金币
                GameData.Instance.money += 10;
                Ani.SetBool("Dead", true);
                Ani.SetBool("Attack", false);
                //agt.SetDestination(this.transform.position);
                this.gameObject.GetComponent<NavMeshAgent>().enabled = false;
                Timer += Time.deltaTime;
                if (Timer >= DestryTime) {
                    Destroy(this.gameObject);
                }
            }
            else
            {
    
            }
        }
    
        public void Attack()
        {
            if (Vector3.Distance(this.transform.position, Pos.transform.position) <= 3.5)
            {
                Ani.SetBool("Attack", true);
            }
        }
    }
    
    

    有了这些还不够,我们还需要创建一个怪物生成点 (一个空物体即可)
    挂载EnemyCreatePos脚本,这里尚未使用对象池技术,想要使用该技术的请到我之前发的文章里找找灵感。
    链接:http://www.jianshu.com/p/18950e18ea75

    再编写生成脚本时,我们要提前想好自己需要几种不同种类的怪物,这里的不同种类不是指外形的不同,而是比如,地面怪物,空中怪物,甚至物理怪物或魔法怪物,我暂时只分出地面怪物,空中怪物两大类。
    代码如下:

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class EnemyCreatePos : MonoBehaviour
    {
        //public float CreateSpeed = 2;
        /// <summary>
        /// 波数
        /// </summary>
        public int boshu = 10;
        /// <summary>
        /// 每波间隔
        /// </summary>
        public float bowait = 5;
        /// <summary>
        /// 每波怪数量
        /// </summary>
        public int bonum = 10;
        /// <summary>
        /// 每个怪间隔
        /// </summary>
        public float numwait = 2;
        /// <summary>
        /// 第几波
        /// </summary>
        private int boNO;
        /// <summary>
        /// 每波第几个
        /// </summary>
        private int numNO;
    
        private string str;
        //void Start () {
        //    StartCoroutine("CreateEnemy");
        //}
        //public GameObject enemyPrefabHyp;
        // Use this for initialization
        void Start()
        {
            StartCoroutine(Test02(boshu));
        }
    
        // Update is called once per frame
        void Update()
        {
    
        }
        //num:一共产生多少波怪
        IEnumerator Test02(int num)
        {
            boNO = 0;
            while (boNO < num)
            {
                //Camera.main.transform.GetComponent<WeatherController>().weather = boNO % 3;
                
                GameObject.Find("Weather").transform.GetComponent<WeatherController>().weather = boNO / 3;
                GameObject.Find("Weather").transform.GetComponent<WeatherController>().Change();
                boNO++;
                yield return StartCoroutine(Test01(bonum));
                Debug.Log("第" + boNO + "波怪产生结束");
                //每波怪产生的时间差
                yield return new WaitForSeconds(bowait);
                Debug.Log("注意第" + (boNO + 1) + "波怪即将产生");
            }
            Debug.Log("GameOver");
        }
        //number:每波怪的数量
        IEnumerator Test01(int number)
        {
            numNO = 0;
            while (numNO < number)
            {
                numNO++;
                //每个怪产生的时间差
                if (boNO > 5)
                    yield return new WaitForSeconds(numwait / 2);
                else
                    yield return new WaitForSeconds(numwait);
                string a = ChooseEnemy(boNO,numNO);
                //GameObject enemy = (GameObject)Resources.Load("Prefabs_Enemy/mon_goblinWizard");
                GameObject enemy = (GameObject)Resources.Load("Prefabs_Enemy/"+a);
                enemy.GetComponent<EnemyContrl>().Pos = GameObject.FindGameObjectWithTag("WayPos");
                //print(enemy.GetComponent<EnemyContrl>().Pos.name);
                GameObject o;
                //如果在飞行怪,则拔高5
                if (enemy.tag == "FlyEnemy")
                {
                    o = Instantiate(enemy, transform.position + Vector3.up * 5, transform.rotation);
                }
                else
                    o =  Instantiate(enemy,transform.position,transform.rotation);
                o.transform.parent = transform;
    
            }
    
        }
        /// <summary>
        /// 选择怪物种类
        /// </summary>
        /// <param name="boNO"></param>波次
        /// <param name="numNO"></param>怪次
        /// <returns></returns>
        string ChooseEnemy(int boNO, int numNO)
        {
    
            switch(boNO % 3)
            {
    
                case 1:
                    {
                        if (numNO < 8)
                        {
                            str = "AmurTiger_01";
                        }
                        else if (numNO < 10 && numNO >= 8)
                        {
                            str = "AmurTiger_02";
                        }
                        else
                        {
                            str = "AmurTiger_03";
                        }
                        break;
                    }
                case 2:
                    {
                        if (numNO < 8)
                        {
                            str = "GiantBat";
                        }
                        else if (numNO < 10 && numNO >= 8)
                        {
                            str = "GiantBat_2";
                        }
                        else
                        {
                            str = "GiantBat_3";
                        }
                        break;
                    }
                case 3:
                    {
                        if (numNO < 8)
                        {
                            print("3-1");
                            str = "Manticore_01";
                        }
                        else if (numNO < 10 && numNO >= 8)
                        {
                            print("3-2");
                            str = "Manticore_02";
                        }
                        else
                        {
                            str = "Manticore_03";
                        }
                        break;
                    }
                case 0:
                    {
                        if (numNO < 4)
                        {
                            str = "GiantBat_2";
                        }
                        else if (numNO < 7 && numNO >= 4)
                        {
                            str = "AmurTiger_02";
                        }
                        else if (numNO <= 10 && numNO >= 7)
                        {
                            str = "Manticore_02";
                        }
                        break;
                    }
            }
            return str;
        }
            
        //IEnumerator CreateEnemy() {
        //    while (true) {       
        //        yield return new WaitForSeconds(CreateSpeed);
        //        GameObject enemy = (GameObject)Resources.Load("Prefabs_Enemy/mon_goblinWizard");        
        //        enemy.GetComponent<EnemyContrl>().Pos = GameObject.FindGameObjectWithTag("WayPos");
        //        Instantiate(enemy);
        //    }     
        //}
    }
    

    很明显,我设置了很多public,这是方便在外部调试。首先我的想法是将怪物分成n个波次,每波m个怪物,后期可以选择关卡难度时可以改变,甚至可以每波数量递增。其次我们需要将自己需要的怪物名字写成何种形式,或枚举,或分支,总之可以在生成怪时可以控制每次生成的怪物是哪一个。最后,我们对脚本进行微调,如:若是飞行怪则出生高度拔高x单位,或为每一波怪物来临之前加上一个提示等等,随你喜欢。
    当然,我们要在怪物的攻击动画中添加时间,在怪物攻击“水晶”或者“萝卜”的时候,扣除水晶一定血量,本游戏采取积分制,但是目前所有怪物死亡后加的分数相同,不便于分出高下,所以我便加了一个判断,假如怪物是被防御塔打死则加10分,被水晶打死则不得分,甚至扣分。
    怪物生成逻辑就先告一段落,日后若有优化会开新篇,下一篇我们来探讨防御塔对怪物的检测以及各种子弹的逻辑。

    相关文章

      网友评论

        本文标题:小白贪狼做塔防(3)

        本文链接:https://www.haomeiwen.com/subject/eqcvuxtx.html