U3D多点触控框架实例(下)

来源:互联网 发布:ubuntu zip分卷压缩 编辑:程序博客网 时间:2024/06/05 19:33

1.概述

上次我们一口气讲到下层组件讲多点触控的消息根据具体的需求,在每个时刻将其抽象画成单一指令。

接下来我们要聊聊,上层组件中如何将单一的指令应用在角色上,让角色在移动,普通攻击和释放技能中间做出正确的行为。

上次我们也说过了,上层组件是个优先级队列,队列中分别有对移动,普通攻击,技能释放的判定检测组件,按照 技能> 普攻 > 移动的优先级,对下层组件传递过来的消息依次,逐个进行处理。

按照这种设计思路,我们首先还是应该有一个接口,统一组建的操作,然后在响应事件的时候对组件for循环处理


2.队列组件接口

public enum TouchEventType    {        down,        press,        up,        moveEnd,    }    public class ManualControllerCom    {        protected Units self;//绑定的角色        bool pause = true;        protected Units lastTarget;//选定的地方目标        public virtual void OnInit()        {         }        public virtual void OnStart()        {         }        public virtual void OnExit()        {         }        public virtual void OnStop()        {         }        public virtual void OnDown(TriggerParamTouch param)//响应按下事件        {        }        public virtual void OnPress(TriggerParamTouch param)//响应长按        {        }        public virtual void OnUp(TriggerParamTouch param)//响应弹起        {        }        public virtual void OnMoveEnd(TriggerParamTouch param)//响应移动结束,这个消息是别人加的,暂时忽略,        {        }        public virtual void OnSkill(ITriggerDoActionParam param)//点击UI按下        {        }        public virtual void OnNavigateEnd()//寻路结束,也就是寻路到目标位置了        {        }        protected float GetSkillRange(Skill skill)//获取技能攻击范围(其他人添加,不应该放在基类中)        {            if (skill.IsAttack)            {                return self.GetAttackRange(null);            }            else            {                return skill.distance;            }        }        protected Units GetSkillTarget(Skill skill, Units enemyTarget)//获取技能目标<span style="font-family: Arial, Helvetica, sans-serif;">(其他人添加,不应该放在基类中)</span>        {            if (skill.needTarget)            {                if (enemyTarget == null)                {                    if (skill.data.targetCamp == SkillTargetCamp.Self)                    {                        return self;                    }                    else if (skill.data.targetCamp == SkillTargetCamp.Partener)                    {                        return self;                    }                    else if (skill.data.targetCamp == SkillTargetCamp.AllWhitOutPartener)                    {                        return self;                    }                }                else                {                    if (skill.data.targetCamp == SkillTargetCamp.Self)                    {                        return self;                    }                    else if (skill.data.targetCamp == SkillTargetCamp.Partener)                    {                        if (enemyTarget.teamType == self.teamType)                        {                            return enemyTarget;                        }                        else                        {                            return self;                        }                    }                    else if (skill.data.targetCamp == SkillTargetCamp.AllWhitOutPartener)                    {                        if (enemyTarget.teamType == self.teamType)                            return self;                        else                            return enemyTarget;                    }                }                return enemyTarget;            }            return null;        }    }

该接口响应触控事件,以及技能释放事件


3.上层组件

上层组件主要是集合所有上层操作组件(释放技能,普攻,移动)。

