角色技能系统

  • 架构分析
  • 类的设计
    • 技能数据类
    • 技能管理类
    • 技能释放类
    • 类的调用流程
  • 封装变化
  • 具体代码
    • 技能数据类
    • 技能管理类
    • 选择攻击目标接口
    • 扇形选择攻击目标接口实现
    • 影响效果接口
    • 造成伤害接口实现
    • 技能释放器
    • 近身技能释放类
    • 技能释放类配置工厂类

学习的技能系统。

架构分析

先看一下我Demo中的技能,我方释放了一次普通攻击,
Boss总共释放两个近身技能,一个范围攻击,一个单体攻击
技能的释放流程是,当按下了技能按钮或满足了条件,实例化出技能预制体,受伤方受伤

一个角色肯定要有多个技能。先来分析一下技能的共同点。

1.技能的数据,如攻击距离,攻击角度,角色动画,使用的特效以及对自身、对敌人的影响等数据,所以将技能涉及的数据封装到一个技能数据类中。

2.每个角色拥有多个技能,所有要有一个统一的类来进行技能数据的读取,以及配置技能以及准备技能。

3.每一个技能释放后都有不同的效果,如攻击方式的不同,特殊的效果不同,所有将技能释放后的算法统一交给一个释放类来实现。

类的设计

技能的释放方挂载技能管理类。
技能预制体挂载技能释放类。

技能数据类

储存所有技能的数据,方便统一管理。

技能管理类

通过配置或者读取Json获得并储存当前角色所拥有的所有技能数据,来准备,生成,并且开启技能的冷却,技能释放后续算法需要根据技能的数据来进行计算伤害以及其他效果,所有技能管理类需要将技能数据传给释放类,并且调用释放类中对外提供的执行算法的方法。

技能释放类

根据技能数据执行各种算法。

类的调用流程

大体来说就是技能管理器配置当前角色技能—>准备技能(查找冷却时间为0,)—>生成技能预制体—>查找生成预制体的身上的技能释放类将技能数据传递给技能释放类,并且调用技能释放类中的方法—>技能释放类根据技能数据选择攻击目标,执行各种算法。

封装变化

角色释放技能逻辑有很多,有的是在释放技能的圆形内寻找敌人,有的是在释放技能的一个特殊形状范围内寻找敌人,可能以后还会有特殊的选择敌人的方式。

所有技能在释放完都要有很多逻辑,例如造成伤害,消耗法力值,这个每一个技能都不一样。

技能释放有直接在自身就生成技能特效的就像上面图片那样,还有可能是下图这样在敌方直接生成的技能。还会有可能像火球那样移动到目标再造成伤害的。

具体代码

技能数据类

