4.8 防守单位 本游戏中唯一的一个防守单位是个袍塔,它的功能很简单,当敌人进入它的攻击范围便会开火。 为了能方便地遍历场景中的所有敌人,我们可以准备一个ArrayList,将所有生成的敌人都存进去,这样可以很容易查找到任何一个敌人。 打开GameManager.cs脚本,添加一个ArrayList属性用来存放所有的敌人。 public ArrayList m_EnemyList=new ArrayList(); 打开Enemy.cs脚本,在Start和OnDisable函数中分别在存放敌人的ArrayList中添加敌人和删除敌人。添加一个SetDamage函数减少生命值,当生命值为零时销毁自身。 void Start () { m_spawn.m_liveEnemy++; GameManager.Instance.m_EnemyList.Add(this); } void OnDisable() { if (m_spawn) m_spawn.m_liveEnemy--; if (GameManager. Instance) GameManager.Instance.m_EnemyList.Remove(this); if ( m_bar ) Destroy(m_bar.gameObject); } public void SetDamage(int damage) { m_life -= damage; if (m_life <= 0) { GameManager.Instance.m_EnemyList.Remove(this); // 每消灭一个敌人增加一些点数 GameManager.Instance.SetPoint(2); Destroy(this.gameObject); } } 创建防守单位的脚本Defender.cs: using UnityEngine; using System.Collections; public class Defender : MonoBehaviour { // 目标敌人 Enemy m_targetEnemy; // 攻击范围 public float m_attackArea = 4.0f; // 攻击力 public int m_power = 1; // 攻击时间间隔 public float m_attackTime = 1.0f; // 攻击时间间隔 public float m_timer = 0.0f; void Start () { // 设置当前所处的单元格为CanNotStand状态 GridMap.Instance.m_map[(int)this.transform.position.x, (int)this.transform.position.z].fieldtype = MapData.FieldTypeID.CanNotStand; } void Update () { FindEnemy(); RotateTo(); Attack(); } // 转向敌人 public void RotateTo() { if (m_targetEnemy == null) return; Vector3 current = this.transform.eulerAngles; this.transform.LookAt(m_targetEnemy.transform); Vector3 target = this.transform.eulerAngles; float next = Mathf.MoveTowardsAngle(current.y, target.y, 120 * Time.deltaTime); this.transform.eulerAngles = new Vector3(current.x, next, current.z); } // 查找敌人 void FindEnemy() { // 将目标敌人清空 m_targetEnemy = null; // 用于比较敌人的生命值 int lastlife = 0; // 在敌人列表中遍历所有的敌人 foreach (Enemy enemy in GameManager.Instance.m_EnemyList) { //忽略生命值已为零的敌人 if (enemy.m_life == 0) continue; Vector3 pos1 = this.transform.position; Vector3 pos2 = enemy.transform.position; //与敌人的平面距离 float dist=Vector2.Distance(new Vector2(pos1.x, pos1.z), new Vector2(pos2.x, pos2.z)); // 忽略在攻击范围外的敌人 if (dist > m_attackArea) continue; // 找到生命值最低的敌人 if (lastlife == 0 || lastlife > enemy.m_life) { m_targetEnemy = enemy; lastlife = enemy.m_life; } } } // 攻击敌人 public void Attack() { // 更新攻击间隔时间 m_timer -= Time.deltaTime; if (m_targetEnemy == null) return; if (m_timer > 0) return; //伤害敌人 m_targetEnemy.SetDamage(m_power); // 初始化攻击间隔时间 m_timer = m_attackTime; } } 在这个脚本中,FindEnemy函数主要用于查找进入其攻击范围的敌人,然后在这些敌人中再选出一个生命值最低的敌人作为目标敌人。 Attack函数向敌人攻击,这里只是很简单地调用了敌人的SetDamage函数减少敌人的生命值。 当创建了一个防守单位后,它所处的单元格则被当前防守单位占据,不能再创建其他东西,因此我们在Start函数中改变了防守单位所处单元格的属性。 在Project窗口的Rawdata目录下找到turret.fbx模型,将其在场景中创建出来,并为它指定Defender.cs脚本。 运行游戏,防守单位会向进入它攻击范围的敌人进攻,如图4-24所示,被消灭的敌人会直接消失,如果希望有更好的效果,可以为防守单位添加射击特效,为敌人添加爆炸效果等。 图4-24 防守单位