    public class ManualController : StaticUnitComponent//该组件也是英雄角色身上的组件之一    {                #region 变量        ManualControlTarget targetCom;//目标        ManualControlSignalMng signalCom;//组件通信的信号量        List<TriggerEvent2> listTrigger2 = new List<TriggerEvent2>();//消息监听        List<ManualControllerCom> listManuControllerCom = new List<ManualControllerCom>();//组件容器        TouchEventDebug touchDebugger;//DEBUG组件        bool pause = false;//是否暂停        bool initial = false;//是否初始化        bool debugFlag = false;//是否开启debug        #endregion                public Units ControlUnit        {            get { return self; }        }        public ManualControlTarget TargetCom        {            get { return targetCom; }        }        public ManualControlSignalMng SignalCom        {            get { return signalCom; }        }        public CoroutineManager CoroutineMng        {            get { return m_CoroutineManager; }        }        #region 构造函数        public ManualController()        {                    }        void Init()        {            if(debugFlag)            {                touchDebugger = new TouchEventDebug();                if(null!=touchDebugger)                {                    touchDebugger.OnInit();                }            }            signalCom = new ManualControlSignalMng(this);            targetCom = new ManualControlTarget(this);            RegisterTrigger();            InvokeEveryCom("OnInit");//init组件  这是通过反射调用每个组件的对应override函数        }        #endregion        #region 事件处理        public override void OnInit()        {            base.OnInit();            if (!initial)            {                Init();                initial = true;            }        }        public override void OnStart()        {            pause = false;            base.OnStart();            InvokeEveryCom("OnStart");//组件启动        }        public override void OnStop()        {            pause = true;            base.OnStop();            InvokeEveryCom("OnStop");//停止组件        }                public override void OnExit()//退出组件        {            base.OnExit();            InvokeEveryCom("OnExit");            UnRegisterTrigger();            m_CoroutineManager.StopAllCoroutine();//停止协程            if (debugFlag && null != touchDebugger)            {                touchDebugger.OnExit();            }        }        #endregion        void OnDown(ITriggerDoActionParam param)        {            if(!CanHandleControl())//这个就是因为一些情况不需要处理,比如角色死亡之类的                return;            TriggerParamTouch info;            if (!HandleTouchParam(param,out info))//检查传入参数,传入的是个接口                return;            //if (!targetCom.UpdateTarget(info.Pos))            //    return;            signalCom.Init();//初始化信号量,表示现在没有组件处理这个消息,因为每个组件依次处理,所以处理前要复位,处理过程中置位,职位后后续组件无需处理            InvokeEveryCom("OnDown", new object[] { info });        }        void OnPress(ITriggerDoActionParam param)        {            if(!CanHandleControl())                return;            TriggerParamTouch info;            if (!HandleTouchParam(param,out info))                return;            //if (!targetCom.UpdateTarget(info.Pos))            //    return;            signalCom.Init();            InvokeEveryCom("OnPress", new object[] { info });        }        void OnUp(ITriggerDoActionParam param)        {            if(!CanHandleControl())                return;            TriggerParamTouch info;            if (!HandleTouchParam(param,out info))                return;            //if (!targetCom.UpdateTarget(info.Pos))            //    return;            signalCom.Init();            InvokeEveryCom("OnUp", new object[] { info });        }        void OnMoveEnd(ITriggerDoActionParam param)        {            if(!CanHandleControl())                return;            TriggerParamTouch info;            if (!HandleTouchParam(param,out info))                return;            //if (!targetCom.UpdateTarget(info.Pos))            //    return;            signalCom.Init();            InvokeEveryCom("OnMoveEnd", new object[] { info });        }        //@jason        void OnSkillEnd(ITriggerDoActionParam param)        {            if (!CanHandleControl())                return;            signalCom.Init();            InvokeEveryCom("OnSkillEnd", new object[] { param });        }        void OnSkill(ITriggerDoActionParam param)        {            if (!CanHandleControl())                return;            signalCom.Init();            InvokeEveryCom("OnSkill",new object[]{param});        }        void OnNavigateEnd(ITriggerDoActionParam param=null) //停止寻路回调        {            signalCom.Init();            InvokeEveryCom("OnNavigateEnd");        }        void InvokeEveryCom(string methodName,object[] param=null)//用反射调用每个组件的对应方法        {            if (string.IsNullOrEmpty(methodName))                return;            ShowEventDebug(methodName);            foreach (var it in listManuControllerCom)            {                Type t = it.GetType();                                MethodInfo mInfo =  t.GetMethod(methodName);                if(null!=mInfo)                {                    mInfo.Invoke(it, param);                }            }        }        public void ShowEventDebug(string str)        {            if (debugFlag)            {                touchDebugger.AddEventInfo(str);            }        }        public void ShowHandlerDebug(string str)        {            if (debugFlag)            {                touchDebugger.AddHandlerInfo(str);            }        }        //---------------------------------//后面的代码就不用怎么看了,和框架没啥大关系        #region 注册回调        //切换主站英雄的时候将移动光标去掉        void RegisterTrigger()        {            RegisterEvent2(EEventID2_touch.eDown, OnDown);            RegisterEvent2(EEventID2_touch.ePress, OnPress);            RegisterEvent2(EEventID2_touch.eUp, OnUp);            RegisterEvent2(EEventID2_touch.eMoveEnd, OnMoveEnd);            RegisterEvent2(EEventID2_skillControl.ePressSkill, OnSkill);            RegisterEvent2(EEventID2_navigation.eOnStopPath, OnNavigateEnd);            //@jason            RegisterEvent2(EEventID2_skillControl.eKillEnd, OnSkillEnd);            MobaMessageManager.RegistMessage((ClientMsg)ClientV2V.BattleShop_shopOpened, OnControllerClose);            MobaMessageManager.RegistMessage((ClientMsg)ClientV2V.BattleShop_shopClosed, OnControllerOpen);        }        void UnRegisterTrigger()        {            for (int i = 0; i < listTrigger2.Count; ++i)            {                TriggerManager2.Instance.RemoveListner(listTrigger2[i]);            }            MobaMessageManager.UnRegistMessage((ClientMsg)ClientV2V.BattleShop_shopOpened, OnControllerClose);            MobaMessageManager.UnRegistMessage((ClientMsg)ClientV2V.BattleShop_shopClosed, OnControllerOpen);        }        void RegisterEvent2(EEventID2_touch eventID, Callback<ITriggerDoActionParam> fun_action)        {            TriggerCreateParamTouch param = new TriggerCreateParamTouch();            RecordTrigger(param, (int)eventID, fun_action);        }        void RegisterEvent2(EEventID2_skillControl eventID, Callback<ITriggerDoActionParam> fun_action)        {            TriggerCreateParamSkillControl param = new TriggerCreateParamSkillControl();            RecordTrigger(param, (int)eventID, fun_action);        }        void RegisterEvent2(EEventID2_navigation eventID, Callback<ITriggerDoActionParam> fun_action)        {            TriggerCreateParamNavigation param = new TriggerCreateParamNavigation();            List<TriggerCondition<ITriggerDoActionParam>> list = new List<TriggerCondition<ITriggerDoActionParam>>();            list.Add(IsPlayer);            RecordTrigger(param, (int)eventID, fun_action,list);        }        void RecordTrigger(ITriggerCreatorParam param, int eventID,            Callback<ITriggerDoActionParam> fun_action,            List<TriggerCondition<ITriggerDoActionParam>> conditions = null)        {            if (null != param)            {                param.EventID = (int)eventID;                param.TriggerID = TriggerManager2.assign_trigger_id();                param.Func_actions = fun_action;                param.Func_conditions = conditions;                TriggerEvent2 trigger = TriggerManager2.CreateTriggerEvent2(param);                listTrigger2.Add(trigger);                TriggerManager2.Instance.AddListener(trigger);            }        }        bool IsPlayer(ITriggerDoActionParam param=null)        {            TriggerParamNavigation info = param as TriggerParamNavigation;            return null != info && info.IsPlayer;        }        #endregion        bool HandleTouchParam(ITriggerDoActionParam param,out TriggerParamTouch info)        {            info = param as TriggerParamTouch;            return info != null;        }        bool CanHandleControl()        {            if (controllerUnlockTime > 0)            {                if (DateTime.Now.Ticks - controllerUnlockTime < 100 * 10000)                {                    return false;                }                controllerUnlockTime = 0;            }            return null!=self && self.isLive && !self.IsLockCharaControl && !self.LockInputState && controllerLock == 0;           }        public void ShowDebugMsg(string s)        {#if UNITY_EDITOR            ClientLogger.Debug(LogTagNames.TAG_NULL, "==>>ManualController:" + s);#endif        }

4.组件实现

a.技能组件

每个组件不仅处理事件,而且会保存角色移动,释放技能,普通攻击的状态。以释放技能为例,其实也有很多状态,可以考虑用状态机,不过有点复杂。技能显示范围指示,技能释放过程中,技能释放结束,技能释放结束的结果,是成功,失败,还是打断,这些状态下,都可能收到对应的消息,那么要对其进行处理。如果不处理,那么信号量就是闲置,接下来普攻组件和移动组件会处理。如果处理了,后面的组件优先级较低,就不会再处理了。由于这个功能完成之后没有及时做笔记,被其他人改的面目全非,所以现在仅仅保留一个影子,可以看到一个大概。

