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


1.需求

         首先我们先来说说需求,在U3D的引擎中,做一个ARPG游戏的现多点触控。

         a. 点击A点,人物向A点移动,A点手指未抬起,按下B点,角色立刻响应B点手指点击,向B点移动。如果按下B点的过程中A点抬起,则松开B点后不再响应A点。

         c.点击A点,A点手指未抬起,同时点击(没有长按)敌方目标B,B处手指松开,则角色立刻攻击一下B目标,然后再向A点移动。

         d.点击A点,同时点击技能图标,则角色释放技能,释放结束后向A点移动。


2.框架设计

首先我们要通过分析需求,找到问题的本质。

a.其实虽然是多点触摸,我们可以理解为2点触摸,也就是有第三点出现时,我们忽略第三点。

b.无论是两点还是多点,游戏角色,在某一瞬间仅仅响应一个触点控制,这就意味着我们某一时刻仅需要判断出,在多个触碰手指中,拿个手指是有效的。

        c.角色有三种行为,移动,普通攻击,释放技能,其实这是一个优先级队列,优先级为  技能 > 普攻 > 移动

通过上面的分析,我们可以初步判做出设计为,底层组件和应用层组件。

       底层设计:判断手指的触碰,来实现某一瞬间仅仅有一个有效手指触点动作,并将该动作报告上层组件,进而由应用层组件进行使用。

       应用层组件:接收来自底层组件的消息,然后对角色行为的优先级队列进行操作,让角色做出正确的决定。


3.下层组件

下层组件是绑定到人物身上的,人物身上有各种组件,可以根据需要进行添加删除,以达到最大的灵活性。

UnitCompoent就是人物身上的组件。

  a.检测组件

