1 MouseManager:
2 private function check(sp:Sprite, mouseX:Number, mouseY:Number, callBack:Function):Boolean {
3 this._point.setTo(mouseX, mouseY);
4 sp.fromParentPoint(this._point);
5 mouseX = this._point.x;
6 mouseY = this._point.y;
7
8 //如果有裁剪,則先判斷是否在裁剪范圍內
9 var scrollRect:Rectangle = sp.scrollRect;
10 if (scrollRect) {
11 _rect.setTo(scrollRect.x, scrollRect.y, scrollRect.width, scrollRect.height);
12 if (!_rect.contains(mouseX, mouseY)) return false;
13 }
14
15 //先判定子對象是否命中
16 if (!disableMouseEvent) {
17 //優先判斷父對象
18 //默認情況下,hitTestPrior=mouseThrough=false,也就是優先check子對象
19 //$NEXTBIG:下個重大版本將sp.mouseThrough從此邏輯中去除,從而使得sp.mouseThrough只負責目標對象的穿透
20 if (sp.hitTestPrior && !sp.mouseThrough && !hitTest(sp, mouseX, mouseY)) {
21 return false;
22 }
23 for (var i:int = sp._childs.length - 1; i > -1; i--) { //倒敘遍歷,從外向內檢測,如果檢測到則跳過內部檢測
24 var child:Sprite = sp._childs[i];
25 //只有接受交互事件的,才進行處理
26 if (!child.destroyed && child.mouseEnabled && child.visible) {
27 if (check(child, mouseX, mouseY, callBack)) return true;
28 }
29 }
30 }
31
32 //避免重復進行碰撞檢測,考慮了判斷條件的命中率。
33 var isHit:Boolean = (sp.hitTestPrior && !sp.mouseThrough && !disableMouseEvent) ? true : hitTest(sp, mouseX, mouseY);
34
35 if (isHit) {
36 _target = sp;
37 callBack.call(this, sp);
38 } else if (callBack === onMouseUp && sp === _stage) {
39 //如果stage外mouseUP
40 _target = _stage;
41 callBack.call(this, _target);
42 }
43
44 return isHit;
45 }
46
47 private function hitTest(sp:Sprite, mouseX:Number, mouseY:Number):Boolean {
48 var isHit:Boolean = false;
49 if (sp.scrollRect) {
50 mouseX -= sp.scrollRect.x;
51 mouseY -= sp.scrollRect.y;
52 }
53 if (sp.hitArea is HitArea) {
54 return sp.hitArea.isHit(mouseX, mouseY);
55 }
56 if (sp.width > 0 && sp.height > 0 || sp.mouseThrough || sp.hitArea) {
57 //判斷是否在矩形區域內
58 if (!sp.mouseThrough) {
59 var hitRect:Rectangle = this._rect;
60 if (sp.hitArea) hitRect = sp.hitArea;
61 else hitRect.setTo(0, 0, sp.width, sp.height); //坐標已轉換為本地坐標系
62 isHit = hitRect.contains(mouseX, mouseY);
63 } else {
64 //如果可穿透,則根據子對象實際大小進行碰撞
65 isHit = sp.getGraphicBounds().contains(mouseX, mouseY);
66 }
67 }
68 return isHit;
69 }
70
71 /**
72 * 執行事件處理。
73 */
74 public function runEvent():void {
75 var len:int = _eventList.length;
76 if (!len) return;
77
78 var _this:MouseManager = this;
79 var i:int = 0,j:int,n:int,touch:*;
80 while (i < len) {
81 var evt:* = _eventList[i];
82
83 if (evt.type !== 'mousemove') _prePoint.x = _prePoint.y = -1000000;
84
85 switch (evt.type) {
86 case 'mousedown':
87 _touchIDs[0] = _id++;
88 if (!_isTouchRespond) {
89 _this._isLeftMouse = evt.button === 0;
90 _this.initEvent(evt);
91 _this.check(_this._stage, _this.mouseX, _this.mouseY, _this.onMouseDown);
92 } else
93 _isTouchRespond = false;
94 break;
95 case 'mouseup':
96 _this._isLeftMouse = evt.button === 0;
97 _this.initEvent(evt);
98 _this.check(_this._stage, _this.mouseX, _this.mouseY, _this.onMouseUp);
99 break;
100 case 'mousemove':
101 if ((Math.abs(_prePoint.x - evt.clientX) + Math.abs(_prePoint.y - evt.clientY)) >= mouseMoveAccuracy) {
102 _prePoint.x = evt.clientX;
103 _prePoint.y = evt.clientY;
104 _this.initEvent(evt);
105 _this.check(_this._stage, _this.mouseX, _this.mouseY, _this.onMouseMove);
106 // _this.checkMouseOut();
107 }
108 break;
109 case "touchstart":
110 _isTouchRespond = true;
111 _this._isLeftMouse = true;
112 var touches:Array = evt.changedTouches;
113 for (j = 0, n = touches.length; j < n; j++) {
114 touch = touches[j];
115 //是否禁用多點觸控
116 if (multiTouchEnabled || isNaN(_curTouchID)) {
117 _curTouchID = touch.identifier;
118 //200次點擊清理一下id資源
119 if (_id % 200 === 0) _touchIDs = {};
120 _touchIDs[touch.identifier] = _id++;
121 _this.initEvent(touch, evt);
122 _this.check(_this._stage, _this.mouseX, _this.mouseY, _this.onMouseDown);
123 }
124 }
125
126 break;
127 case "touchend":
128 case "touchcancel":
129 _isTouchRespond = true;
130 _this._isLeftMouse = true;
131 var touchends:Array = evt.changedTouches;
132 for (j = 0, n = touchends.length; j < n; j++) {
133 touch = touchends[j];
134 //是否禁用多點觸控
135 if (multiTouchEnabled || touch.identifier == _curTouchID) {
136 _curTouchID = NaN;
137 _this.initEvent(touch, evt);
138 var isChecked:Boolean;
139 isChecked = _this.check(_this._stage, _this.mouseX, _this.mouseY, _this.onMouseUp);
140 if (!isChecked)
141 {
142 _this.onMouseUp(null);
143 }
144 }
145 }
146
147 break;
148 case "touchmove":
149 var touchemoves:Array = evt.changedTouches;
150 for (j = 0, n = touchemoves.length; j < n; j++) {
151 touch = touchemoves[j];
152 //是否禁用多點觸控
153 if (multiTouchEnabled || touch.identifier == _curTouchID) {
154 _this.initEvent(touch, evt);
155 _this.check(_this._stage, _this.mouseX, _this.mouseY, _this.onMouseMove);
156 }
157 }
158 break;
159 case "wheel":
160 case "mousewheel":
161 case "DOMMouseScroll":
162 _this.checkMouseWheel(evt);
163 break;
164 case "mouseout":
165 //_this._stage.event(Event.MOUSE_OUT, _this._event.setTo(Event.MOUSE_OUT, _this._stage, _this._stage));
166 TouchManager.I.stageMouseOut();
167 break;
168 case "mouseover":
169 _this._stage.event(Event.MOUSE_OVER, _this._event.setTo(Event.MOUSE_OVER, _this._stage, _this._stage));
170 break;
171 }
172 i++;
173 }
174 _eventList.length = 0;
175 }
176 }
177 TouchManager
178 /**
179 * 派發事件。
180 * @param eles 對象列表。
181 * @param type 事件類型。
182 * @param touchID (可選)touchID,默認為0。
183 */
184 private function sendEvents(eles:Array, type:String, touchID:int = 0):void {
185 var i:int, len:int;
186 len = eles.length;
187 _event._stoped = false;
188 var _target:*;
189 _target = eles[0];
190 var tE:Sprite;
191 for (i = 0; i < len; i++) {
192 tE = eles[i];
193 if (tE.destroyed) return;
194 tE.event(type, _event.setTo(type, tE, _target));
195 if (_event._stoped)
196 break;
197 }
198 }
199
200 /**
201 * 獲取對象列表。
202 * @param start 起始節點。
203 * @param end 結束節點。
204 * @param rst 返回值。如果此值不為空,則將其賦值為計算結果,從而避免創建新數組;如果此值為空,則創建新數組返回。
205 * @return Array 返回節點列表。
206 */
207 private function getEles(start:Node, end:Node = null, rst:Array = null):Array {
208 if (!rst) {
209 rst = [];
210 } else {
211 rst.length = 0;
212 }
213 while (start && start != end) {
214 rst.push(start);
215 start = start.parent;
216 }
217 return rst;
218 }