AS3中将TUIO协议转换到传统触摸事件

来源:互联网 发布:eclipse 改变端口号 编辑:程序博客网 时间:2024/06/11 02:29

     TUIO是一个用途广泛,支持厂商众多的多点触摸协议。 其编码采用XML抽象描述,所以任何支持XML的语言都可以使用TUIO协议的触摸设备。另外,TUIO不受windows触摸点上限限制,即设备支持多少个点,你就能使用多少个。

    现在最新的TUIO协议版本是2.0 ,  但是仍然没有普及,现有设备还是以1.0为默认支持。


    希望在设备中使用TUIO,必须要与TUIO服务建立一个连接,TUIO协议的默认端口为 3000,这里跳过连接直接进入主题。

   

    这是一个TUIO协议的一个数据包,其包含至少3个名为MESSAGE子项,每个子项的第一个子项的value属性定义了此子项的数据类型,

    以此例为示,它有3个子项,第1个子项(alive)代表着当前存在的触摸点,这里是指所有在设备上的触摸点,包括那些正在移动的和静止的。第2个子项(set)对应了一个触摸点的详细数据,第3个子项(fseq)定义了包的序列ID。

<OSCPACKET ADDRESS="127.0.0.1" PORT="55448" TIME="-3736546999771946328">  <MESSAGE NAME="/tuio/2Dcur">    <ARGUMENT TYPE="s" VALUE="alive"/>    <ARGUMENT TYPE="i" VALUE="4"/>  </MESSAGE>  <MESSAGE NAME="/tuio/2Dcur">    <ARGUMENT TYPE="s" VALUE="set"/>    <ARGUMENT TYPE="i" VALUE="4"/>    <ARGUMENT TYPE="f" VALUE="0.014778325123152709"/>    <ARGUMENT TYPE="f" VALUE="0.03414634146341464"/>    <ARGUMENT TYPE="f" VALUE="0"/>    <ARGUMENT TYPE="f" VALUE="0"/>    <ARGUMENT TYPE="f" VALUE="0"/>  </MESSAGE>  <MESSAGE NAME="/tuio/2Dcur">    <ARGUMENT TYPE="s" VALUE="fseq"/>    <ARGUMENT TYPE="i" VALUE="3"/>  </MESSAGE></OSCPACKET>

    事实上,我们只需要使用alive和set消息,其他的消息都不在我们的考虑之内,

    set消息传过来的参数只是TUIO设备上的坐标比例,从0-1,将其与本地舞台大小相乘才能得到舞台坐标。


   alive消息描述了当前存在的点,根据这个参数我们可以排除那些已经消失的点。首先,我们先创建一个触摸点类

    import flash.display.InteractiveObject;    public class TuioObject    {        /** 触摸id */        public var id:int;                /** 远程触摸编号 */        public var remoteID:int;                /** 指针对象 */        public var target:InteractiveObject;                /** 屏幕上的位置 */        public var x:int;                /** 屏幕上的位置 */        public var y:int;                /** 生效时候的位置 */        public var startX:Number;                /** 生效时候的位置 */        public var startY:Number;                /** 是否存在 */        public var isExist:Boolean;                public function TuioObject(touchID:int,x:Number,y:Number)        {            id = touchID;            this.x = startX = x;            this.y = startY = y;            isExist = true;        }

    这个类描述了一个TUIO触摸点,每次出现新的触摸点时我们实例化一个与其相对应的触摸点。由于传输过来的数据并没有告诉我们某个触摸点是刚出现的,我们必须从现有的触摸点集合中查找ID,如果没有找到则判断为新的触摸事件。

//根据ID查找TOUCHprivate function searchByRemoteName(remoteID:int):TuioObject{for each(var touch:TuioObject in _touchList){if(touch.remoteID == remoteID){return touch;}}return null;}


    当有一个新点出现时,我们必须为它指定一个指向显示对象,以便从其向舞台冒泡事件,如果从这个点没有找到显示对象,则直接对舞台抛事件。注意,只有InteractiveObject才能抛出触摸事件,而Bitmap或Shape则不能接受鼠标事件

//搜索舞台元素  private function findDisplayObject(x:Number,y:Number):InteractiveObject{var obj:DisplayObject;var objArray:Array = _stage.getObjectsUnderPoint(new Point(x,y));if(objArray.length>0){obj=objArray[objArray.length-1];if(!(obj is InteractiveObject)){obj = obj.parent;}return obj;}else{return _stage;}}

    而由于从tuio里发送过来的事件都是以TUIO自己习惯进行编号的,为了防止与本地的触摸冲突,我们需要给每个触摸点一个本地的ID,本地的触摸编号从1开始到255结束,我们就从256开始,上限随你设定,尽管你设置的上限足够大,但是必须为其准备一个超出上限了就返回-1的默认值

        private function getFreeID():int{            for(var i:int=256;i<1024;i++){                var used:Boolean=false;                for each(var temp:TuioObject in _touchList){                    used = i == temp.id;                }                if(!used)return i;            }            return -1;        }

    为了让程序更清晰一点,我们将   触摸点生效、触摸点移动、触摸点消失  三个状态的处理函数分开来写。

                //应用新的触摸点private function addTouch(touchPoint:TuioObject):void{touchPoint.target = findDisplayObject(touchPoint.x,touchPoint.y);if(touchPoint.target == _stage){_stage.dispatchEvent(new TouchEvent(TouchEvent.TOUCH_BEGIN,true,false,touchPoint.id,false,touchPoint.x,touchPoint.y));}else{var local:Point = touchPoint.target.globalToLocal(new Point(touchPoint.x,touchPoint.y));touchPoint.target.dispatchEvent(new TouchEvent(TouchEvent.TOUCH_BEGIN,true,false,touchPoint.id,false,local.x,local.y));}}//触摸点移动private function moveTouch(touchPoint:TuioObject):void{var oldTarget:InteractiveObject = touchPoint.target;touchPoint.target = findDisplayObject(touchPoint.x,touchPoint.y);var local:Point = touchPoint.target.globalToLocal(new Point(touchPoint.x,touchPoint.y));if(touchPoint.target == oldTarget){oldTarget.dispatchEvent(new TouchEvent(TouchEvent.TOUCH_MOVE,true,false,touchPoint.id,false,local.x,local.y));}else{var old:Point = oldTarget.globalToLocal(new Point(touchPoint.x,touchPoint.y));oldTarget.dispatchEvent(new TouchEvent(TouchEvent.TOUCH_OUT,true,false,touchPoint.id,false,old.x,old.y,NaN,NaN,NaN,touchPoint.target));touchPoint.target.dispatchEvent(new TouchEvent(TouchEvent.TOUCH_OVER,true,false,touchPoint.id,false,local.x,local.y,NaN,NaN,NaN,touchPoint.target));touchPoint.target.dispatchEvent(new TouchEvent(TouchEvent.TOUCH_MOVE,true,false,touchPoint.id,false,local.x,local.y));}}//触摸点消失private function removeTouch(touchPoint:TuioObject):void{var oldTarget:InteractiveObject = touchPoint.target;touchPoint.target = findDisplayObject(touchPoint.x,touchPoint.y);var local:Point = touchPoint.target.globalToLocal(new Point(touchPoint.x,touchPoint.y));if(touchPoint.target == oldTarget){oldTarget.dispatchEvent(new TouchEvent(TouchEvent.TOUCH_END,true,false,touchPoint.id,false,local.x,local.y));}else{var old:Point = oldTarget.globalToLocal(new Point(touchPoint.x,touchPoint.y));oldTarget.dispatchEvent(new TouchEvent(TouchEvent.TOUCH_OUT,true,false,touchPoint.id,false,old.x,old.y,NaN,NaN,NaN,touchPoint.target));touchPoint.target.dispatchEvent(new TouchEvent(TouchEvent.TOUCH_OVER,true,false,touchPoint.id,false,local.x,local.y,NaN,NaN,NaN,touchPoint.target));touchPoint.target.dispatchEvent(new TouchEvent(TouchEvent.TOUCH_END,true,false,touchPoint.id,false,local.x,local.y));}                }

    最后  关键的处理TUIO的xml消息的函数

                //解析消息        private function processMessage(msg:XML):void{            //点是否存在  不存在则从列表中移除            var node:XML;            var touch:TuioObject;            for each(node in msg.MESSAGE)            {                if(node.ARGUMENT[0].@VALUE == "alive")                {                    for each (touch in _touchList)touch.isExist=false;                                        for each(var aliveItem:XML in node.ARGUMENT.(@VALUE != "alive"))                    {                        touch = searchByRemoteName(int(aliveItem.@VALUE));                        if(touch){                            touch.isExist=true;                        }                    }                }            }            //处理事件            var remoteID:int;            var x:Number;            var y:Number;            var touchObj:TuioObject;            for each(node in msg.MESSAGE)            {                if(node.ARGUMENT[0] && node.@NAME == "/tuio/2Dcur")                {                    if(node.ARGUMENT[0].@VALUE == "set")                     {                        remoteID = int(node.ARGUMENT[1].@VALUE);                        x = Number(node.ARGUMENT[2].@VALUE) * _stageWidth;                        y = Number(node.ARGUMENT[3].@VALUE) * _stageHeight;                                                touchObj=searchByRemoteName(remoteID);                        if(!touchObj){                            var id:int = getFreeID();                            if(id == -1)return;                            touchObj = new TuioObject(id,x,y);                            touchObj.remoteID = remoteID;                            _touchList.push(touchObj);                            addTouch(touchObj);                        }else{                            touchObj.x = x ;touchObj.y = y;                            moveTouch(touchObj);                        }                    }                }            }                        //处理不存在的点            for(var i:int=_touchList.length-1;i>=0;i--){                if(!_touchList[i].isExist){                    removeTouch(_touchList[i]);                    _touchList.splice(i,1);                }            }        }

   

0 0
原创粉丝点击