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

news/2024/11/19 13:23:10/

文章目录

  • 本章目标
  • 防御塔策划
  • 四种防御塔
  • 防御塔配置文件
  • 每关可选不同的防御塔
  • 加载配置
  • 制作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学习笔记目录整理


http://www.ppmy.cn/news/377955.html

相关文章

植物大战僵尸阳光冷却地址

打开游戏 开始搜索 搜索未知的初始值 然后无限次的进入游戏&#xff0c;返回。搜索减少的数值 过滤一下无用的数据&#xff0c;搜索没变动的数值 过滤一下无用的数据&#xff0c;搜索比10000小的值 搜索结果 最后得到5个地址&#xff0c;我们进行筛选 修改…

Xilinx 7系列FPGA简介--选型参考

Xilinx-7系列FPGA 主要包括&#xff1a;Spartan-7、Artix-7、Kintex-7、Virtex-7。其性能、密度、价格也随着系列的不同而提升。和前几代FPGA产品不同的是&#xff0c;7系列FPGA采用的是统一的28nm设计架构&#xff0c;客户在不同子系列的使用方式上是统一的&#xff0c;消除了…

说出我的故事,献给正在迷茫的你

今天在翻看 Blink 的时候&#xff0c;可能正值毕业季&#xff0c;发现好多人陷入迷茫。于是放下本来亟待今日开发的项目任务&#xff0c;牺牲了每日常规做晚饭的时间&#xff0c;花了整整一天&#xff0c;思如泉涌&#xff0c;行云流水般一气呵成&#xff0c;写下了我的故事&am…

天龙八部TLBB系列 - 关于技能冷却和攻击范围数量的问题

往期文章分享 点击跳转=>《导航贴》- Unity手册,系统实战学习点击跳转=>《导航贴》- Android手册,重温移动开发👉关于作者 众所周知,人生是一个漫长的流程,不断克服困难,不断反思前进的过程。在这个过程中会产生很多对于人生的质疑和思考,于是我决定将自己的思考…

冷却水的循环方式有哪几种_循环水冷却设备 循环冷却水设备都有哪几种

2, 循环水处理设备冷却系统主要分为哪几种? 在直流循环水处理设备冷却系统中,冷却水仅仅通过换热设备一次,用过后水就被排放掉。因此,它的用水量很大,而排出水的温升却很小,水中各种矿物质和离子含量基本上保持不变。这种冷却水系统不需要其他冷却水构筑物,因此投资少、…

aspen吸收塔是哪个_Aspen吸收塔的设计说明

SO 2吸收塔的设计计算 矿石焙烧炉送出的气体冷却到25℃后送入填料塔中&#xff0c;用20℃清水洗涤以除去其中的SO 2。入塔的炉气流量为2400h m /3&#xff0c;其中SO 2摩尔分率为0.05&#xff0c;要求SO 2的吸收率为95%。吸收塔为常压操作。 试设计该填料吸收塔。 解 (1)设计方…

数据中心服务器冷却技术,盘点数据中心液体冷却系统

多年来,由于增加服务器的密度并减少其体积的大小,服务器的密度变得越来越高,数据中心正日益产生更多的热量。因此,每平方英尺产生热量的瓦数正在不断上升,这种功率密度的增加严重制约了传统的冷却方法和技术。液体冷却作为是数据中心最新的制冷技术,正在被人们所接纳并应…

冷却水的循环方式有哪几种_冷却水的循环系统及组成基本原理

冷却塔冷却水的循环系统 冷却水的循环系统及组成循环冷却水系统由冷、热水池、泵房(站)、被冷却的设备或产品、冷却设备、管路系统等组成。示意图见图4-1。 图4-1 的工艺流程为:冷却设备或产品后温度升高的热水流入热水池,经热水泵提升后流入冷却塔进行冷却,经冷却后的冷水流…