小白贪狼做塔防(4)

现在呢我们来搞一下防御塔对怪物的检测逻辑。
首先呢,我想到了触发器检测,并配以一条列表储存在该防御塔射程内的所有敌人。
那么我们来建一个CheckEnemy脚本,用来监测敌人,跟随注视并攻击。

小白贪狼做塔防(4)_第1张图片
组件及脚本设置

话不多说,贴上代码先:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CheckEnemy : MonoBehaviour {
    /// 
    /// 炮塔价格
    /// 
    public float value = 100;
    /// 
    /// 开火频率
    /// 
    public int firewaittime = 2;
    /// 
    /// 临时ID,测试
    /// 
    public int idi = 0;
    /// 
    /// 炮塔转动速度
    /// 
    public float turnSpeed = 2;
    /// 
    /// 最远攻击距离
    /// 
    public float disFire = 12;
    /// 
    /// 是否有正在攻击的目标
    ///   
    private bool isAlarm;
    /// 
    /// 子弹
    /// 
    public GameObject ziDan;
    /// 
    /// 子弹生成位置
    /// 
    public Transform firePos;
    /// 
    /// 攻击目标
    /// 
    private Transform targetEnemy;
    /// 
    /// 存储所有检测到的敌人
    /// 
    private List enemyList;
    /// 
    /// 开火的协程是否开启
    /// 
    private bool isFire = false;

    private Input_Key ik;
    void Start () 
        {
        enemyList = new List();
    }
    
    void Update () {
        //攻击队列里有敌人
        if (enemyList.Count != 0)
        {
            if (enemyList[0] == null)
            {
                enemyList[0] = enemyList[1];
                enemyList.Remove(enemyList[1]);
            }
            else
            {
                if (!isFire)
                {
                    isFire = true;
                    StartCoroutine("Fire");
                }
                //瞄准敌人
                //transform.LookAt(enemyList[0]);
                Vector3 direction = enemyList[0].position - transform.position;
                Quaternion qua = Quaternion.LookRotation(direction);
                transform.rotation = Quaternion.Lerp(transform.rotation, qua, Time.deltaTime * turnSpeed);
                ////如果敌人脱离攻击范围,或者死亡                   
                if (Vector3.Distance(transform.position, enemyList[0].position) > disFire || enemyList[0].GetComponent().Blood <= 0)
                {
                    enemyList.Remove(enemyList[0]);
                }
            }
        }
        else
        {
            if (isFire)
            {
                StopCoroutine("Fire");
                isFire = false;
            }
        }
    }
    /// 
    /// 检测触发物是否为敌人,是的话放入攻击列表
    /// 
    void OnTriggerEnter(Collider other) 
    {
        //可以改成检测空中和地上
        if (other.transform.tag == "Enemy"||other.transform.tag == "FlyEnemy")
        {
            if (!enemyList.Contains(other.transform)) {
                enemyList.Add(other.transform);
            }        
        }
    }
    /// 
    /// 炮塔射击敌人
    /// 
    IEnumerator Fire() {       
        while (true) {
            if (enemyList.Count != 0 && enemyList[0] != null)
            {
                //生成子弹并指定发射的目标
                GameObject go = Instantiate(ziDan, firePos.transform.position, firePos.transform.rotation);
                go.GetComponent().target = enemyList[0];
            }
            else if (enemyList[0] == null) {
                enemyList.Remove(enemyList[0]);
            }
            yield return new WaitForSeconds(firewaittime);        
        }      
    }
}

这里有一小点:如果不写下面的这个就会出现n座塔同时攻击有一个目标,怪物被其中一座塔收走人头,其他以该怪物为目标的塔就会丢失目标而哑火。

if (enemyList[0] == null)
            {
                enemyList[0] = enemyList[1];
                enemyList.Remove(enemyList[1]);
            }

为了改正这个bug,我一开始是想直接在enemyList[0] = null时enemyList.Remove(enemyList[0]),但是不知道为什么还是会出错,所以我就改成把enemyList[1]提前一个单位,并enemyList.Remove(enemyList[1]),这样就好使了,坑爹啊,各位大神如果知道原因请在评论区赐教贪狼感激不尽。

然后我们迎来了本游戏的重头戏“防御塔”攻击方式——弹药。我分成了三大类:1.单体攻击类,2.范围攻击类。而这两类又可以分别派生出对地类,对空类甚至减速buff这种buff类
首先,我们来看看单体攻击类:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Bullet : MonoBehaviour {

    public float damageValue = 25f;
    /// 
    /// 攻击目标
    /// 
    public Transform target;
    /// 
    /// 子弹发射速度
    /// 
    public float speed = 10f;
    void Update () 
        {
        if (target&&target!=null)
        {
            transform.position = Vector3.MoveTowards(transform.position, target.transform.position+new Vector3(0,1.5f,0), speed * Time.deltaTime);
        }
//丢失目标
        else {
            Destroy(transform.gameObject);
        }
    }
//此处为对地对空双功能,你可以改成单一功能
    void OnTriggerEnter(Collider other) {
        if (other.transform.tag == "Enemy"|| other.transform.tag == "FlyEnemy") {
            other.GetComponent().EnemyHurt(damageValue);
            Destroy(this.gameObject);
        }
    }
}

