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

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

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

前面已经给读者介绍了两个类,这两个类并没有具体对象的行为表示,给人的感觉就是一个抽象的类,接下来它们的孩子类的编写,也就是具体的类了。在这里介绍一下设计思路,游戏中的角色和怪物也有共同的属性,比如Buff、Debuff、伤害、移动等等,将这些共同的属性可以放在我们已经规划好的BaseCharacter类中,该类主要实现的就是英雄和怪物的基础属性和方法,代码如下所示:

    public class BaseCharacter:BaseActor
    {

        public GameObject m_MPoint;

        /// <summary>
        /// 攻击特效最长持续时间
        /// </summary>
        protected float m_AttackedEffTimeMax;

        /// <summary>
        /// 
        /// </summary>
        protected bool m_bCameraFrustum;
        
        /// <summary>
        /// 标识碰撞后是否移动
        /// </summary>
        protected bool m_bCollisionMove;
        
        protected bool m_bMute;

        protected int m_BulletUidCount;

        /// <summary>
        /// 
        /// </summary>
        protected CapsuleCollider m_CapsuleCol;

        /// <summary>
        /// 移动朝向
        /// </summary>
        protected Vector3 m_MoveDirection;

        /// <summary>
        /// 移动至向量位置
        /// </summary>
        protected Vector3 m_MoveToPos;

        /// <summary>
        /// 屏幕向量
        /// </summary>
        protected Vector3 m_ScreenPos;

        /// <summary>
        /// 打昏特效
        /// </summary>
        protected GameObject m_StunEff;

        /// <summary>
        /// 
        /// </summary>
        protected float m_StunTimeMax;
        
        /// <summary>
        /// 队伍Id
        /// </summary>
        protected int m_TeamId;

        protected float m_TurnTimeMax;

        /// <summary>
        /// 角色状态
        /// </summary>
        protected CharStat m_Stat = new CharStat();

        /// <summary>
        /// Buff 列表
        /// </summary>
        protected List<BaseBuff> m_Buffs = new List<BaseBuff>();

        /// <summary>
        /// DeBuff 列表
        /// </summary>
        protected List<BaseDeBuff> m_Debuffs = new List<BaseDeBuff>();


        

        public override void Init(int uid)
        {
            base.Init(uid);
            this.m_bMute = false;
            this.m_FBX.SendMessage("SetParent", gameObject);
            this.m_CapsuleCol = this.gameObject.GetComponent<CapsuleCollider>();
        }

        public override void Enable(Vector3 pos)
        {
            base.Enable(pos);
            this.m_MoveDirection = Vector3.zero;
            this.m_BulletUidCount = 0;
            this.m_bCameraFrustum = true;
            this.m_AttackedEffTimeMax = 0f;
            this.m_StunTimeMax = 0f;
            this.m_bCollisionMove = true;
            this.m_Buffs.Clear();
            this.m_Debuffs.Clear();
        }

        protected override void UpdateObj(float delta)
        {
            base.UpdateObj(delta);
            this.UpdateBuffs(delta);
            this.UpdateDebuffs(delta);
            this.CheckInCameraFrustum();

            //if(this.GetCurState() != 13 && this.m_bCollisionMove &&
            //    Application.loadedLevelName != "03_LobbyScene" &&
            //    gameObject.GetComponent<Rigidbody>().velocity.magnitude <= 0.1f)
            //{
            //    gameObject.rigidbody.velocity = GetDirection() * delta * 3f;
            //}


        }


        public override void OnObjectDestroy()
        {
            this.m_StunEff = null;
            base.OnObjectDestroy();
        }

        /// <summary>
        /// 更新增益buff
        /// </summary>
        /// <param name="delta"></param>
        protected void UpdateBuffs(float delta)
        {
            for (int i = 0; i < this.m_Buffs.Count; i++)
            {
                this.m_Buffs[i].OnUpdate(delta);
            }

            for (int j = this.m_Buffs.Count - 1; j >= 0; j--)
            {
                BaseBuff buff = this.m_Buffs[j];
                buff.m_Time -= delta;
                if (this.m_Buffs[j].m_Time < 0f)
                {
                    this.m_Buffs[j].OnDestroy();
                    this.m_Buffs.RemoveAt(j);
                }
            }
        }

        /// <summary>
        /// 更新减益buff
        /// </summary>
        /// <param name="delta"></param>
        protected void UpdateDebuffs(float delta)
        {
            for (int i = 0; i < this.m_Debuffs.Count; i++)
            {
                this.m_Debuffs[i].OnUpdate(delta);
            }

            for (int j = this.m_Debuffs.Count - 1; j >= 0; j--)
            {
                BaseDeBuff debuff = this.m_Debuffs[j];
                debuff.m_Time -= delta;
                if (this.m_Debuffs[j].m_Time < 0f)
                {
                    this.m_Debuffs[j].OnDestroy();
                    this.m_Debuffs.RemoveAt(j);
                }
            }
        }


        public void EnableCapsuleCol(bool flag)
        {
            if (this.m_CapsuleCol != null)
                this.m_CapsuleCol.enabled = flag;
        }

        /// <summary>
        /// 获取英雄角色的身体半径
        /// </summary>
        /// <returns></returns>
        public float GetBodyRadius()
        {
            if (this.m_CapsuleCol != null)
                return this.m_CapsuleCol.radius;

            return 0f;
        }


        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public int GetBulletUid()
        {
            return this.m_BulletUidCount++;
        }

        public void SetTeamId(int teamId)
        {
            this.m_TeamId = teamId;
        }

        public int GetTeamId()
        {
            return this.m_TeamId;
        }

        /// <summary>
        /// 设定等级
        /// </summary>
        /// <param name="level"></param>
        public void SetLevel(int level)
        {
            if (m_ObjType == EnumDefine.ObjType.Mon)
            {

            }

            this.SetGrowth(EnumDefine.GrowthT.Min, level);
            this.SetStatusByLevel(level);
        }

        /// <summary>
        /// 增加buff
        /// </summary>
        /// <param name="type"></param>
        /// <param name="time"></param>
        /// <param name="value"></param>
        protected void AddBuff(EnumDefine.BuffType type, float time, float value)
        {
            BaseBuff buff = this.m_Buffs.Find(x => x.GetBuffType() == type);
            if (buff != null)
            {
                buff.OnInit(type, time, this, value);
            }
            else
            {
                BaseBuff instance = BaseBuff.GetInstance(type);
                instance.OnInit(type, time, this, value);
                this.m_Buffs.Add(instance);
            }

;
        }

        /// <summary>
        /// 增加Debuff
        /// </summary>
        /// <param name="type"></param>
        /// <param name="time"></param>
        /// <param name="value"></param>
        protected void AddDebuff(EnumDefine.DeBuffT type, float time, float value)
        {
            BaseDeBuff debuff = this.m_Debuffs.Find(x => x.GetDebuffType() == type);
            if (debuff != null)
            {
                debuff.OnInit(type, time, this, value);
            }
            else
            {
                BaseDeBuff instance = BaseDeBuff.GetInstance(type);
                instance.OnInit(type, time, this, value);
                this.m_Debuffs.Add(instance);
            }
        }


        /// <summary>
        /// 获取Buff 值
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        protected float GetBuffValue(EnumDefine.BuffType type)
        {

            BaseBuff buff = this.m_Buffs.Find(x => x.GetBuffType() == type);
            if (buff != null)
                return buff.GetValue();
            return 0f;

        }

        /// <summary>
        /// 获取 DeBuff 值
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        protected float GetDeBuffValue(EnumDefine.DeBuffT type)
        {
            BaseDeBuff debuff = this.m_Debuffs.Find(x => x.GetDebuffType() == type);
            if (debuff != null)
                return debuff.GetValue();
            
            return 0f;
        }


        /// <summary>
        /// 检查是否在摄像机视锥体范围内
        /// (视锥体(frustum),是指场景中摄像机的可见的一个锥体范围。它有上、下、左、右、近、远,共6个面组成。在视锥体内的景物可见,反之则不可见。为提高性能,只对其中与视锥体有交集的对象进行绘制。)
        /// </summary>
        protected void CheckInCameraFrustum()
        {
            this.m_ScreenPos = Camera.main.WorldToScreenPoint(gameObject.transform.localPosition);

            if (this.m_ScreenPos.z <= 0f)
            {
                this.m_ScreenPos.x *= -1f;
                this.m_ScreenPos.y *= -1f;
            }

            if ((this.m_ScreenPos.x > Screen.width) || (this.m_ScreenPos.x < 0f))
            {
                this.m_bCameraFrustum = false;
            }
            else
            {
                this.m_bCameraFrustum = true;
            }

        }

        /// <summary>
        /// 获得屏幕向量
        /// </summary>
        /// <returns></returns>
        public Vector3 GetScreenPos()
        {
            return this.m_ScreenPos;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public bool IsInnerCameraFrustum()
        {
            return this.m_bCameraFrustum;
        }


        /// <summary>
        /// 是否可以被攻击
        /// </summary>
        /// <returns></returns>
        public virtual bool IsPossibleAttacked()
        {

            if (m_CurState == 1)        //
            {
                return false;
            }
            if (m_CurState == 13)       //死亡状态
                return false;
            return true;
        }

        /// <summary>
        /// 根据当前状态判定是否在Move
        /// </summary>
        /// <returns></returns>
        public virtual bool IsPossibleMoveTo()
        {
            switch (m_CurState)
            {
                case 1:
                case 13:    //Die
                case 9:     //Slide 滑动
                case 10:    //Down 打到
                case 12:    //Stun  打昏
                case 7:     //CriticalStiff
                    return false;

            }
            return true;
        }

        /// <summary>
        /// 是否在使用技能
        /// </summary>
        /// <returns></returns>
        public virtual bool IsPossibleSkill()
        {
            switch (m_CurState)
            {
                case 1:
                case 13:
                case 9:
                case 10:
                case 12:
                case 7:
                    return false;
            }

            return true;
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="flag"></param>
        public void SetCollisionMove(bool flag)
        {
            this.m_bCollisionMove = flag;

        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="growthT"></param>
        /// <returns></returns>
        protected bool CheckGrowth(EnumDefine.GrowthT growthT)
        {
            if ((growthT >= EnumDefine.GrowthT.Min) && (growthT < EnumDefine.GrowthT.Max))
            {
                return true;
            }

            return false;

        }


        /// <summary>
        /// 设置成长属性
        /// </summary>
        /// <param name="growthT"></param>
        /// <param name="value"></param>
        public void SetGrowth(EnumDefine.GrowthT growthT, int value)
        {
            if (this.CheckGrowth(growthT))
            {
                this.m_Stat.GrowthEnc[(int)growthT] = AhHelper.XEncInt(value);
            }
        }


        /// <summary>
        /// 获取成长
        /// </summary>
        /// <param name="growthT"></param>
        /// <returns></returns>
        public virtual int GetGrowth(EnumDefine.GrowthT growthT)
        {
            if (!this.CheckGrowth(growthT))
            {
                return 0;
            }
            return AhHelper.XDecToInt(this.m_Stat.GrowthEnc[(int)growthT]);

        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="baseStatT"></param>
        /// <param name="value"></param>
        public void SetStatusBase(EnumDefine.BaseStatT baseStatT,float value)
        {
            if (this.CheckStatusBase(baseStatT))
            {
                this.m_Stat.BaseStr[(int)baseStatT] = AhHelper.EncFloat(value);
            }
        }

        /// <summary>
        /// 设定等级状态
        /// </summary>
        /// <param name="level"></param>
        protected virtual void SetStatusByLevel(int level)
        {
            //Debug.Log("Virtual Func");
        }

        public void SetStatusOption(EnumDefine.OptT optT, float value)
        {
            if (CheckStatusOption(optT))
            {
                this.m_Stat.OptStr[(int)optT] = AhHelper.EncFloat(value);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="baseStateType"></param>
        /// <returns></returns>

        protected bool CheckStatusBase(EnumDefine.BaseStatT baseStateType)
        {
            if ((baseStateType >= EnumDefine.BaseStatT.MIN) && (baseStateType < EnumDefine.BaseStatT.MAX))
            {
                return true;
            }
            return false;
        }

        protected bool CheckStatusOption(EnumDefine.OptT optionType)
        {
            if (optionType >= EnumDefine.OptT.Min && optionType < EnumDefine.OptT.Max)
            {
                return true;
            }
            return false;
        }

        /// <summary>
        /// 获取基础状态属性
        /// </summary>
        /// <param name="baseType"></param>
        /// <returns></returns>
        public virtual float GetStatusBase(EnumDefine.BaseStatT baseType)
        {

            if (!this.CheckStatusBase(baseType))
            {
                return 0f;
            }

            float num = AhHelper.DecToFloat(this.m_Stat.BaseStr[(int)baseType]);

            float statusBaseP = 0f;

            if (PlayerHelper.IsPvPMode())
            {
                statusBaseP = this.GetStatusBaseP(baseType, true);
            }
            else
            {
                statusBaseP = this.GetStatusBaseP(baseType, false);

            }

            if (baseType == EnumDefine.BaseStatT.MPC)
            {
                return (num + statusBaseP);
            }


            return num + (num * (statusBaseP / 100f));
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="baseType"></param>
        /// <returns></returns>
        public virtual float GetStatusBaseOrg(EnumDefine.BaseStatT baseType)
        {

            if (!this.CheckStatusBase(baseType))
            {
                return 0f;
            }
            return AhHelper.DecToFloat(this.m_Stat.BaseStr[(int)baseType]);
        }


        /// <summary>
        /// 获取基础状态(PVP)
        /// </summary>
        /// <param name="baseType"></param>
        /// <param name="addPvp"></param>
        /// <returns></returns>
        public virtual float GetStatusBaseP(EnumDefine.BaseStatT baseType, bool addPvp = false)
        {
            if (!CheckStatusBase(baseType))
            {
                return 0f;
            }
            float statusOption = 0f;

            switch (baseType)
            {
                case EnumDefine.BaseStatT.MPC:
                    return this.GetStatusOption(EnumDefine.OptT.MPA);

                case EnumDefine.BaseStatT.MHP:
                    statusOption = this.GetStatusOption(EnumDefine.OptT.HPU);
                    if (addPvp)
                    {
                        statusOption += this.GetStatusOption(EnumDefine.OptT.HPU_PVP);
                    }
                    return statusOption;
                case EnumDefine.BaseStatT.MMP:
                    return this.GetStatusOption(EnumDefine.OptT.MPU);
                case EnumDefine.BaseStatT.ATT:
                    statusOption = this.GetStatusOption(EnumDefine.OptT.ATTR);
                    if (addPvp)
                        statusOption += this.GetStatusOption(EnumDefine.OptT.ATTR_PVP);
                    return statusOption;
                case EnumDefine.BaseStatT.DEF:
                    statusOption = this.GetStatusOption(EnumDefine.OptT.DEFR);
                    if (addPvp)
                        statusOption += this.GetStatusOption(EnumDefine.OptT.DEFR_PVP);
                    return statusOption;
                case EnumDefine.BaseStatT.MS:
                    return this.GetStatusOption(EnumDefine.OptT.MSR);

            }

            return statusOption;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="optionType"></param>
        /// <returns></returns>
        public virtual float GetStatusOption(EnumDefine.OptT optionType)
        {
            if (!this.CheckStatusOption(optionType))
                return 0f;


            float num = AhHelper.DecToFloat(this.m_Stat.OptStr[(int)optionType]);

            switch (optionType)
            {
                case EnumDefine.OptT.ATTR:
                    num += this.GetBuffValue(EnumDefine.BuffType.MIN);
                    break;
                case EnumDefine.OptT.DEFR:
                    num += this.GetBuffValue(EnumDefine.BuffType.DEF_UP);
                    break;
                case EnumDefine.OptT.ASR:
                    num += this.GetBuffValue(EnumDefine.BuffType.AS_UP);
                    break;
                case EnumDefine.OptT.MSR:
                    num += this.GetDeBuffValue(EnumDefine.DeBuffT.IC);
                    break;
            }

            if(HasDebuff(EnumDefine.DeBuffT.CS) && optionType == EnumDefine.OptT.DEFR){
                num+= this.GetDeBuffValue(EnumDefine.DeBuffT.CS);
            }

            return num;

        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="outDmgAttT"></param>
        /// <param name="outValue"></param>
        public void GetDmgAttT(out EnumDefine.DmgAttT outDmgAttT, out float outValue)
        {
            float statusOption = 0f;
            statusOption = GetStatusOption(EnumDefine.OptT.Min);
            if (statusOption > 0f)
            {
                outDmgAttT = EnumDefine.DmgAttT.PS;
                outValue = statusOption;
            }
            else
            {
                statusOption = this.GetStatusOption(EnumDefine.OptT.IDR);
                if (statusOption > 0f)
                {
                    outDmgAttT = EnumDefine.DmgAttT.IC;
                    outValue = statusOption;
                }
                else
                {
                    statusOption = this.GetStatusOption(EnumDefine.OptT.FDR);
                    if (statusOption > 0f)
                    {
                        outDmgAttT = EnumDefine.DmgAttT.FR;
                        outValue = statusOption;
                    }
                    else
                    {
                        statusOption = this.GetStatusOption(EnumDefine.OptT.TDR);
                        if (statusOption > 0f)
                        {
                            outDmgAttT = EnumDefine.DmgAttT.TD;
                            outValue = statusOption;
                        }
                        else
                        {
                            outDmgAttT = EnumDefine.DmgAttT.Min;
                            outValue = 0f;
                        }
                    }
                }
            }
        }

        


        public virtual EnumDefine.AttackedEffT ResearchAttEffType(EnumDefine.AttackedEffT srcType)
        {
            return srcType;
        }

        protected bool HasDebuff(EnumDefine.DeBuffT type)
        {
            return (this.m_Debuffs.Find(x => x.GetDebuffType() == type) != null);
        }


        public bool IsDead()
        {
            return m_CurState == 13;
        }

        /// <summary>
        /// 播放受击效果
        /// </summary>
        /// <param name="attackerPos"></param>
        /// <param name="effId"></param>
        /*
        public void PlayAttackedEff(Vector3 attackerPos, int effId)
        {
            Vector3 vector = gameObject.transform.position - attackerPos;
            vector.Normalize();
            Vector3 pos = gameObject.transform.position - this.m_CapsuleCol.radius * vector;
            pos += this.m_CapsuleCol.center;
            FxManager.PlayEff(effId, pos, 0f);
            ShineEff(0.15f);
        }
        */
       
        public virtual void PlayAttackedEff(Vector3 pos, int effId, EnumDefine.EffT efft = EnumDefine.EffT.HeroEffect) {
            if (m_MPoint != null) {
                GameObject effObj = FxManager.PlayEff(effId, GetDirection(), m_MPoint.transform.position, 0.5f, efft);
                effObj.transform.parent = m_MPoint.transform;
                effObj.transform.localPosition = Vector3.zero;
                effObj.transform.localEulerAngles = Vector3.zero;
                //DebugLog.Log("PlayAttackedEff:" + effId);
            }

        }

        /// <summary>
        /// 自残 
        /// 一般用在Debuff状态下
        /// </summary>
        /// <param name="damage"></param>
        /// <param name="resultHp"></param>
        /// <param name="effId"></param>
        /// <param name="numEffId"></param>
        public virtual void SelfDamage(float damage, float resultHp, int effId, int numEffId)
        {

            this.PlayAttackedEff(gameObject.transform.position, effId, EnumDefine.EffT.PublicEffect);


        }



        public enum eState
        {
            None,
            Sleep,
            Advent,
            Idle,
            Move,
            MoveTo,
            Turn,
            CriticalStiff,  //至命最后一击
            Stiff,
            Slide,          //滑动
            Down,
            StunSlide,
            Stun,
            Die,
            Max

        }


    }

在主要的函数中都有代码注释,读者可以参考,给出类的实现,是给读者设计时做一个参考使用的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

海洋_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值