这个根据具体项目不同配置不同

 public class SkillData{///<summary>技能ID</summary>public int skillID;///<summary>技能名称</summary>public string name;///<summary>技能描述</summary>public string description;///<summary>冷却时间</summary>public int coolTime;///<summary>冷却剩余</summary>public int coolRemain;///<summary>魔法消耗</summary>public int costSP;///<summary>攻击距离</summary>public float attackDistance;/// <summary> 移动速度</summary>public float moveSpeed;///<summary>攻击角度</summary> public float attackAngle;///<summary>攻击目标tags</summary> public string[] attackTargetTags = { "Enemy" };///<summary>攻击目标对象数组</summary>[HideInInspector]public Transform[] attackTargets;///<summary>技能影响类型</summary> public string[] impactType = { "CostSP", "Damage" };///<summary>连击的下一个技能编号</summary>public int nextBatterId;///<summary>伤害比率</summary>public float atkRatio;///<summary>持续时间</summary>public float durationTime;///<summary>伤害间隔</summary>public float atkInterval;///<summary>技能生成位置名称</summary>public string spawnPosName;[HideInInspector]///<summary>技能生成位置</summary>public Transform spawnPos;///<summary>技能所属</summary>[HideInInspector]public GameObject owner;///<summary>技能预制件名称</summary>public string prefabName;///<summary>预制件对象</summary>[HideInInspector]public GameObject skillPrefab;///<summary>动画名称</summary> public string animationName;///<summary>受击特效名称</summary>public string hitFxName;///<summary>受击特效预制件</summary>[HideInInspector]public GameObject hitFxPrefab;///<summary>技能等级</summary>public int level;///<summary>攻击类型 单攻,群攻</summary> public SkillAttackType attackType;/<summary>选择类型 扇形(圆形),矩形</summary>  public SelectorType selectorType;}

技能管理类

public class SkillManager : MonoBehaviour {public SkillData[] skills;private void Start(){for (int i = 0; i < skills.Length; i++){InitSkills(skills[i]);}}/// <summary>/// 准备技能/// </summary>/// <param name="id">技能id</param>/// <returns></returns>public SkillData PrepareSkill(int id){SkillData data = null;for (int i = 0; i < skills.Length; i++){if (skills[i].skillID ==id){data = skills[i];}}//如果当前技能剩余冷却时间小于0 则可以释放if (data.coolRemain <= 0) return data;else return null;}/// <summary>/// 生成技能/// </summary>/// <param name="data">技能数据</param>/// <param name="spawnPos">生成位置 默认自身位置</param>public void GererateSkill(SkillData data){if (data == null) return;GameObject skillGo = GameObjectPool.Instance.CreateObject(data.prefabName,data.skillPrefab, data.spawnPos.position, data.spawnPos.rotation);SkillDeployer deployer = skillGo.GetComponent<SkillDeployer>();//将释放器所需要技能数据赋值deployer.SkillData = data;//释放具体技能效果deployer.DeploySkill();//开启技能冷却StartCoroutine("CoolTimeDown", data);}/// <summary>/// 初始化技能/// </summary>/// <param name="skill"></param>void InitSkills(SkillData data){data.skillPrefab = ResourceManager.Load<GameObject>(data.prefabName);if (string.IsNullOrEmpty(data.spawnPosName)){data.spawnPos = transform;}else{data.spawnPos = transform.FindChildByName(data.spawnPosName);}data.owner = gameObject;}/// <summary>/// 技能冷却/// </summary>/// <param name="data"></param>/// <returns></returns>IEnumerator CoolTimeDown(SkillData data){//将剩余冷却时间设置为技能的冷却时间data.coolRemain = data.coolTime;//技能剩余冷却每秒减少1while (data.coolRemain>0){yield return new WaitForSeconds(1);data.coolRemain--;}}}

选择攻击目标接口

public interface IAttackSelector  {/// <summary>/// 计算攻击目标/// </summary>Transform[] CalculateTarget(SkillData data,Transform skillTf);}

扇形选择攻击目标接口实现

public class SectorAttackSelector : IAttackSelector{public Transform[] CalculateTarget(SkillData data, Transform skillTf){List<Transform> targets = new List<Transform>();//通过技能标签找到所有目标for (int i = 0; i < data.attackTargetTags.Length; i++){GameObject[] tempGo = GameObject.FindGameObjectsWithTag(data.attackTargetTags[i]);//Debug.Log(tempGo[i].name);targets.AddRange(tempGo.Select(g=>g.transform));}//通过向量判断找出集合中角度与距离在攻击范围内的targets = targets.FindAll(t =>//技能预制体距离目标距离小于技能攻击距离Vector3.Distance(skillTf.position, t.position) <= data.attackDistance &&//技能预制体正前方与目标之间的夹角小于攻击角度的一半Vector3.Angle(skillTf.forward, t.position - skillTf.position) <= data.attackAngle / 2);//寻找到生命值大于0的目标targets = targets.FindAll(t=>t.GetComponent<ICharacter>().HP>0);//将集合转化成数组Transform[] result = targets.ToArray();//判断单攻还是群攻 如果是群攻则直接返回当前数组if (data.attackType == SkillAttackType.Group||result.Length==0){return result;}//如果是单攻则返回距离最近的Transform min = result.GetMin(m=>Vector3.Distance(m.position,skillTf.position));return new Transform[] {min};}}

影响效果接口

public interface IImpactEffect {/// <summary>/// 触发影响效果/// </summary>void TriggerImpact(SkillDeployer skillDeployer);}

造成伤害接口实现

public class DamageImpactEffect : IImpactEffect{public void TriggerImpact(SkillDeployer skillDeployer){skillDeployer.StartCoroutine(RepeatDamage(skillDeployer));}/// <summary>/// 重复伤害/// </summary>/// <param name="data"></param>/// <returns></returns>IEnumerator RepeatDamage(SkillDeployer data){float timer = 0;do{OnceDamage(data.SkillData);//每次执行完伤害后等待技能间隔yield return new WaitForSeconds(data.SkillData.atkInterval);timer += data.SkillData.atkInterval;//一直持续到当前技能持续时间结束} while (timer<data.SkillData.durationTime);}/// <summary>/// 单次伤害/// </summary>/// <param name="data"></param>private void OnceDamage(SkillData data){//基础攻击力乘以当前技能攻击比率最终攻击力float atk = data.atkRatio * data.owner.GetComponent<ICharacter>().baseAtk;//遍历攻击目标,造成伤害for (int i = 0; i < data.attackTargets.Length; i++){ICharacter character = data.attackTargets[i].GetComponent<ICharacter>();character.Damage(atk);}}}

技能释放器

public abstract class SkillDeployer : MonoBehaviour {private SkillData skillData;public SkillData SkillData{get{return skillData;}set{skillData = value;InitDeployer();}}/// <summary>/// 攻击目标接口对象/// </summary>private IAttackSelector attackSelector;/// <summary>/// 影响效果接口对象/// </summary>private IImpactEffect[] impactEffects;/// <summary>/// 初始化释放器(创建对象)/// </summary>private void InitDeployer(){//工厂模式创建对象attackSelector = DeployerConfigFactory.CreatAttackSelector(skillData);impactEffects = DeployerConfigFactory.CreatImpactEffect(skillData);}/// <summary>/// 计算攻击目标/// </summary>protected void CalculateTarget(){skillData.attackTargets = attackSelector.CalculateTarget(skillData,transform);}/// <summary>/// 造成影响效果/// </summary>protected void ImpactEffect(){for (int i = 0; i < impactEffects.Length; i++){impactEffects[i].TriggerImpact(this);}}/// <summary>/// 具体释放技能,子类具体实现/// </summary>public abstract void DeploySkill();}

近身技能释放类

近身技能在技能释放出来就可以计算伤害了所以很简单

public class MeleeSkillDeployer : SkillDeployer{public override void DeploySkill(){CalculateTarget();ImpactEffect();}}

技能释放类配置工厂类

public class DeployerConfigFactory  {/// <summary>/// 缓存池/// </summary>private static Dictionary<string,object> cache;static DeployerConfigFactory(){cache = new Dictionary<string, object>();}/// <summary>/// 创建选择敌人接口对象/// </summary>/// <param name="data"></param>/// <returns></returns>public static IAttackSelector CreatAttackSelector(SkillData data){//反射创建对象自定义类名规则 TowerDemo.Skill.枚举名AttackSelectorstring className = string.Format("TowerDemo.Skill.{0}AttackSelector",data.selectorType);return CreatObject<IAttackSelector>(className);}/// <summary>/// 创建影响效果接口对象/// </summary>/// <param name="data"></param>/// <returns></returns>public static IImpactEffect[] CreatImpactEffect(SkillData data){//初始化数组长度IImpactEffect[] impactEffects = new IImpactEffect[data.impactType.Length];//遍历技能影响效果字符串长度,赋值给影响效果接口对象数组for (int i = 0; i < data.impactType.Length; i++){//反射创建对象自定义类名规则 TowerDemo.Skill.枚举名ImpactEffectstring className = string.Format("TowerDemo.Skill.{0}ImpactEffect", data.impactType[i]);impactEffects[i] = CreatObject<IImpactEffect>(className);}return impactEffects;}/// <summary>/// 通过反射创建对象/// </summary>/// <typeparam name="T">创建对象的类型</typeparam>/// <param name="className">类名</param>/// <returns></returns>private static T CreatObject<T>(string className) where T:class{//如果缓存池没有当前对象创建,如果有则直接返回if (!cache.ContainsKey(className)){Type type = Type.GetType(className);object instance = Activator.CreateInstance(type);cache.Add(className,instance);}return cache[className] as T;}}

Unity技能系统架构相关推荐

  1. Unity技能系统框架(一)技能效果

    一场疫情,让我居家办公了两个月,感觉人生快颓废了-- 这里记录下个人仿DOTA2编写的技能系统结构,借鉴了知乎博文的编辑器思想,使用了ProtoBuf和AdvancedInspector,最后仿照DO ...

  2. Unity技能系统框架(二)技能抽象模块细化

    看了上一篇的技能效果Demo,接下来大概说下该技能系统可实现的一些技能事件和效果.技能一般包含这几个要素: 数据(配置表和资源).技能属性(消耗能量.冷却时间等).事件操作(这是一个大的范畴,后面分析 ...

  3. Unity技能系统框架(三)分析一个具体被动技能

    这一篇分析一个具体的被动技能:蚁人的影矛 首先看下技能描述:"每个蚁人都是天生的掷手,投掷出长矛刺穿目标的身躯.普通攻击有几率对攻击范围内其他{0}名目标进行相同攻击.",只要是个 ...

  4. Unity教程之-Unity游戏技能Skill系统架构设计

    我想把技能做的比较牛逼,所以项目一开始我就在思考,是否需要一个灵活自由的技能系统架构设计,传统的技能设计,做法都是填excel表,技能需要什么,都填表里,很死板,比如有的技能只需要1个特效,有的要10 ...

  5. 三.技能系统 [Unity_Learn_RPG_1]

    三.技能系统 一.技能系统架构 excel转xml 直接excel就能转= = 二.技能系统管理类和Unity事件 1.Unity事件 老师说,开发的时候基本不用搞这些 = =. 1).VRTK UI ...

  6. 系统架构技能之设计模式-抽象工厂模式

    一.上篇回顾 上篇我们主要讲述了简单工厂模式和工厂模式.并且分析了每种模式的应用场景和一些优缺点,我们现在来回顾一下: 简单工厂模式:一个工厂负责所有类型对象的创建,不支持无缝的新增新的类型对象的创建 ...

  7. 从程序员到CTO的Java技术路线图 JAVA职业规划 JAVA职业发展路线图 系统后台框架图、前端工程师技能图 B2C电子商务基础系统架构解析...

    http://zz563143188.iteye.com/blog/1877266在技术方面无论我们怎么学习,总感觉需要提升自已不知道自己处于什么水平了.但如果有清晰的指示图供参考还是非常不错的,这样 ...

  8. unity简单技能系统

    unity简单技能系统 类类型概览 CharacterSkillManager      角色技能管理器 挂载在角色 持有SkillData与释放器 通过释放器进行技能释放 SkillDeployer ...

  9. java职业发展路线图_从程序员到CTO的Java技术路线图 JAVA职业规划 JAVA职业发展路线图 系统后台框架图、前端工程师技能图 B2C电子商务基础系统架构解析...

    http://zz563143188.iteye.com/blog/1877266在技术方面无论我们怎么学习,总感觉需要提升自已不知道自己处于什么水平了.但如果有清晰的指示图供参考还是非常不错的,这样 ...

最新文章

  1. shared_ptr和weak_ptr使用介绍
  2. 将查询结果插入到现有表中
  3. PM——【1】维护功能位置主数据
  4. mysql 浮点数定义2_MySQL学习笔记(二):数据类型
  5. 神奇的事情--长见识了
  6. wenstorm设置谷歌_WebStorm+Chrome调试Vue步骤
  7. 使用jXLS将Excel文件解析为JavaBeans
  8. 精读《你不知道的javascript》中卷
  9. STM32-SPI通信
  10. 存储极客谈“SPC-1负载分析与AFA寿命评估”
  11. c++14 0 名字空间和条件编译
  12. ubuntu下安装gcc
  13. Android相同包名不同签名的apk安装失败问题分析
  14. Java学生档案管理系统的设计与实现
  15. godot着色器shader效果收集
  16. cad工具箱详细讲解_正确使用AutoCAD插件CAD工具箱如何使用?
  17. Elastic:Data tiers 介绍及索引生命周期管理 - 7.10 之后版本
  18. killall杀死nginx顽固进程
  19. 中国天气网免费天气预报接口API
  20. javascript百炼成仙 第一章 掌握JavaScript基础1.8 对象的取值

热门文章

  1. 什么是sp,怎么运作,他们是怎么发财的
  2. 二维码门禁(基于微信小程序)
  3. 『 云原生·Docker』Docker镜像分层与Docker镜像操作(二)
  4. 浅谈聚合支付系统的安全性
  5. python量化投资实训班_Python量化投资实训营
  6. 16个千兆光口8个千兆Combo光电复用口管理型工业以太网交换机环网+WEB管理+SNMP+VLAN
  7. plsql导出查询结果
  8. 求助vmbox更新之后打不开了
  9. 5-2 uniapp 打包 app 自定义开屏页
  10. Telegram、Telethon