我们先看看执行具体检测人物的代码:我们先使用一个通过的接口,然后有两个类分别实现这个接口,一个类负责检测鼠标事件,另一个负责检测触摸事件,当然这两个组件不会同时使用。

    public class IControlHandler
    {
        int ControlID;//检测组件的唯一编号
        public virtual void updateControl(float deltaTime) { }//用于检测操作

        Vector3 initPressPos;
        float pressDeltaTime;
        static float sPressDeltaTime;
        protected void InitPressPos(Vector3 initPos)//保存鼠标或者手指按下时的一些信息(位置和时间)
        {
            initPressPos = initPos;
            pressDeltaTime = Time.realtimeSinceStartup;
            sPressDeltaTime = Time.realtimeSinceStartup;
            //Debug.LogError("IControl Down Init" + Time.realtimeSinceStartup);
        }
        protected bool IsDrag(Vector3 curPos)//判断是否有过拖动
        {
            //Debug.LogError("IControl Down Init" + Time.realtimeSinceStartup + " - " + sPressDeltaTime + " = " + (Time.realtimeSinceStartup - sPressDeltaTime));
            float dis = Vector3.Distance(initPressPos, curPos);
            if (GlobalSettings.Instance.isLockView)
            {
                return true;
            }
            else
            {
                if (Time.realtimeSinceStartup - sPressDeltaTime < 0.3f && dis < 0.5) return false;
            }
            if (dis < 0.5f)
            {
            }
            return true; 
        }
    }
    #endregion

    #region 鼠标检测组件
    public class MouseHandler : IControlHandler
    {
        public MouseHandler(int mouseIndex, ControlEventManager teManager)
        {
            tEventManager = teManager;
            mouseID = mouseIndex;
            Init();
        }
        public int ControlID
        {
            get
            {
                return mouseID;//0,1,表示左右键
            }
        }
        void Init()
        {
            hasPressed = false;
            downTimeStamp = 0;
        }
        ControlEventManager tEventManager;//消息管理器引用,用于发送消息
        int mouseID = -1;
        bool hasPressed = false;//是否长按过
        float downTimeStamp = 0;
        Vector2 mousePos;//点击位置

        public override void updateControl(float deltaTime)
        {
#if UNITY_EDITOR || UNITY_STANDALONE
            AnalysisState(deltaTime);//每帧进行检测
#endif
        }
        void AnalysisState(float deltaTime)//检测函数
        {
            mousePos = Input.mousePosition;//更新鼠标位置
            if (Input.GetMouseButtonDown(ControlID))//如果按下左键
            {
                Down(deltaTime);//进一步处理
            }
            else if (Input.GetMouseButtonUp(ControlID))//检测按键弹起
            {
                Up(deltaTime);
            }
            else if (Input.GetMouseButton(ControlID))//检测鼠标是否是按下状态
            {
                if (IsDrag(Input.mousePosition))
                    Press(deltaTime);
            }
        }
        void Down(float deltaTime)//处理按下状态
        {
            //YJLog.log3("Down Event");
            hasPressed = false;
            InitPressPos(Input.mousePosition);//每次按下初始化位置和时间
            downTimeStamp = Time.realtimeSinceStartup;
            CreateTouchEvent(EControlType.eDown);//构造消息
        }
        void Up(float deltaTime)
        {
            if (hasPressed)
            {
                hasPressed = false;
                //YJLog.log3("Move End Event");
                CreateTouchEvent(EControlType.eMoveEnd);//长按结束的事件
            }
            else
            {
                //YJLog.log3("Up Event");
                CreateTouchEvent(EControlType.eUp);//按下弹起的事件
            }
            downTimeStamp = 0;
        }

        void Press(float deltaTime)
        {
            hasPressed = true;
            //YJLog.log3("Press Event");
            CreateTouchEvent(EControlType.ePress);//长按事件
        }
        void CreateTouchEvent(EControlType tType)//事件构发送
        {
            tEventManager.AddEvent(new ControlEvent()//添加事件到列表
            {
                type = tType,
                id = ControlID,
                touchDownTimeStamp = downTimeStamp,
                position = mousePos,
                createTimeStamp = Time.realtimeSinceStartup
            });
        }

    }
    #endregion

    #region 触摸检测组件
    public class TouchHandler : IControlHandler
    {
        public TouchHandler(int fingerIndex, ControlEventManager teManager)
        {
            tEventManager = teManager;
            fingerID = fingerIndex;
            Init();
        }

        public int ControlID
        {
            get
            {
                return fingerID;//0,1分别代表按下的第1,2根手指的fingerID,A按下,ID为0,B按下ID为1,A抬起,B ID不变,A再次按下,ID还是0
            }
        }
        void Init()
        {
            hasPressed = false;
            downTimeStamp = 0;
        }
        ControlEventManager tEventManager;
        int fingerID;
        bool hasPressed = false;
        float downTimeStamp = 0;
        Touch touchInfo;//保存touchInfo
        public override void updateControl(float deltaTime)
        {
#if !UNITY_EDITOR && (UNITY_ANDROID || UNITY_IOS) 
            AnalysisState(deltaTime);
#endif
        }
        void AnalysisState(float deltaTime)//分析手指触控动作
        {
            for (int i = 0; i < Input.touchCount; ++i)
            {
                Touch t = Input.GetTouch(i);
                if (t.fingerId == ControlID)//FingerID如果是当前组件的ID,说明是当前组件处理,这两个是一致的,
                {
                    touchInfo = t;
                    DidpatchEvent(touchInfo.phase, deltaTime);
                }
            }
        }
        void DidpatchEvent(TouchPhase phase, float deltaTime)
        {
            switch (phase)
            {
                case TouchPhase.Began://开始按下
                    Down(deltaTime);
                    break;
                case TouchPhase.Ended://抬起
                    Up(deltaTime);
                    break;
                case TouchPhase.Moved://按下后移动
                    if (IsDrag(touchInfo.position))
                        Press(deltaTime);
                    break;
                case TouchPhase.Stationary://按下后保持不动,这里其实不需要IsDrag,这个代码被人改过,我也不想说啥了,聪明人都懂得
                    if (IsDrag(touchInfo.position))
                        Press(deltaTime);
                    break;
                default:
                    break;
            }
        }
        void Down(float deltaTime)
        {
            hasPressed = false;
            InitPressPos(touchInfo.position);
            downTimeStamp = Time.realtimeSinceStartup;
            CreateTouchEvent(EControlType.eDown);
        }
        void Up(float deltaTime)
        {

            if (hasPressed)
            {
                hasPressed = false;
                //Debug.LogError("IControl MoveEnd");
                CreateTouchEvent(EControlType.eMoveEnd);
            }
            else
            {
                //Debug.LogError("IControl Up");
                CreateTouchEvent(EControlType.eUp);
            }
            downTimeStamp = 0;
        }
        void Press(float deltaTime)
        {
            //Debug.LogError("IControl Press");
            hasPressed = true;
            CreateTouchEvent(EControlType.ePress);
        }
        void CreateTouchEvent(EControlType tType)
        {
            tEventManager.AddEvent(new ControlEvent()
            {
                type = tType,
                id = ControlID,
                touchDownTimeStamp = downTimeStamp,
                position = touchInfo.position,
                createTimeStamp = Time.realtimeSinceStartup
            });
        }
    }

