文章目录

  • 本章目标
  • 防御塔策划
  • 四种防御塔
  • 防御塔配置文件
  • 每关可选不同的防御塔
  • 加载配置
  • 制作UI
  • 锁定敌人
  • 攻击敌人
  • 防御塔个性化实现
    • 对父类方法进行扩充
    • 替代父类方法
    • 斜抛运动
  • 效果演示

本章目标

设计防御塔类型以及配置方式,选择几种防御塔做样例,实现防御塔的攻击相关功能,如:锁定敌人、攻击敌人、攻击动画、攻击特效等。

防御塔策划

虽然是个 Demo 游戏,但也要有基本的策划,我们暂定防御塔可以有以下几种类别:

  • 单体攻击类:箭塔,锁定单体攻击,攻击频率较快
  • 溅射攻击类:炮塔,攻击有溅射伤害
  • 超远程攻击类:导弹塔,单体锁定溅射攻击,锁定半径极大,攻击力较强,有溅射效果,攻击速度低。
  • 远程群体减速类:冰锥塔,锁定单体并溅射减速效果,降低范围内敌人移动力,攻击力极低。
  • 单体减速类:毒液塔,锁定单体攻击,降低单个敌人移动力,攻击力极低。
  • 周围群体减速类:荆棘塔,群体锁定攻击,降低半径范围内敌人移动力,攻击力极低。
  • 定身类:时间秩序塔,群体锁定攻击,限制半径范围内敌人移动,攻击力极低。
  • 群体攻击类:多重箭塔,最多可同时攻击6个单位,攻击力较弱。
  • 单体暴击类:剑神,基础攻击力较强,攻击产生暴击。
  • 持续攻击类:电塔,针对 Boss ,每帧都造成伤害,对 Boss 伤害有加成
  • 线性攻击类:激光塔,对一条射线路径上的所有敌人造成伤害。目标有距离限制,伤害无距离限制。
  • 弹射攻击类:折射炮塔,锁定单体攻击,击中后炮弹有两次弹射攻击。弹射距离有限制。

四种防御塔

我们在Demo中先做四种防御塔,分别是:

  1. 箭塔;
  2. 炮塔;
  3. 导弹塔;
  4. 冰锥塔。

    因为是 Demo ,所以模型都是各个网站下载的,风格不太统一,先凑合一下,哈哈。

防御塔配置文件

每关可选不同的防御塔

为了增加游戏的可玩性,我们让不同的关卡拥有不同的可选防御塔,所以要在关卡配置文件增加一个配置项。

加载配置

防御塔管理类(DefenseManager)代码:

using Excel;
using System;
using System.Collections.Generic;
using TDGameDemo.GameDefense;
using TDGameDemo.GameLevel;
using UnityEngine;
using UnityEngine.UI;public class DefenseManager : MonoBehaviour
{private Dictionary<string, List<DefenseConfig>> _defenseConfigs;private void Start(){InitConfig();}/// <summary>/// 初始化配置/// </summary>private void InitConfig(){_defenseConfigs = new Dictionary<string, List<DefenseConfig>>();ConfigManager cm = new ConfigManager();IExcelDataReader excelReader = cm.LoadExcel(new string[] { "Configs", "DefenseConfig", "DefenseConfig_All.xlsx" });// 读取int index = 0;// 移动到第四行for (; index < 4; index++){excelReader.Read();}while (true){if (excelReader.GetString(1) == null) break;DefenseConfig defConfig = new DefenseConfig();defConfig.DefenseCode = excelReader.GetString(1);defConfig.DefenseType = excelReader.GetString(2);defConfig.DefenseTypeCode = excelReader.GetInt32(3);defConfig.LockTargetRange = excelReader.GetInt32(5);defConfig.LockTargetCount = excelReader.GetInt32(6);defConfig.AttackCooldownTime = excelReader.GetFloat(7);defConfig.BulletATK = excelReader.GetInt32(8);defConfig.RetardanceCoefficient = excelReader.GetFloat(9);defConfig.RetardanceDuration = excelReader.GetFloat(10);defConfig.RetardanceRange = excelReader.GetInt32(11);defConfig.IsTopLevel = false;if (!_defenseConfigs.ContainsKey(defConfig.DefenseCode)){_defenseConfigs.Add(defConfig.DefenseCode, new List<DefenseConfig>());}_defenseConfigs[defConfig.DefenseCode].Add(defConfig);excelReader.Read();index++;}foreach (KeyValuePair<string, List<DefenseConfig>> items in _defenseConfigs){// 让每个类别的炮塔按照等级重新排序items.Value.Sort();// 将每个类别中最高级的炮塔设置为顶级炮塔items.Value[items.Value.Count - 1].IsTopLevel = true;//foreach (DefenseConfig item in items.Value)//{//    Debug.Log(items.Key + "===========" + item.DefenseLevel);//}}}
}

