Unity MMO游戏架构设计(一):角色设计

发表于2017-05-07
评论1 3.3k浏览

想免费获取内部独家PPT资料库?观看行业大牛直播?点击加入腾讯游戏学院游戏程序行业精英群

711501594

考虑到有很多人还没有过MMO大型网络游戏中的架构设计的经历,本篇文章就给大家介绍的是MMO游戏架构设计中角色的设计,主要针对的是商业游戏中的结构设计,游戏中都会有英雄角色,这些英雄是受玩家控制的,这些英雄会随着版本的迭代而去扩充,这就需要我们在编写代码时要设计一个能扩充的架构。Unity自身提供了一个非常好的组件概念,每个对象身上可以挂接属于自己的组件,我们在设计角色架构时也是采用这种理念。架构没有好坏之分,只要能满足项目需求就可以了。

在Unity引擎中各个类的继承方式如下所示:



我们的角色设计也是参考Unity的类结构设计如下所示:

其中BaseObject是所有对象类的根,也就是祖宗级别,这个相当于Unity中的Object类,在它的下面是BaseActor类,从BaseActor类中延伸出两个儿子一个是3D的模型表示的BaseCharacter类和特效BaseEff类。

以前开发端游的时候,也是采用这种方式。针对BaseCharacter类,又延伸出两个继承类BaseHero和BaseMonster。BaseHero类再下面是具体的英雄类,比如武士,刺客,道士等英雄,BaseMonster类的子类是具体的怪物类。

接下来要去做控制类了,BaseCtrl,该类主要是用于控制上述实现的各个类。这个设计类似MVC中的C也就是是说Control,用于控制英雄和怪物或者特效。

用心的做架构设计目的是为了方便后期进行扩展,下面把实现的代码给读者展示如下:

在BaseActor前面还有一个父类是BaseObject类,作为BaseObject类,也就是所有对象类的根,实现如下所示:

[csharp] view plain copy
 
  1. public class BaseObject:MonoBehaviour  
  2.  {  
  3.      protected int m_Id;  
  4.   
  5.      ///   
  6.      /// 标识移除后储存  
  7.      ///   
  8.      protected bool m_bRererveRemove;  
  9.        
  10.      protected Dictionary m_MsgFuncs = new Dictionary();  
  11.   
  12.      protected string m_Name;  
  13.   
  14.      ///   
  15.      /// 对象类别  
  16.      ///   
  17.      protected EnumDefine.ObjType m_ObjType;  
  18.      protected int m_Uid;  
  19.      public virtual void Init(int uid)  
  20.      {  
  21.          this.m_Uid = uid;  
  22.          this.m_ObjType = EnumDefine.ObjType.None;  
  23.          this.m_MsgFuncs.Clear();  
  24.      }  
  25.   
  26.      public virtual void Enable(Vector3 pos)  
  27.      {  
  28.          base.gameObject.transform.position = pos;  
  29.          this.m_bRererveRemove = false;  
  30.      }  
  31.   
  32.      public virtual void Disable() { }  
  33.      public int GetId()  
  34.      {  
  35.          return this.m_Id;  
  36.      }  
  37.      public void SetName(string name)  
  38.      {  
  39.          this.m_Name = name;  
  40.          this.gameObject.name = name;  
  41.      }  
  42.   
  43.      public string GetName()  
  44.      {  
  45.          return this.m_Name;  
  46.      }  
  47.   
  48.      public EnumDefine.ObjType GetObjType()  
  49.      {  
  50.          return this.m_ObjType;  
  51.      }  
  52.   
  53.      public int GetUid()  
  54.      {  
  55.          return this.m_Uid;  
  56.      }  
  57.   
  58.      private void OnDestroy()  
  59.      {  
  60.          this.OnObjectDestroy();  
  61.      }  
  62.   
  63.      public virtual void OnObjectDestroy() { }  
  64.   
  65.      ///   
  66.      /// 执行指令  
  67.      ///   
  68.      ///   
  69.      ///   
  70.      public void OnObjMsg(eCmd cmd, IBaseMsgData baseData)  
  71.      {  
  72.          if (this.m_MsgFuncs.ContainsKey(cmd))  
  73.          {  
  74.              this.m_MsgFuncs[cmd](baseData);  
  75.          }  
  76.      }  
  77.   
  78.      ///   
  79.      /// 注册消息指令  
  80.      ///   
  81.      ///   
  82.      ///   
  83.      protected void RegisterMsgHandler(eCmd cmd, OnMsgFunc func)  
  84.      {  
  85.          this.m_MsgFuncs.Add(cmd, func);  
  86.      }  
  87.      public void SetId(int id)  
  88.      {  
  89.          this.m_Id = id;  
  90.      }  
  91.   
  92.     protected void Update()  
  93.      {  
  94.          this.UpdateObj(Time.deltaTime);  
  95.      }  
  96.   
  97.      protected virtual void UpdateObj(float delta) { }  
  98.      public delegate void OnMsgFunc(IBaseMsgData bmd);  
  99.  }  