然后是范围伤害类:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ZhaDan : MonoBehaviour {

    public float DamageOffeset;
    public float damageValue;
    /// 
    /// 攻击目标
    /// 
    public Transform target;
    /// 
    /// 子弹发射速度
    /// 
    public float speed = 10f;
    // Use this for initialization
    /// 
    /// AOE半径
    /// 
    public float r = 1f;
    void Start()
    {

    }

    void Update()
    {
        if (target.GetComponent() !=null)
        {
            if (transform.tag != "Ice")
            {
                transform.position = Vector3.MoveTowards(transform.position, target.transform.position + new Vector3(0, 2.5f, 0), speed * Time.deltaTime);
            }
            else {
                transform.position = Vector3.MoveTowards(transform.position, target.transform.position + new Vector3(0, 0.1f, 0), speed * Time.deltaTime);
            }        
        }
        else
        {
            Destroy(transform.gameObject);
        }
    }

    void OnTriggerEnter(Collider other)
    {
        if (other.transform.tag == "Enemy")
        {
            Grenade_AOE_Damage(transform, r, damageValue);
              
        }
    }
    void Grenade_AOE_Damage(Transform _grenade, float _AOE_radius, float _damage)
    {
            //获取手雷_AOE_radius范围内所有的碰撞体(敌人)
            Collider[] colliders = Physics.OverlapSphere(_grenade.position, _AOE_radius);
         
            //遍历范围内所有敌人并给予伤害
            for (int i = 0; i < colliders.Length; i++)
            {
            
            bool isCap = colliders[i].GetType() == (typeof(CapsuleCollider));
         
            if (isCap && (colliders[i].gameObject.tag=="Enemy"))
            {
              
                //判断距离中心爆炸点距离,并实现伤害衰减
                float dis = Vector3.Distance(colliders[i].transform.position, _grenade.position);
                float dam = _damage - dis * DamageOffeset;
                //加上特效

                //获取生命脚本组件,调用伤害函数
                colliders[i].gameObject.GetComponent().EnemyHurt(dam);
            }
             
            }
        StartCoroutine(Boom());
    }

    IEnumerator Boom() {
        transform.GetComponent().enabled = false;
        GameObject go;
        if (transform.tag == "Bomb")
        {
            go = Instantiate((GameObject)Resources.Load("fireball/Boom/Prefabs/Bomb"), transform.position, transform.rotation);
        } else if (transform.tag == "Ice") {
            go = Instantiate((GameObject)Resources.Load("fireball/IceEffect/Prefabs/Fx/IceGo"), transform.position, transform.rotation);
        }
        else {
            go = null;
        }
        yield return new WaitForSeconds(0.8f);
        Destroy(this.gameObject);
        if (go != null) {
            Destroy(go);
        }      
    }
}

然后我们上网下载一个冰霜特效和爆炸特效,可以增加真实感,并在冰霜特效上挂载脚本控制减速协程:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
public class IceBullet : MonoBehaviour {
    void Start () {
    }
    
    // Update is called once per frame
    void Update () {
        
    }

    void OnTriggerEnter(Collider other) { 
         if (other.transform.tag == "Enemy" && other.transform.GetComponent())
         {
            other.transform.GetComponent().DealSpeed();
         }       
    }
}

这时,我们需要在EnemyContrl脚本及加些“零件”:

private bool isLowSpeed = false;
public void DealSpeed() {
        if (isLowSpeed)
        {
            return;
        }
        else {
            isLowSpeed = true;
            StartCoroutine(LowSpeed());          
        }
    }

    IEnumerator LowSpeed() {
        transform.GetComponent().speed /= 2;
        yield return new WaitForSeconds(2.5f);
        if(transform.GetComponent())
            transform.GetComponent().speed *= 2;
![Uploading IS}]3IW`}1{XXX_(8YB{98F_078727.png . . .]

        isLowSpeed = false;
    }

其中isLowSpeed是为了防止同一怪物被反复减速,然后可以将减速幅度设为public类型,以便想要防御塔升级时加大减速幅度的朋友控制。
另外还有激光枪,喷火筒两种,这里我将粒子特效挂在枪口,并为粒子特效增加碰撞器,使其只检测Enemy层敌人。

小白贪狼做塔防(4)_第2张图片
喷火筒
小白贪狼做塔防(4)_第3张图片
加碰撞器

然后有两种思路,第一种是在CheckEnemy时,判断自己是否是激光枪,喷火筒(tag=“strong”)
然后监测到敌人就向目标放“特效”(用ParticleSystem my_PS;my_PS.Stop();my_PS.Play();)控制。然后通过粒子碰撞器,将碰到的敌人扣除血量(可以用OnParticleCollisionStay判断)。

第二种思路是我们偷懒想出的办法,特效照开不误,但是用“隐形的”子弹和炮弹(激光单体,喷火群体)以很快的速度攻击怪物(哈哈这样就可以用旧代码实现新功能了,我好懒)。

你可能感兴趣的:(小白贪狼做塔防(4))