防御塔配置模型类(DefenseConfig)代码:
注意:代码中实现了 IComparable 接口,以便于在列表中实现按防御塔等级排序。关于排序的详细介绍可以参考我的另一篇文章:【Unity】Unity开发进阶(三)对象排序工具、减少使用foreach。

using System;namespace TDGameDemo.GameDefense
{/// <summary>/// 防御塔配置类/// </summary>public class DefenseConfig : IComparable<DefenseConfig>{/// <summary>/// 实现IComparable接口,让防御塔具备按照等级排序的能力/// </summary>/// <param name="other"></param>/// <returns></returns>public int CompareTo(DefenseConfig other){return DefenseLevel.CompareTo(other.DefenseLevel);}/// <summary>/// 防御塔编号/// </summary>public string DefenseCode { get; set; }/// <summary>/// 防御塔类型/// </summary>public string DefenseType { get; set; }/// <summary>/// 防御塔类型编号/// </summary>public int DefenseTypeCode { get; set; }/// <summary>/// 防御塔等级/// </summary>public int DefenseLevel { get; set; }/// <summary>/// 是否顶级/// </summary>public bool IsTopLevel { get; set; }/// <summary>/// 锁定目标范围/// </summary>public float LockTargetRange { get; set; }/// <summary>/// 子弹速度/// </summary>public float BulletSpeed { get; set; }/// <summary>/// 目标数量/// </summary>public int LockTargetCount { get; set; }/// <summary>/// 攻击CD时间/// </summary>public float AttackCooldownTime { get; set; }/// <summary>/// 攻击力/// </summary>public float BulletATK { get; set; }/// <summary>/// 减速系数/// </summary>public float RetardanceCoefficient { get; set; }/// <summary>/// 减速持续时间/// </summary>public float RetardanceDuration { get; set; }/// <summary>/// 攻击影响范围/// </summary>public float RetardanceRange { get; set; }/// <summary>/// 定身时间/// </summary>public float DizzyDuration { get; set; }}
}

制作UI


锁定敌人

首先所有的防御塔都应该继承于一个基类:DefenseBase ,代码如下:

using UnityEngine;namespace TDGameDemo.GameDefense
{/// <summary>/// 防御塔基类/// </summary>public class DefenseBase : MonoBehaviour{/// <summary>/// 敌人生成点的父节点/// <para>防御塔管理器创建防御塔时获得。</para>/// </summary>[HideInInspector]public Transform EnemyGeneratePointParent;/// <summary>/// 防御塔中需要旋转的物体/// <para>例如导弹发射器等需要旋转的炮台</para>/// </summary>public Transform Rotater;/// <summary>/// 防御塔配置/// <para>防御塔管理器创建防御塔时获得。</para>/// </summary>public DefenseConfig _defenseConfig;/// <summary>/// 防御塔目标/// <para>通过LockTarget锁定目标。</para>/// </summary>protected Transform _target;// TODO 暂时为单个目标,后续需要改成列表。/// <summary>/// 攻击偏移时间/// <para>当此变量超过防御塔的攻击冷却时间(AttackCooldownTime)时才可以进行下一次攻击。</para>/// </summary>protected float _attackOffsetTime = 50f;/// <summary>/// 子弹生成点/// </summary>protected Transform _weaponGenPoint;/// <summary>/// 子弹预制件文件路径前缀/// </summary>public const string BULLET_PREFAB_PREFIX = "Defense/Prefab/";/// <summary>/// 锁定敌人方法/// </summary>/// <returns></returns>public virtual void LockTarget(){for (int i = 0; i < EnemyGeneratePointParent.childCount; i++){// 查找所有敌人foreach (Transform child in EnemyGeneratePointParent.GetChild(i)){// 确认是否在射程范围内if (Vector3.Distance(transform.position, child.position) < _defenseConfig.LockTargetRange){_target = child;}}}}}
}

在子类的 Update 中调用父类的 LockTarget 方法来锁定敌人。子类代码如下:

using UnityEngine;namespace TDGameDemo.GameDefense
{public class ArrowDefense : DefenseBase{void Update(){// 叠加攻击CD时间_attackOffsetTime += Time.deltaTime;// 如果失去目标,则重新锁定新的目标if (_target == null){LockTarget();}else // 如果有目标则攻击目标{AttackTarget();}}}
}

攻击敌人

锁定敌人以后调用父类的 AttackTarget 方法即可实现攻击,代码如下:

/// <summary>
/// 攻击目标方法
/// </summary>
/// <returns></returns>
public virtual void AttackTarget()
{// 判断受击物体是否存在if (_target == null){return;}// 判断是否可以攻击//if (_attackOffsetTime > _defenseConfig.AttackCooldownTime && _weaponGenPoint.childCount == 0)if (_attackOffsetTime > _defenseConfig.AttackCooldownTime){// 能调用攻击,证明已经有目标了,要看目标是不是在攻击范围内,如果不在范围内,要更换新目标。// 计算玩家与目标敌人的距离if (Vector3.Distance(transform.position, _target.position) < _defenseConfig.LockTargetRange){_weaponGenPoint.LookAt(_target);string path = BULLET_PREFAB_PREFIX + "Prefab_Defense_" + _defenseConfig.DefenseCode + "_Bullet";GameObject enemyPrefab = Resources.Load<GameObject>(path);GameObject bullet = Instantiate(enemyPrefab, _weaponGenPoint.position, _weaponGenPoint.rotation, _weaponGenPoint);bullet.GetComponent<Bullet>().Target = _target;bullet.GetComponent<Bullet>().Speed = _defenseConfig.BulletSpeed;_attackOffsetTime = 0f;}else{// 目标离开攻击范围,失去目标_target = null;}}
}

将此方法放到 DefenseBase 类中即可。

防御塔个性化实现

父类的锁定敌人方法 LockTarget 和攻击敌人方法 AttackTarget 是常规情况下的处理方式,有时候新的防御塔并不一定用同样的方式锁定敌人或者攻击敌人,此时可以在子类中增加个性化代码。

个性化代码分为两种,一种是对父类方法进行扩充,另一种是完全替代父类方法。

对父类方法进行扩充

比如我们的加农炮台需要顶部炮台朝着敌人的位置旋转,此时可以使用扩充的方式,在子类代码中重写 AttackTarget 方法并调用父类方法(base.AttackTarget();),然后再进行扩充,代码如下:

using UnityEngine;namespace TDGameDemo.GameDefense
{public class CannonDefense : DefenseBase{private void Start(){_weaponGenPoint = transform.Find("WeaponGenPoint");}private void Update(){// 叠加攻击CD时间_attackOffsetTime += Time.deltaTime;// 如果失去目标,则重新锁定新的目标if (_target == null){LockTarget();}else // 如果有目标则攻击目标{AttackTarget();}}/// <summary>/// 攻击目标/// </summary>public override void AttackTarget(){base.AttackTarget();if (_target != null){Rotater.LookAt(new Vector3(_target.position.x, Rotater.transform.position.y, _target.position.z));}}}
}

替代父类方法

导弹塔的发射轨迹与箭塔不同,导弹是先斜向上飞然后再飞向敌人。这需要进行一个斜抛运动的计算,此时就可以直接替代父类方法,也就是在子类方法中不去调用父类方法即可,代码大致为:

/// <summary>
/// 攻击目标
/// </summary>
public override void AttackTarget()
{// TODO 斜抛运动攻击敌人
}

斜抛运动

关于斜抛运动的计算方式我将在下一章中讲解,欢迎关注,大家共同进步。

效果演示

Unity制作炮台防守游戏(3)防御塔攻击


更多内容请查看总目录【Unity】Unity学习笔记目录整理

【Unity】U3D TD游戏制作实例(五)防御塔设计:对象排序、锁定敌人、攻击敌人、防御塔特色功能实现相关推荐

  1. 【Unity】U3D TD游戏制作实例(一)创建敌人、加载预制件

    文章目录 前言 本章实现效果 场景和敌人 文件目录结构 场景层次结构(Hierarchy) 处理模型 指定GameScript脚本 运行游戏 前言 TD(炮台防守)类游戏是比较经典的游戏类型,当年在 ...

  2. 【Unity】U3D TD游戏制作实例(四)建造防御塔:防御塔生成器、一个int代表多选框,圆上任意点位的坐标计算、制作防御塔预制件

    文章目录 本章内容介绍 制作生成器 生成器Hierarchy 高亮显示生成器 制作箭塔菜单 将创建菜单对齐到选中的生成器 动态生成按钮 动态计算按钮坐标 制作预制件 最终运行效果 本章内容介绍 由于目 ...

  3. 【Unity】U3D TD游戏制作实例(三)相机管理器、生成敌人优化、敌人血槽小组件

    文章目录 相机管理器 调整相机 敌人类优化 融合导航测试代码 敌人移动速度 销毁对象 加载敌人配置 敌人生成方式优化 血槽组件 相机管理器 调整相机 首先将主相机调整为正交镜头,这样可以防止模型畸变. ...

  4. 《Unity 3.x游戏开发实例》一1.5 欢迎来到Unity 3D

    本节书摘来异步社区<Unity 3.x游戏开发实例>一书中的第1章,第1.5节,作者: [加]Ryan Henson Creighton 译者: 师蓉 责编: 陈冀康,更多章节内容可以访问 ...

  5. 《Unity 3.x游戏开发实例》——1.2节风靡全球的Unity

    本节书摘来自异步社区<Unity 3.x游戏开发实例>一书中的第1章,第1.2节风靡全球的Unity,作者邓文渊,更多章节内容可以访问云栖社区"异步社区"公众号查看 1 ...

  6. 《Unity 3.x游戏开发实例》一第2章 让我们从天空开始

    本节书摘来异步社区<Unity 3.x游戏开发实例>一书中的第2章,第2.1节,作者: [加]Ryan Henson Creighton 译者: 师蓉 责编: 陈冀康,更多章节内容可以访问 ...

  7. 《Unity 3.x游戏开发实例》——1.5节欢迎来到Unity 3D

    本节书摘来自异步社区<Unity 3.x游戏开发实例>一书中的第1章,第1.5节欢迎来到Unity 3D,作者邓文渊,更多章节内容可以访问云栖社区"异步社区"公众号查看 ...

  8. 《Unity 3.x游戏开发实例》——2.13节适合上千款游戏的机制

    本节书摘来自异步社区<Unity 3.x游戏开发实例>一书中的第2章,第2.13节适合上千款游戏的机制,作者 [加]Ryan Henson Creighton,更多章节内容可以访问云栖社区 ...

  9. 《Unity 3.x游戏开发实例》——2.11节《Artillery Live!》

    本节书摘来自异步社区<Unity 3.x游戏开发实例>一书中的第2章,第2.11节<Artillery Live!>,作者 [加]Ryan Henson Creighton,更 ...

  10. 《Unity 3.x游戏开发实例》——2.10节注意

    本节书摘来自异步社区<Unity 3.x游戏开发实例>一书中的第2章,第2.10节注意,作者 [加]Ryan Henson Creighton,更多章节内容可以访问云栖社区"异步 ...

最新文章

  1. java安全接口调用_步骤3:调用Java接口
  2. Boost:以协程的方式实现重构echo服务器的实例
  3. DirectFB的架构介绍
  4. BigDecimal加减乘除运算
  5. python实验九答案_Python实验九
  6. 解决报错:java.lang.NoSuchMethodException: com.tangyuan.entity.RicherProduct.<init>()
  7. 洛谷P1901 发射站
  8. vue项目原理分析-3:vuex
  9. Jakarta EE工作组正式成立
  10. 斐波那契数列的第N项
  11. 登陆豆瓣显示服务器开小差,豆瓣打不开
  12. 文件及代码代码命名规则
  13. 微信小程序switch样式修改
  14. 软件测试 实验一 软件测试案例分析
  15. 使用Arduino读取RC接收机PWM信号的三种方式
  16. 有感觉,有深意的说辞
  17. python节日贺卡绘制
  18. 如何解决Mysql忘记用户名和密码
  19. 企业工商四要素核验是对哪些信息进行验证?
  20. java的nullpoint_java.lang.NullPointerException

热门文章

  1. 洛谷P1725 琪露诺
  2. android网络权限动态,Android权限详解(含6.0动态申请)
  3. 《哈利·波特与混血王子》(Harry Potter and the Half-Blood Prince)[DVDRip]
  4. springboot中汉字转拼音
  5. 暴躁是企业家的性格?
  6. CyanogenMod源码下载和编译
  7. 古镇、温泉、阳澄湖品蟹二日游--这个周末,终于放松了一下。
  8. iTOP-4418开发板Android7.1系统支持RFID、VGA、继电器、LOAR、CAN-RS485
  9. spyder怎么执行html文件,spyder添加快捷键
  10. 是java运行时环境的缩写,java运行环境的英文缩写