考虑到有很多人还没有过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类,也就是所有对象类的根,实现如下所示:
- public class BaseObject:MonoBehaviour
- {
- protected int m_Id;
-
-
-
-
- protected bool m_bRererveRemove;
-
- protected Dictionary m_MsgFuncs = new Dictionary();
-
- protected string m_Name;
-
-
-
-
- protected EnumDefine.ObjType m_ObjType;
- protected int m_Uid;
- public virtual void Init(int uid)
- {
- this.m_Uid = uid;
- this.m_ObjType = EnumDefine.ObjType.None;
- this.m_MsgFuncs.Clear();
- }
-
- public virtual void Enable(Vector3 pos)
- {
- base.gameObject.transform.position = pos;
- this.m_bRererveRemove = false;
- }
-
- public virtual void Disable() { }
- public int GetId()
- {
- return this.m_Id;
- }
- public void SetName(string name)
- {
- this.m_Name = name;
- this.gameObject.name = name;
- }
-
- public string GetName()
- {
- return this.m_Name;
- }
-
- public EnumDefine.ObjType GetObjType()
- {
- return this.m_ObjType;
- }
-
- public int GetUid()
- {
- return this.m_Uid;
- }
-
- private void OnDestroy()
- {
- this.OnObjectDestroy();
- }
-
- public virtual void OnObjectDestroy() { }
-
-
-
-
-
-
- public void OnObjMsg(eCmd cmd, IBaseMsgData baseData)
- {
- if (this.m_MsgFuncs.ContainsKey(cmd))
- {
- this.m_MsgFuncs[cmd](baseData);
- }
- }
-
-
-
-
-
-
- protected void RegisterMsgHandler(eCmd cmd, OnMsgFunc func)
- {
- this.m_MsgFuncs.Add(cmd, func);
- }
- public void SetId(int id)
- {
- this.m_Id = id;
- }
-
- protected void Update()
- {
- this.UpdateObj(Time.deltaTime);
- }
-
- protected virtual void UpdateObj(float delta) { }
- public delegate void OnMsgFunc(IBaseMsgData bmd);
- }
这个类使用了对象消息函数OnObjMsg用于执行消息指令,ReginsterMsgHandler函数用于消息的添加,通过对象类的根可以看出,模块之间是通过消息执行的。实现完了对象的根,接下来实现BaseActor类,下面把类的具体实现给读者展示如下:
- public class BaseActor : BaseObject
- {
-
-
-
-
- protected BaseAICtrl m_AiCtrl;
-
-
-
-
- protected BaseCtrl m_Ctrl;
- protected bool m_bUpdateShineEff;
-
-
-
-
- protected int m_CurState;
-
-
-
-
- protected Vector3 m_Direction;
-
-
-
-
- protected Animator animator;
-
-
-
-
- public GameObject m_FBX;
-
-
-
-
- protected List m_Materials = new List();
-
-
-
-
- protected int m_PrevState;
-
-
-
- protected Dictionary<int, StateFunc> m_StateFunc = new Dictionary<int, StateFunc>();
-
-
-
-
- protected StateParam m_StateParam = new StateParam();
- protected float m_StateTimer;
- public override void Init(int uid)
- {
- base.Init(uid);
- this.m_StateFunc.Clear();
- this.RefreshMaterialInfo();
- if(this.m_FBX !=null)
- animator = this.m_FBX.GetComponent();
- }
-
- public override void Enable(Vector3 pos)
- {
- base.Enable(pos);
- this.m_Direction = Vector3.forward;
- this.m_ShineValue = 0f;
- this.m_ShineTimer = 0f;
- this.m_bUpdateShineEff = false;
- this.m_PrevState = 0;
- this.m_CurState = 0;
- this.m_StateTimer = 0;
-
- }
-
- protected override void UpdateObj(float delta)
- {
- base.UpdateObj(delta);
-
- if (this.m_bUpdateShineEff)
- {
- UpdateShineEff(delta);
- }
-
- if (this.m_StateFunc.ContainsKey(this.m_CurState) && (this.m_StateFunc[this.m_CurState].updateFunc != null))
- {
- this.m_StateFunc[this.m_CurState].updateFunc(delta);
- }
-
- }
-
-
-
- public void RefreshMaterialInfo()
- {
- this.m_Materials.Clear();
- SkinnedMeshRenderer[] smrs = gameObject.GetComponentsInChildren();
- for (int i = 0; i < smrs.Length; i++)
- {
- for (int k = 0; k < smrs[i].materials.Length; k++)
- {
- this.m_Materials.Add(smrs[i].materials[k]);
- }
- }
-
- MeshRenderer[] mrs = gameObject.GetComponentsInChildren();
- for (int j = 0; j < mrs.Length; j++)
- {
- for (int m = 0; m < mrs[j].materials.Length; m++)
- {
- this.m_Materials.Add(mrs[j].materials[m]);
- }
- }
- }
-
- public void ChangeAnimSpeed(string aniName, float speed)
- {
- if (this.m_FBX.GetComponent() != null)
- {
- this.m_FBX.GetComponent()[aniName].speed = speed;
- }
- }
- public void SetCtrl(BaseCtrl ctrl)
- {
- this.m_Ctrl = ctrl;
- }
-
- public BaseCtrl GetCtrl()
- {
- return this.m_Ctrl;
- }
-
- public int GetCurState()
- {
- return this.m_CurState;
- }
-
- public Vector3 GetDirection()
- {
- return this.m_Direction;
- }
- public void Look(Vector3 dir)
- {
- if (dir != Vector3.zero)
- {
- dir.Normalize();
- base.gameObject.transform.localRotation = Quaternion.LookRotation(dir);
- this.m_Direction = dir;
- }
- }
-
-
-
-
-
-
- protected void RegisterAnimEvent(string aniName, string funcName, float time)
- {
- AnimationEvent evt = new AnimationEvent
- {
- time = time,
- functionName = funcName,
- intParameter = m_Uid
- };
- AnimationClip ac = this.m_FBX.GetComponent().GetClip(aniName);
-
- if (ac == null)
- Debug.LogError("Not Found the AnimationClip:" + aniName);
- else
- this.m_FBX.GetComponent().GetClip(aniName).AddEvent(evt);
-
- }
-
-
-
-
-
-
-
-
- protected void RegistState(int state, StateFunc.EnterFunc enter, StateFunc.UpdateFunc update, StateFunc.ExitFunc exit)
- {
- StateFunc func = new StateFunc
- {
- enterFunc = enter,
- updateFunc = update,
- exitFunc = exit
- };
-
- this.m_StateFunc.Add(state, func);
-
- }
-
-
-
-
-
-
- public void ChangeState(int state, StateParam param = null)
- {
- int curState = this.m_CurState;
- this.m_PrevState = curState;
- this.m_CurState = state;
-
- if (this.m_StateFunc.ContainsKey(curState) && (this.m_StateFunc[curState].exitFunc) != null)
- {
- this.m_StateFunc[curState].exitFunc();
- }
-
- if (this.m_StateFunc.ContainsKey(this.m_CurState) && (this.m_StateFunc[this.m_CurState].enterFunc) != null)
- {
- this.m_StateFunc[this.m_CurState].enterFunc(param);
- }
- this.m_StateTimer = 0f;
-
- }
-
-
-
-
-
-
- public void Turn(float angle, float duration)
- {
- Quaternion rot = Quaternion.AngleAxis(angle, Vector3.up);
- TweenRotation.Begin(base.gameObject, duration, rot);
- this.m_Direction = (Vector3)(rot * Vector3.forward);
- }
-
-
-
-
-
-
- public void Turn(Vector3 targetPos, float duration)
- {
- Vector3 forward = targetPos - gameObject.transform.position;
- Quaternion rot = Quaternion.LookRotation(forward);
- iTween.RotateTo (this.gameObject, iTween.Hash ("rotation", rot.eulerAngles, "time", duration, "easetype", "linear"));
- this.m_Direction = forward;
- }
-
-
-
-
-
-
- public void PlayAnim(string condition,float speed = 0f,float value=0,Type t = null)
- {
- animator.speed = speed;
- if (t == typeof(int))
- {
- animator.SetInteger(condition, (int)value);
- }
- else if (t == typeof(float))
- {
- animator.SetFloat(condition, value);
- }
- else
- {
- animator.SetTrigger(condition);
- }
- }
-
- }
该类主要实现了类的注册状态和切换状态,以及动画注册事件。