【Unity】动作游戏开发实战详细分析-06-技能系统设计
基本思想
不同的技能可以设计为技能模版,当角色释放技能时,会通过模版ID将它进行实例化,这个实例技能类可以是一个挂载的MonoBehaviour组件或者通过上下文传入的独立对象
其次,考虑技能是否共用的问题,如果一个技能,玩家和敌人都可以使用,是否需要设计更为严谨的上下文接口?在动作游戏中,真正需要共用技能的情况相对比价多见。
系统设计
我们首先设计技能基本接口
它包含了:
属性-技能ID方法-序列化恢复方法-执行
public interface ISkillBase{int ID { get; }//技能IDvoid SerializeRecovery(SkillContext skillContext);//序列化恢复void Execute(Action onFinished);//技能执行}
其中序列化恢复需要传入技能上下文,它是一个结构体,定义如下,它存储了该技能的技能释放者以及使用按键
public struct SkillContext{public GameObject GameObject { get; set; }//技能释放者引用public KeyCode TriggerKey { get; set; }}
然后,我们继续设计技能接口
新增接口包含:
模版注册回调函数模版注销回调函数技能实例化
public interface ISkill : ISkillBase{void OnTemplateRegist();//模板注册回调void OnTemplateUnregist();//模板反注册回调ISkillBase Instantiate(SkillContext skillContext);//技能对象实例化}
最后,定义我们的抽象类技能模版
它包含基本属性和字段
属性:ID
这里有一点需要注意,Skill实现了ISkill接口,它就会有一个公开的ID,这个ID和现在我们定义的ID不是一个东西。其次,模版类中的东西均是不可访问,对技能的访问只能通过ISkill接口进行访问,这里使用了类似的技术使的所有东西被封闭封装
using System;namespace ACTBook{public abstract class Skill : ISkill, ICloneable{protected abstract int ID { get; }protected SkillContext mSkillContext;protected abstract void Execute(Action onFinished);protected virtual void OnTemplateRegist(){}protected virtual void OnTemplateUnregist(){}protected virtual void OnInstantiate(){}protected virtual void SerializeRecovery(SkillContext skillContext){}protected virtual ISkillBase SkillInstantiate(SkillContext skillContext){var instantiateSkill = Clone() as Skill;instantiateSkill.mSkillContext = skillContext;instantiateSkill.OnInstantiate();return instantiateSkill;}#region --- ISkillBase Members ---int ISkillBase.ID { get { return this.ID; } }void ISkillBase.Execute(Action onFinished){this.Execute(onFinished);}ISkillBase ISkill.Instantiate(SkillContext skillContext){return SkillInstantiate(skillContext);}void ISkill.OnTemplateRegist(){OnTemplateRegist();}void ISkill.OnTemplateUnregist(){OnTemplateUnregist();}void ISkillBase.SerializeRecovery(SkillContext skillContext){SerializeRecovery(skillContext);}#endregion#region --- ICloneable Members ---public object Clone(){return base.MemberwiseClone();}#endregion}}
仅仅这些,我们还无法实例化技能,我们还需要一个技能管理类
它是一个单例,并且作为一个可用组件
通过技能模版字典存储所有的基本技能模版,通过公共接口对公共技能进行访问获取,这样的设计使的所有的技能都只需要实例化一次,因为它是共用的。
public class SkillManager : MonoBehaviour{static bool mIsDestroying;static SkillManager mInstance;//单例对象public static SkillManager Instance{get{if (mIsDestroying) return null;if (mInstance == null){mInstance = new GameObject("[SkillManager]").AddComponent<SkillManager>();DontDestroyOnLoad(mInstance.gameObject);}return mInstance;}}Dictionary<int, ISkill> mSkillTemplateDict;//技能模板字典void Awake(){mSkillTemplateDict = new Dictionary<int, ISkill>(10);}void OnDestroy(){mIsDestroying = true;//单例处理}public void RegistToTemplate(ISkill skill)//模板注册{mSkillTemplateDict.Add(skill.ID, skill);}public bool UnregistFromTemplate(int skillID)//模板反注册{return mSkillTemplateDict.Remove(skillID);}public ISkillBase InstantiateSkill(int skillID, SkillContext skillContext)//技能实例化{return mSkillTemplateDict[skillID].Instantiate(skillContext);}}
然后我们最后只需要定义一个技能初始化的类,来对我们自己个性化的技能进行模版注册即可
并使用[DefaultExecutionOrder(-100)]
来让它的执行顺序优先,防止出现空异常
[DefaultExecutionOrder(-100)]public class SkillManagerInitialization : MonoBehaviour{void Awake(){SkillManager.Instance.RegistToTemplate(new PlayerSkill_Roll());SkillManager.Instance.RegistToTemplate(new PlayerSkill_SkillAttack1());SkillManager.Instance.RegistToTemplate(new PlayerSkill_SkillAttack2());}}
如果觉得《【Unity】动作游戏开发实战详细分析-06-技能系统设计》对你有帮助,请点赞、收藏,并留下你的观点哦!