b.检测组件管理和消息优先级判定


#region ControlType
    public enum EControlType//触碰事件类型
    {
        eNull = 0,
        eDown = 1,
        ePress = 2,
        eUp = 3,
        eMoveEnd = 4
    }
    #endregion
    #region ControlEventManager
    public class ControlEventManager//触碰检测管理
    {
        List<ControlEvent> rowEventList;//保存未经过筛选的触控事件
        List<IControlHandler> listTouchHandler;//集合中包含触碰检测组件,多点触控2个,鼠标1个,不会同时加载
        ControlEvent lastTriggerEvent = null;//最后一个触发的有效(传给高层组件)的事件
        //Camera m_UICamera;
        bool isDebug = false;//是否开启调试
        TouchDebug tDebug;//DEBUG组件
        private Camera mUICamera//获取摄像机主要是需要支持多点触摸
        {
            get
            {
                return UICamera.mainCamera;
            }
        }
          
        public ControlEventManager()
        {
           
        }
        public void OnInit()
        {
            rowEventList = new List<ControlEvent>();
            listTouchHandler = new List<IControlHandler>();
#if (UNITY_ANDROID || UNITY_IPHONE) && (!UNITY_EDITOR)
            listTouchHandler.Add(new TouchHandler(0, this));//加载触摸检测组件 0 
            listTouchHandler.Add(new TouchHandler(1, this));//家在触摸检测组件 1
#else
            listTouchHandler.Add(new MouseHandler(0, this));//加载鼠标检测组件 0

#endif
            if (isDebug)
            {
                tDebug = new TouchDebug();
                tDebug.OnInit();
            }
        }
        public void OnExit()
        {
            if (isDebug && null != tDebug)
            {
                tDebug.OnExit();
            }
        }
        public void OpenMultiTouch(bool b)//打开关闭多点触控,这里要注意,Input这里有个开关, NGUI的UICamera有个开关(该开关仅影响同时点击UI)
        { 
            Input.multiTouchEnabled = b;
            if (null!=mUICamera)
            {
                UICamera c = mUICamera.GetComponent<UICamera>();
                if (c != null)
                {
                    c.allowMultiTouch = b;
                }
            }
        }
        void ClearEvent()
        {
            rowEventList.Clear();
        }
        public void AddEvent(ControlEvent newEvent)
        {
            if (null != newEvent)
            {
                rowEventList.Add(newEvent);
            }
        }
        public ControlEvent UpdateControl(float deltaTime)//每帧调用每个触摸组件检测
        {
            ClearEvent();
            for (int i = 0; i < listTouchHandler.Count; ++i)
            {
                listTouchHandler[i].updateControl(deltaTime);
            }
            return HandleEvent();//这个时候如果有检测到触摸事件,应该已经添加到事件管理类中,这是处理其中的事件
        }
        ControlEvent HandleEvent()
        {
            ControlEvent ce = GetFirstPirorityEvent();//获取优先级最高的事件

            if (isDebug)
            {
                tDebug.UpdateList(rowEventList);
            }

            if (null!=ce && IsEventChanged(ce) && (!IsTouchUI(ce.position)))//检测事件是否是有意义的改变,同事是否是触碰UI
            {
                lastTriggerEvent = ce;//返回有效事件
                return ce;
            }
            else
            {
                //TouchDebug.PrintDebugInfo("==>>touch event: ignore");
                return null;
            }
        }
        ControlEvent GetFirstPirorityEvent()
        {
            rowEventList.Sort((x, y) => ControlEvent.CompareTouchEvent(x,y));//按照游戏的需求,对事件进行排序,
            if (rowEventList.Count > 0)
            {
                return rowEventList[0];//返回第一个,也就是优先级最高的事件
            }
            return null;
        }
        bool IsEventChanged(ControlEvent cEvent)//检测事件是否改变
        {
            bool flag = true;
            do
            {
                if (null == cEvent)//没有事件,就没有改变
                {
                    flag = false;
                    break;
                }
                if (null == lastTriggerEvent)//有事件,且上次有效事件为空,那这个就是新的事件,有效
                {
                    break;
                }
                if (cEvent.type != EControlType.ePress || lastTriggerEvent.type != EControlType.ePress)//上次和这次只要有一个不是长按事件,有效
                {
                    break;//非长按事件的优先级比较高,这个是从需求分析出来的
                }
                if (cEvent.id != lastTriggerEvent.id)//不是同一个手指,有效,这个不一定触发上层组建的优先级队列,但是对于底层组件,这是个有效事件
                {
                    break;
                }//位置间隔小于2,且事件间隔小于0.2不触发,减少同类型事件的触发频率(其实这里可以看出,这里仅仅是两次事件都是press的情况,且没有移动)
                if (Mathf.Abs(cEvent.position.x - lastTriggerEvent.position.x) < 2f && Mathf.Abs(cEvent.position.y - lastTriggerEvent.position.y) < 2f)
                {
                    if (cEvent.createTimeStamp - lastTriggerEvent.createTimeStamp < 0.2f)
                    {
                        flag = false;
                    }
                }
            } while (false);

            return flag;
        }
        private int UIlayerMask = (1 << LayerMask.NameToLayer("PlayerUI")) |
                (1 << LayerMask.NameToLayer("NGUI")) |
                (1 << LayerMask.NameToLayer("UIEffect"));//UI屏蔽位
        public bool IsTouchUI(Vector3 targetPoint)//检测是否是对UI的点击,其实这个感觉可以从NGUI层面进行记录保存,(没有尝试过,不确定)
        {
            if (mUICamera == null) return false;

            Ray ray = UICamera.mainCamera.ScreenPointToRay(targetPoint);
            RaycastHit hit;
            
            if (Physics.Raycast(ray, out hit, 100f, UIlayerMask))
            {
                return true;
            }
            return false;
        }   
    }
    #endregion
    
    #region ControlEvent
    public class ControlEvent//事件类
    {
        public EControlType type = EControlType.eNull;
        public int id = -1;
        public float touchDownTimeStamp = 0;//按下操作的时间戳,抬起以后为0
        public Vector2 position;
        public float createTimeStamp = 0;//事件创建的时间戳
        public override string ToString()//debug使用
        {
            return string.Format("figureID={0}  type={1} position=({2},{3})  ",
              id,
              type.ToString(),
              position.x,
              position.y
              );
        }//因为我们处理多点触摸的思路一直是将其抽象成一个单一的指令,所以需要排序选出一个最优解来
        static public int CompareTouchEvent(ControlEvent a, ControlEvent b)//比较事件的优先级
        {

            if (null == a && null == b)
            {
                return 0;
            }
            else if (null == a)
            {
                return 1;
            }
            else if (null == b)
            {
                return -1;
            }
            else
            {
                if (a.type == EControlType.eDown)//A按下
                {
                    if (b.type == EControlType.eDown)//B同时按下,这个可能性较小,如果出现,那么fingerID(触摸)小的,表示“先”按下的
                    {
                        if (a.id > b.id)
                        {
                            return -1;
                        }
                        else
                        {
                            return 1;
                        }
                    }
                    else//按下操作的优先级是最高的,超过长按和抬起
                    {
                        return -1;
                    }
                }
                else if (a.type == EControlType.ePress)//A长按
                {
                    if (b.type == EControlType.eDown)//B按下,B优先级高
                    {
                        return 1;
                    }
                    else if (b.type == EControlType.ePress)//B 长按
                    {
                        if (a.touchDownTimeStamp > b.touchDownTimeStamp)//比较A,B两个事件在各自序列中谁先按下的,后按下的(时间戳大)优先级高
                        {
                            return -1;
                        }
                        else if (a.touchDownTimeStamp < b.touchDownTimeStamp)
                        {
                            return 1;
                        }
                        else
                        {
                            return 0;
                        }
                    }
                    else if (b.type == EControlType.eUp)//B弹起,A优先级高
                    {
                        return -1;
                    }
                    else
                    {
                        return -1;
                    }
                }
                else if (a.type == EControlType.eUp)//A弹起
                {
                    if (b.type == EControlType.eDown)//B按下,B优先级高
                    {
                        return 1;
                    }
                    else if (b.type == EControlType.ePress)//B长按  B优先级高
                    {
                        return 1;
                    }
                    else if (b.type == EControlType.eUp)//B弹起,也就是同时弹起
                    {
                        if (a.id > b.id)//fingerID大的优先级高
                        {
                            return -1;
                        }
                        else
                        {
                            return 1;
                        }
                    }
                    else
                    {
                        return 0;
                    }
                }
                else
                {
                    if (b.type == EControlType.eNull)
                    {
                        return 0;
                    }
                    else
                    {
                        return 1;
                    }
                }

            }
        }
    }
    #endregion


