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

     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。


  
    
    
  
  
    
    
    
    
    
    
    
  
  
    
    
  

    事实上,我们只需要使用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查找TOUCH
		private 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);
                }
            }
        }

   

你可能感兴趣的:(AS3)