目标选择器接口,只定义了一个方法,选择符合条件的目标并返回;
//策略模式 将选择算法进行抽象 /// <summary>攻击目标选择算法</summary> public interface IAttackSelector { ///<summary>目标选择算法</summary> GameObject[] SelectTarget(SkillData skillData, Transform skillTransform); }LineAttackSelector,CircleAttackSelector,SectorAttackSelector线性,圆形,扇形目标选择器,继承该接口;
就只展示一个了CircleAttackSelector;
class CircleAttackSelector : IAttackSelector { public GameObject[] SelectTarget(SkillData skillData, Transform skillTransform) { //发一个球形射线,找出所有碰撞体 var colliders = Physics.OverlapSphere(skillTransform.position, skillData.skill.attackDisntance); if (colliders == null || colliders.Length == 0) return null; //通过碰撞体拿到所有的gameobject对象 String[] attTags = skillData.skill.attckTargetTags; var array = CollectionHelper.Select<Collider, GameObject>(colliders, p => p.gameObject); //挑选出对象中能攻击的,血量大于0的 array = CollectionHelper.FindAll<GameObject>(array, p => Array.IndexOf(attTags, p.tag) >= 0 && p.GetComponent<CharacterStatus>().HP > 0); if (array == null || array.Length == 0) return null; GameObject[] targets = null; //根据技能是单体还是群攻,决定返回多少敌人对象 if (skillData.skill.attackNum == 1) { //将所有的敌人,按与技能的发出者之间的距离升序排列, CollectionHelper.OrderBy<GameObject, float>(array, p => Vector3.Distance(skillData.Owner.transform.position, p.transform.position)); targets = new GameObject[] {array[0]}; } else { int attNum = skillData.skill.attackNum; if (attNum >= array.Length) targets = array; else { for (int i = 0; i < attNum; i++) { targets[i] = array[i]; } } } return targets; } }这里有个问题,技能的目标选择器每次释放技能都会调用,因此会重复频繁的创建,但其实这只是提供方法而已;
解决:使用工厂来缓存目标选择器;
//简单工厂 //创建敌人选择器 public class SelectorFactory { //攻击目标选择器缓存 private static Dictionary<string, IAttackSelector> cache = new Dictionary<string, IAttackSelector>(); public static IAttackSelector CreateSelector(DamageMode mode) { //没有缓存则创建 if (!cache.ContainsKey(mode.ToString())) { var nameSpace = typeof(SelectorFactory).Namespace; string classFullName = string.Format("{0}AttackSelector", mode.ToString()); if (!String.IsNullOrEmpty(nameSpace)) classFullName = nameSpace + "." + classFullName; Type type = Type.GetType(classFullName); cache.Add(mode.ToString(), Activator.CreateInstance(type) as IAttackSelector); } //从缓存中取得创建好的选择器对象 return cache[mode.ToString()]; } } 小结所有基类,前期准备数据只有这些,另外想Demo更有体验感,还需要有角色控制,相机跟随脚本;
之后就是技能管理系统,技能释放器等;