c.下层组件

public class BattleTouchController:UnitComponent
    {
         //激活控制
        protected bool isActive = true;//表示是否启用该组件
        ControlEventManager tEventManager; //分别管理
        List<TriggerEvent2> listTrigger;//消息监听,这个我们可以回头再讲讲
        bool inital = false;
        #region 组件生命周期
        public BattleTouchController()
        {
        }
        public BattleTouchController(Units self)
            : base(self)
        {
        }
        public void Enable(bool b)//组件的启用/禁用
        {
            isActive = b;
        }
        public override void OnInit()
        {
            if (!inital)
            {
                Init();
                inital = true;
            }
        }
        public override void OnStart()
        {
            if (RecManager.CheckControl())//非录像播放状态才需要启用组件,其实这个应该放在组件外判断,
            {
                isActive = true;
            }
        }
        public void OnUpdateByFrame(float delta = 0)//每帧调用组件检测
        {
            if (isActive)
            {
                TriggerEvent(tEventManager.UpdateControl(delta));//调用组件检测
                DebugInput();//检测辅助按键,也就是在电脑上模拟多点触控
            }
        }
        public override void OnUpdate(float delta = 0)
        {
        }
        public override void OnStop()
        {
            isActive = false;
        }
        public override void OnExit()//退出时
        {
            tEventManager.OpenMultiTouch(false);//关闭多点触控
            isActive = false;
            UnRegisterEvent();//取消事件监听,
            tEventManager.OnExit();
        }
        #endregion
        #region 触发消息
        void TriggerEvent(ControlEvent tEvent)//
        {
            if (null == tEvent)
                return;
            TriggerParamTouch param = new TriggerParamTouch();
            param.EventID = (int)tEvent.type;
            param.Trigger = this;
            param.Pos = tEvent.position;
            param.FingerID = tEvent.id;
            TriggerManager2.Instance.Trigger2(param);
        }
        #endregion
       
        void Init()
        {
            listTrigger = new List<TriggerEvent2>();
            tEventManager = new ControlEventManager();
            tEventManager.OnInit();
            tEventManager.OpenMultiTouch(true);
            RegisterEvent();  //TriggerParam_touchController
        }
        void RegisterEvent()//注册事件
        {
            TriggerCreateParam_touchController param = new TriggerCreateParam_touchController();//该事件的作用是控制组件enable和disable
            param.EventID = (int)EEventID2_touchController.eStop;
            param.TriggerID = TriggerManager2.assign_trigger_id();
            param.Func_actions = OnStopOrStart;
            param.Func_conditions = null;
            TriggerEvent2 trigger = TriggerManager2.CreateTriggerEvent2(param);
            TriggerManager2.Instance.AddListener(trigger);
            listTrigger.Add(trigger);
        }
       
        void UnRegisterEvent()//取消注册
        {
            TriggerManager2.Instance.RemoveListner(ETriggerType2.TriggerEvent2_manulController);//取消注册消息
            foreach(var it in listTrigger)
            {
                TriggerManager2.Instance.RemoveListner(it);//
            }
        }
        void OnStopOrStart(ITriggerDoActionParam param)//事件监听函数,用于开启/禁用组件
        {
            TriggerParam_touchController info = param as TriggerParam_touchController;
            if (null == info)
                return;
            if (info.Start)
            {
                OnStart();
            }
            else
            {
                OnStop();
            }
        }
        void DebugInput()//用两个按键模拟触发多点触控事件,方便电脑上调试。
        {
#if UNITY_EDITOR
            if (Input.GetKey(KeyCode.S))
            {
                TriggerParamTouch param = new TriggerParamTouch();
                param.EventID = (int)EControlType.ePress;
                param.Trigger = this;
                param.Pos = new Vector2(123, 276);
                param.FingerID = 1;
                TriggerManager2.Instance.Trigger2(param);
            }
            if (Input.GetKey(KeyCode.F))
            {
                TriggerParamTouch param = new TriggerParamTouch();
                param.EventID = (int)EControlType.ePress;
                param.Trigger = this;
                param.Pos = new Vector2(600, 276);
                param.FingerID = 1;
                TriggerManager2.Instance.Trigger2(param);
            }
#endif
        }

 d. 下层debug组件

 #region 触摸点调试
    public class TouchDebug
    {
        string ret1 = "";
        string ret2 = "";
        string ret = "";
        int testTouchNum = 0;
        int createEventTimes = 0;
        int callTimes = 0;
        int updateTimes = 0;
        Touch pointA;
        Touch pointB;
        UILabel labelRet1;
        UILabel labelRet2;
        UILabel labelRet;
        UILabel eventLabel;
        UILabel labelA;
        UILabel labelB;
        List<ControlEvent> eList;
        GameObject root;
        bool valid = false;

        public TouchDebug()
        {
           
        }
        public void OnInit()
        {
            do
            {
                GameObject obj = null;
                obj = Resources.Load("Prefab/Debug/touchDebug") as GameObject;
                if (null == obj)
                    break;
                GameObject target = GameObject.Find("ViewRoot/Camera") as GameObject;
                if (null == target)
                    break;
                root = NGUITools.AddChild(target, obj);
                if (null == root)
                    break;
                root.name = "TouchDebug";

                Transform trans = null;
                trans = root.transform.FindChild("ret1");
                if(null==trans)
                    break;
                labelRet1 = trans.gameObject.GetComponent<UILabel>();
                if (null == labelRet1)
                    break;

                trans = root.transform.FindChild("ret2");
                if (null == trans)
                    break;
                labelRet2 = trans.gameObject.GetComponent<UILabel>();
                if (null == labelRet2)
                    break;

                trans = root.transform.FindChild("ret");
                if (null == trans)
                    break;
                labelRet = trans.gameObject.GetComponent<UILabel>();
                if (null == labelRet)
                    break;

                trans = root.transform.FindChild("event");
                if (null == trans)
                    break;
                eventLabel = trans.gameObject.GetComponent<UILabel>();
                if (null == eventLabel)
                    break;

                trans = root.transform.FindChild("pointA");
                if (null == trans)
                    break;
                labelA = trans.gameObject.GetComponent<UILabel>();
                if (null == labelA)
                    break;
                trans = root.transform.FindChild("pointB");
                if (null == trans)
                    break;
                labelB = trans.gameObject.GetComponent<UILabel>();
                if (null == labelB)
                    break;
                valid = true;
            }
            while (false);
        }
        public void OnExit()
        {
            if (valid && null != root)
            {
                GameObject.Destroy(root);
                root = null;
                valid = false;
            }
        }
        public void UpdateList(List<ControlEvent> list)
        {
            if (valid)
            {
                eList = list;
                RefreshDebugInfo_touchPoint();
                RefreshDebugInfo_ret();
            }
        }
        void RefreshDebugInfo_ret()
        {
            for (int i = 0; i < eList.Count; ++i)
            {
                ControlEvent tEvent = eList[i];
                if (null != tEvent)
                {
                    if (tEvent.id == 0)
                    {
                        ret1 = tEvent.ToString();
                        labelRet1.text = ret1;
                    }
                    else
                    {
                        ret2 = tEvent.ToString();
                        labelRet2.text = ret2;
                    }
                }
            }
            if (eList.Count > 0 && eList[0] != null)
            {
                ret = "ret= " + eList[0].ToString();
                labelRet.text = ret;
            }
        }
        void RefreshDebugInfo_touchPoint()
        {
            testTouchNum = Input.touchCount;

            if (testTouchNum > 0)
            {
                pointA = Input.GetTouch(0);
                labelA.text = string.Format("Touch 1: Phase={0},Id = {1},pos={2}", pointA.phase.ToString(), pointA.fingerId, pointA.position);
            }
            if (testTouchNum > 1)
            {
                pointB = Input.GetTouch(1);
                labelB.text = string.Format("Touch 2: Phase={0},Id = {1},pos={2}", pointB.phase.ToString(), pointB.fingerId, pointB.position);
            }
        }
        public static void PrintDebugInfo(string str)
        {
#if UNITY_EDITOR
            ClientLogger.Debug(LogTagNames.TAG_NULL, str);
#endif
        }
    }
    #endregion




  

猜你喜欢

转载自blog.csdn.net/konglingbin66/article/details/51558280