Unity MMO游戏架构设计之角色设计一

笔者介绍:姜雪伟,IT公司技术合伙人,IT高级讲师,CSDN社区专家,特邀编辑,畅销书作者,国家专利发明人;已出版书籍:《手把手教你架构3D游戏引擎》电子工业出版社和《Unity3D实战核心技术详解》电子工业出版社等。

CSDN视频网址:http://edu.csdn.net/lecturer/144

网上很多人问我关于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;

        /// <summary>
        /// 标识移除后储存
        /// </summary>
        protected bool m_bRererveRemove;
        
        protected Dictionary<eCmd, OnMsgFunc> m_MsgFuncs = new Dictionary<eCmd, OnMsgFunc>();

        protected string m_Name;

        /// <summary>
        /// 对象类别
        /// </summary>
        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() { }

        /// <summary>
        /// 执行指令
        /// </summary>
        /// <param name="cmd"></param>
        /// <param name="baseData"></param>
        public void OnObjMsg(eCmd cmd, IBaseMsgData baseData)
        {
            if (this.m_MsgFuncs.ContainsKey(cmd))
            {
                this.m_MsgFuncs[cmd](baseData);
            }
        }

        /// <summary>
        /// 注册消息指令
        /// </summary>
        /// <param name="cmd"></param>
        /// <param name="func"></param>
        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
    {

        /// <summary>
        /// AI 控制
        /// </summary>
        protected BaseAICtrl m_AiCtrl;

        /// <summary>
        /// 普通控制
        /// </summary>
        protected BaseCtrl m_Ctrl;
        protected bool m_bUpdateShineEff;
        
        /// <summary>
        /// 当前状态
        /// </summary>
        protected int m_CurState;

        /// <summary>
        /// 方位
        /// </summary>
        protected Vector3 m_Direction;

        /// <summary>
        /// 动画组件
        /// </summary>
        protected Animator animator;

        /// <summary>
        /// 模型fbx
        /// </summary>
        public GameObject m_FBX;

        /// <summary>
        /// 材质列表
        /// </summary>
        protected List<Material> m_Materials = new List<Material>();

        /// <summary>
        /// 上一状态
        /// </summary>
        protected int m_PrevState;
        /// <summary>
        /// 状态键值对
        /// </summary>
        protected Dictionary<int, StateFunc> m_StateFunc = new Dictionary<int, StateFunc>();

        /// <summary>
        /// 状态参数
        /// </summary>
        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<Animator>();
        }

        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);
            }
                
        }
        /// <summary>
        /// 刷新材质球信息
        /// </summary>
        public void RefreshMaterialInfo()
        {
            this.m_Materials.Clear();
            SkinnedMeshRenderer[] smrs = gameObject.GetComponentsInChildren<SkinnedMeshRenderer>();
            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<MeshRenderer>();
            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<Animation>() != null)
            {
                this.m_FBX.GetComponent<Animation>()[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;
            }
        }
        /// <summary>
        /// 注册动画事件
        /// </summary>
        /// <param name="aniName"></param>
        /// <param name="funcName"></param>
        /// <param name="time"></param>
        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<Animation>().GetClip(aniName);
            
            if (ac == null)
                Debug.LogError("Not Found the AnimationClip:" + aniName);
            else
                this.m_FBX.GetComponent<Animation>().GetClip(aniName).AddEvent(evt);

        }

        /// <summary>
        /// 注册状态事件
        /// </summary>
        /// <param name="state"></param>
        /// <param name="enter"></param>
        /// <param name="update"></param>
        /// <param name="exit"></param>
        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);
            //Debug.Log("State:" + state);
        }

        /// <summary>
        /// 切换状态 
        /// </summary>
        /// <param name="state"></param>
        /// <param name="param"></param>
        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;

        }

        /// <summary>
        /// 转向
        /// </summary>
        /// <param name="angle"></param>
        /// <param name="delay"></param>
        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);
        }

        /// <summary>
        /// 转身
        /// </summary>
        /// <param name="targetPos"></param>
        /// <param name="delay"></param>
        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;
        }
        
        /// <summary>
        /// 动作播放New Mecanim System
        /// </summary>
        /// <param name="condition"></param>
        /// <param name="speed"></param>
        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);
            }            
        }
    
    }

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




发布了327 篇原创文章 · 获赞 583 · 访问量 89万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览