这个类使用了对象消息函数OnObjMsg用于执行消息指令,ReginsterMsgHandler函数用于消息的添加,通过对象类的根可以看出,模块之间是通过

消息执行的。实现完了对象的根,接下来实现BaseActor类,下面把类的具体实现给读者展示如下:

[csharp] view plain copy
 
  1. public class BaseActor : BaseObject  
  2. {  
  3.   
  4.     ///   
  5.     /// AI 控制  
  6.     ///   
  7.     protected BaseAICtrl m_AiCtrl;  
  8.   
  9.     ///   
  10.     /// 普通控制  
  11.     ///   
  12.     protected BaseCtrl m_Ctrl;  
  13.     protected bool m_bUpdateShineEff;  
  14.       
  15.     ///   
  16.     /// 当前状态  
  17.     ///   
  18.     protected int m_CurState;  
  19.   
  20.     ///   
  21.     /// 方位  
  22.     ///   
  23.     protected Vector3 m_Direction;  
  24.   
  25.     ///   
  26.     /// 动画组件  
  27.     ///   
  28.     protected Animator animator;  
  29.   
  30.     ///   
  31.     /// 模型fbx  
  32.     ///   
  33.     public GameObject m_FBX;  
  34.   
  35.     ///   
  36.     /// 材质列表  
  37.     ///   
  38.     protected List m_Materials = new List();  
  39.   
  40.     ///   
  41.     /// 上一状态  
  42.     ///   
  43.     protected int m_PrevState;  
  44.     ///   
  45.     /// 状态键值对  
  46.     ///   
  47.     protected Dictionary<int, StateFunc> m_StateFunc = new Dictionary<int, StateFunc>();  
  48.   
  49.     ///   
  50.     /// 状态参数  
  51.     ///   
  52.     protected StateParam m_StateParam = new StateParam();  
  53.     protected float m_StateTimer;  
  54.     public override void Init(int uid)  
  55.     {  
  56.         base.Init(uid);  
  57.         this.m_StateFunc.Clear();  
  58.         this.RefreshMaterialInfo();  
  59.         if(this.m_FBX !=null)  
  60.             animator = this.m_FBX.GetComponent();  
  61.     }  
  62.   
  63.     public override void Enable(Vector3 pos)  
  64.     {  
  65.         base.Enable(pos);  
  66.         this.m_Direction = Vector3.forward;  
  67.         this.m_ShineValue = 0f;  
  68.         this.m_ShineTimer = 0f;  
  69.         this.m_bUpdateShineEff = false;  
  70.         this.m_PrevState = 0;  
  71.         this.m_CurState = 0;  
  72.         this.m_StateTimer = 0;  
  73.   
  74.     }  
  75.   
  76.     protected override void UpdateObj(float delta)  
  77.     {  
  78.         base.UpdateObj(delta);  
  79.   
  80.         if (this.m_bUpdateShineEff)  
  81.         {  
  82.             UpdateShineEff(delta);  
  83.         }  
  84.   
  85.         if (this.m_StateFunc.ContainsKey(this.m_CurState) && (this.m_StateFunc[this.m_CurState].updateFunc != null))  
  86.         {  
  87.             this.m_StateFunc[this.m_CurState].updateFunc(delta);  
  88.         }  
  89.               
  90.     }  
  91.     ///   
  92.     /// 刷新材质球信息  
  93.     ///   
  94.     public void RefreshMaterialInfo()  
  95.     {  
  96.         this.m_Materials.Clear();  
  97.         SkinnedMeshRenderer[] smrs = gameObject.GetComponentsInChildren();  
  98.         for (int i = 0; i < smrs.Length; i++)  
  99.         {  
  100.             for (int k = 0; k < smrs[i].materials.Length; k++)  
  101.             {  
  102.                 this.m_Materials.Add(smrs[i].materials[k]);  
  103.             }  
  104.         }  
  105.   
  106.         MeshRenderer[] mrs = gameObject.GetComponentsInChildren();  
  107.         for (int j = 0; j < mrs.Length; j++)  
  108.         {  
  109.             for (int m = 0; m < mrs[j].materials.Length; m++)  
  110.             {  
  111.                 this.m_Materials.Add(mrs[j].materials[m]);  
  112.             }  
  113.         }  
  114.     }  
  115.   
  116.     public void ChangeAnimSpeed(string aniName, float speed)  
  117.     {  
  118.         if (this.m_FBX.GetComponent() != null)  
  119.         {  
  120.             this.m_FBX.GetComponent()[aniName].speed = speed;  
  121.         }  
  122.     }  
  123.     public void SetCtrl(BaseCtrl ctrl)  
  124.     {  
  125.         this.m_Ctrl = ctrl;  
  126.     }  
  127.   
  128.     public BaseCtrl GetCtrl()  
  129.     {  
  130.         return this.m_Ctrl;  
  131.     }  
  132.   
  133.     public int GetCurState()  
  134.     {  
  135.         return this.m_CurState;  
  136.     }  
  137.   
  138.     public Vector3 GetDirection()  
  139.     {  
  140.         return this.m_Direction;  
  141.     }  
  142.     public void Look(Vector3 dir)  
  143.     {  
  144.         if (dir != Vector3.zero)  
  145.         {  
  146.             dir.Normalize();  
  147.             base.gameObject.transform.localRotation = Quaternion.LookRotation(dir);  
  148.             this.m_Direction = dir;  
  149.         }  
  150.     }  
  151.     ///   
  152.     /// 注册动画事件  
  153.     ///   
  154.     ///   
  155.     ///   
  156.     ///   
  157.     protected void RegisterAnimEvent(string aniName, string funcName, float time)  
  158.     {  
  159.         AnimationEvent evt = new AnimationEvent  
  160.         {  
  161.             time = time,  
  162.             functionName = funcName,  
  163.             intParameter = m_Uid  
  164.         };  
  165.         AnimationClip ac = this.m_FBX.GetComponent().GetClip(aniName);  
  166.           
  167.         if (ac == null)  
  168.             Debug.LogError("Not Found the AnimationClip:" + aniName);  
  169.         else  
  170.             this.m_FBX.GetComponent().GetClip(aniName).AddEvent(evt);  
  171.   
  172.     }  
  173.   
  174.     ///   
  175.     /// 注册状态事件  
  176.     ///   
  177.     ///   
  178.     ///   
  179.     ///   
  180.     ///   
  181.     protected void RegistState(int state, StateFunc.EnterFunc enter, StateFunc.UpdateFunc update, StateFunc.ExitFunc exit)  
  182.     {  
  183.         StateFunc func = new StateFunc  
  184.         {  
  185.             enterFunc = enter,  
  186.             updateFunc = update,  
  187.             exitFunc = exit  
  188.         };  
  189.   
  190.         this.m_StateFunc.Add(state, func);  
  191.         //Debug.Log("State:" + state);  
  192.     }  
  193.   
  194.     ///   
  195.     /// 切换状态   
  196.     ///   
  197.     ///   
  198.     ///   
  199.     public void ChangeState(int state, StateParam param = null)  
  200.     {  
  201.         int curState = this.m_CurState;  
  202.         this.m_PrevState = curState;  
  203.         this.m_CurState = state;  
  204.   
  205.         if (this.m_StateFunc.ContainsKey(curState) && (this.m_StateFunc[curState].exitFunc) != null)  
  206.         {  
  207.             this.m_StateFunc[curState].exitFunc();  
  208.         }  
  209.   
  210.         if (this.m_StateFunc.ContainsKey(this.m_CurState) && (this.m_StateFunc[this.m_CurState].enterFunc) != null)  
  211.         {  
  212.             this.m_StateFunc[this.m_CurState].enterFunc(param);  
  213.         }  
  214.         this.m_StateTimer = 0f;  
  215.   
  216.     }  
  217.   
  218.     ///   
  219.     /// 转向  
  220.     ///   
  221.     ///   
  222.     ///   
  223.     public void Turn(float angle, float duration)  
  224.     {  
  225.         Quaternion rot = Quaternion.AngleAxis(angle, Vector3.up);  
  226.         TweenRotation.Begin(base.gameObject, duration, rot);  
  227.         this.m_Direction = (Vector3)(rot * Vector3.forward);  
  228.     }  
  229.   
  230.     ///   
  231.     /// 转身  
  232.     ///   
  233.     ///   
  234.     ///   
  235.     public void Turn(Vector3 targetPos, float duration)  
  236.     {  
  237.         Vector3 forward = targetPos - gameObject.transform.position;  
  238.         Quaternion rot = Quaternion.LookRotation(forward);  
  239.  iTween.RotateTo (this.gameObject, iTween.Hash ("rotation", rot.eulerAngles, "time", duration, "easetype""linear"));  
  240.         this.m_Direction = forward;  
  241.     }  
  242.       
  243.     ///   
  244.     /// 动作播放New Mecanim System  
  245.     ///   
  246.     ///   
  247.     ///   
  248.     public void PlayAnim(string condition,float speed = 0f,float value=0,Type t = null)  
  249.     {  
  250.         animator.speed = speed;  
  251.         if (t == typeof(int))  
  252.         {  
  253.             animator.SetInteger(condition, (int)value);                
  254.         }  
  255.         else if (t == typeof(float))  
  256.         {  
  257.             animator.SetFloat(condition, value);  
  258.         }  
  259.         else  
  260.         {  
  261.             animator.SetTrigger(condition);  
  262.         }              
  263.     }  
  264.   
  265. }  

该类主要实现了类的注册状态和切换状态,以及动画注册事件。

原文链接

著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引

游戏学院公众号二维码
腾讯游戏学院
微信公众号

提供更专业的游戏知识学习平台