     public class ManualControlSkillNormal : ManualControllerCom    {        List<VTrigger> listTrigger = new List<VTrigger>();        ManualController controller;        ManualControlTarget targetCom;        ManualControlSignalMng signalCom;        Skill tmpLastSkill;        float tmpLastSkillTm;        Skill readySkill; //已经按出指示器,准备要放的技能        Skill lastReadySkill; //已经按出指示器,准备要放的技能        float readyTm;        void ClearReadySkill()        {            if (readySkill != null)            {                TriggerManager.Instance.SendUnitSkillPointerEvent(UnitEvent.UnitSkillCmdHidePointer, self, readySkill, Vector3.zero);                readySkill = null;                SkillView.Instance.ClearSelectState();                SkillView.Instance.HideSkillWarn();            }        }        void SetReadySkill(Skill skill, Units targetUnits)        {            ClearReadySkill();            readySkill = skill;            lastReadySkill = skill;            readyTm = Time.realtimeSinceStartup;            SkillView.Instance.SetSelectState();            SkillView.Instance.ShowSkillWarn("请选择目标");            TriggerManager.Instance.SendUnitSkillPointerEvent(UnitEvent.UnitSkillCmdShowPointer, self, readySkill, GetSkillPointerPos(skill, targetUnits));        }        void DragSkillPointer(Vector3 targetPos)        {            TriggerManager.Instance.SendUnitSkillPointerEvent(UnitEvent.UnitSkillCmdDragPointer, self, readySkill, targetPos);        }        bool ReadySkillOld()        {            return readySkill == null || Time.realtimeSinceStartup - readyTm > 0.6f;        }        #region 构造函数        public ManualControlSkillNormal(ManualController c)        {            controller = c;            self = c.ControlUnit;            targetCom = controller.TargetCom;            signalCom = controller.SignalCom;        }        #endregion        //-----------------------------------------------------------------------        #region  事件处理        public override void OnInit()        {            //YJLog.log("OnInit");            base.OnInit();            VTrigger tr = null;            tr = TriggerManager.CreateUnitEventTrigger(UnitEvent.UnitSkillOver, null, OnSkillOver, self.unique_id);            listTrigger.Add(tr);            tr = TriggerManager.CreateUnitEventTrigger(UnitEvent.UnitSkillFailed, null, OnSkillFailed, self.unique_id);            listTrigger.Add(tr);            tr = TriggerManager.CreateUnitEventTrigger(UnitEvent.UnitDeath, null, OnUnitDeath, self.unique_id);            listTrigger.Add(tr);            tr = TriggerManager.CreateUnitEventTrigger(UnitEvent.UnitSkillCmdStart, null, OnSkillStart, self.unique_id);            listTrigger.Add(tr);            //tr = TriggerManager.CreateUnitEventTrigger(UnitEvent.UnitSkillEnd, null, OnSkillEnd, self.unique_id);            //listTrigger.Add(tr);            //added by shaoming            self.ClearBornPowerObjSkillData();            //@added by shaoming        }        public override void OnStop()        {            //YJLog.log("OnStop");            base.OnStop();            targetCom.ClearSkillFlag();            targetCom.ClearMoveFlag();        }        public override void OnExit()        {            //YJLog.log("OnExit");            foreach (var it in listTrigger)            {                TriggerManager.DestroyTrigger(it);            }            base.OnExit();        }        public override void OnDown(TriggerParamTouch param)        {            //YJLog.log("OnDown");            //Debug.LogError("Control OnDown");            if (GlobalSettings.Instance.isLockView)            {                if (readySkill == null)                {                    OnTrySkillOrMove(param, TouchEventType.down);                }            }        }        public override void OnPress(TriggerParamTouch param)        {            //YJLog.log("OnPress");            //Debug.LogError("Control OnPress");            if (GlobalSettings.Instance.isLockView)            {                targetCom.ClearTarget();                targetCom.UpdateTarget(param.Pos);                Vector3 targetPos = targetCom.GroundPoint;                Units targetUnits = targetCom.TargetUnit;                if (targetUnits != null && !targetUnits.CanBeSelected)                {                    targetUnits = null;                }                if (!self.CanManualControl())                {                    return;                }                if (readySkill != null)                {                    targetCom.ClearMoveFlag();                    DragSkillPointer(targetPos);                }                else                {                    OnTrySkillOrMove(param, TouchEventType.press);                }            }        }        public override void OnUp(TriggerParamTouch param)        {            //YJLog.log("OnUp");            //Debug.LogError("Control OnUp");            if (GlobalSettings.Instance.isLockView)            {                if (readySkill != null)                    OnTrySkillOrMove(param, TouchEventType.up);            }            else            {                OnTrySkillOrMove(param, TouchEventType.up);            }        }        public virtual void OnMoveEnd(TriggerParamTouch param)        {            //YJLog.log("OnMoveEnd");            //Debug.LogError("Control OnMoveEnd");            if (GlobalSettings.Instance.isLockView)            {//判断移动 或者 攻击                if (readySkill != null)                {                    OnTrySkillOrMove(param, TouchEventType.moveEnd);                }                else                {                    targetCom.ClearTarget();                    targetCom.UpdateTarget(param.Pos);                    Units targetUnits = targetCom.TargetUnit;                    if (targetUnits != null && !targetUnits.CanBeSelected)                    {                        targetUnits = null;                    }                    if (!self.CanManualControl())                    {                        return;                    }                    if (targetUnits == null)                    {                        OnTrySkillOrMove(param, TouchEventType.moveEnd);                    }                }            }            else            {//可以滑动视窗时,什么都不操作                             }        }        void OnTrySkillOrMove(TriggerParamTouch param, TouchEventType type)        {            targetCom.ClearTarget();            targetCom.UpdateTarget(param.Pos);            Vector3 targetPos = targetCom.GroundPoint;            Units targetUnits = targetCom.TargetUnit;            bool needForceSend = type == TouchEventType.press ? false : true;            if (targetUnits != null && !targetUnits.CanBeSelected)            {                targetUnits = null;            }             if (!self.CanManualControl())            {                return;            }            if (readySkill == null)            {                if (targetUnits == null)                {                    DisableAIAutoAttackMove();                    targetCom.DrawMoveFlag();                    self.mCmdCacheController.EnqueueMoveCmd(targetPos, needForceSend);                    lastTarget = null;                }                else                {                    if (type == TouchEventType.down || (type != TouchEventType.down && lastTarget != targetUnits))                    {                        lastTarget = targetUnits;                        DisableAIAutoAttackMove();                        targetCom.ClearMoveFlag();                        self.mCmdCacheController.EnqueueSkillCmd(self.attacks[0], targetPos, targetUnits);                    }                }            }            else            {                targetCom.ClearTarget();                targetCom.UpdateTargetAll(param.Pos, readySkill.data.targetCamp);                targetCom.ClearMoveFlag();                DragSkillPointer(targetCom.GroundPoint);                LaunchSkill(readySkill, targetCom.TargetUnit, targetCom.GroundPoint);                ClearReadySkill();                lastTarget = null;            }        }        void OnSkillOver()        {        }        void OnSkillFailed()        {        }        void OnUnitDeath()        {            //YJLog.log("OnUnitDeath");            ClearReadySkill();        }        void OnSkillStart()        {            Skill skill = self.GetSkillContext();            if (skill != null && skill == readySkill)            {                ClearReadySkill();            }        }        public override void OnSkill(ITriggerDoActionParam param)        {            TriggerParamSkillControl info = param as TriggerParamSkillControl;            //YJLog.log("OnSkill:" + info.SkillID);            Skill skill = self.getSkillOrAttackById(info.SkillID);            Units targetUnits = FindTargetHelper.FindAutoSkillTarget(self, self.trans.position, TargetTag.Hero, self.atk_type == 1 ? 6.5f : GetSkillRange(skill) + 2);            if(targetUnits == null)                targetUnits = PlayerControlMgr.Instance.GetSelectedTarget();            targetCom.ClearMoveFlag();            if (!self.CanManualControl())            {                return;            }            if (self.IsSkillCanTriggerBornPowerObj(info.SkillID))            {                ClearReadySkill();                LaunchSkill(skill, targetUnits);                return;            }            if (DoseSkillNeedDoubleClick(skill))            {                 if (skill == readySkill)                 {                    if (ReadySkillOld())//过期时 再次点击是清楚上次选择                    {                        readyTm = Time.realtimeSinceStartup;                        ClearReadySkill();                    }                    else                    {                        ClearReadySkill();                        LaunchSkill(skill, targetUnits);                    }                    return;                 }                 if (readySkill == null && lastReadySkill == skill && Time.realtimeSinceStartup - readyTm < 0.5f)                 {                    ClearReadySkill();                    LaunchSkill(skill, targetUnits);                    return;                 }                 SetReadySkill(skill, targetUnits);                 return;            }            else            {                ClearReadySkill();                LaunchSkill(skill, targetUnits);            }        }        public override void OnNavigateEnd()        {            //YJLog.log("OnNavigateEnd");            self.mCmdRunningController.OnMoveEnd();            targetCom.ClearMoveFlag();        }        #endregion                Vector3 GetSkillPointerPos(Skill skill, Units targetUnits)        {            if (targetUnits != null)                return targetUnits.mTransform.position;            else            {                return self.mTransform.position + self.mTransform.forward * 10f;            }        }        void LaunchSkill(Skill skill, Units targetUnits)        {            Vector3 targetPos = Vector3.zero;            if (!skill.needTarget)            {                if (targetUnits != null && !targetUnits.CanBeSelected)                {                    targetUnits = null;                }                if (targetUnits == self)                {                    targetUnits = null;                }                targetPos = self.mTransform.forward;                if (targetUnits != null)                {                    targetPos = targetUnits.mTransform.position;                }                else                {                    targetPos.Normalize();                    if (skill.distance == 0)                        targetPos = self.mTransform.position + targetPos;                    else                        targetPos = self.mTransform.position + targetPos * skill.distance;                }                LaunchSkill(skill, targetUnits, targetPos);            }            else            {                targetUnits = GetSkillTarget(skill, targetUnits);                if (targetUnits != null)                {                    LaunchSkill(skill, targetUnits, targetPos);                }                else                {                    UIMessageBox.ShowMessage("未选择目标,不能释放!");                }            }        }        void LaunchSkill(Skill skill, Units targetUnits, Vector3 targetPos)        {            if (skill.needTarget)            {                targetUnits = GetSkillTarget(skill, targetUnits);                if (targetUnits != null && !targetUnits.CanBeSelected)                {                    targetUnits = null;                }                if (targetUnits != null)                {                    DisableAIAutoAttackMove();                    targetCom.ClearMoveFlag();                    self.mCmdCacheController.EnqueueSkillCmd(skill.realSkillMainId, targetUnits.mTransform.position, targetUnits);                }                else                {//如果指向性技能没选择目标  该怎么默认处理                 }            }            else            {                if (targetUnits != null && !targetUnits.CanBeSelected)                {                    targetUnits = null;                }                if (targetUnits == self)                {                    targetUnits = null;                }                DisableAIAutoAttackMove();                targetCom.ClearMoveFlag();                self.mCmdCacheController.EnqueueSkillCmd(skill.realSkillMainId, targetPos, targetUnits);            }        }        bool DoseSkillNeedDoubleClick(Skill skill)        {            return !skill.IsInstance;        }        void DisableAIAutoAttackMove()        {            if (self.aiManager != null)            {                self.aiManager.EnableSearchTarget(false);            }            self.SetAIAutoAttackMove(false);        }    }



0 0
原创粉丝点击