Guest User

Untitled

a guest
Dec 10th, 2018
73
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 18.92 KB | None | 0 0
  1. package org.flixel.system
  2. {
  3. import org.flixel.FlxBasic;
  4. import org.flixel.FlxGroup;
  5. import org.flixel.FlxObject;
  6. import org.flixel.FlxRect;
  7.  
  8. /**
  9. * A fairly generic quad tree structure for rapid overlap checks.
  10. * FlxQuadTree is also configured for single or dual list operation.
  11. * You can add items either to its A list or its B list.
  12. * When you do an overlap check, you can compare the A list to itself,
  13. * or the A list against the B list. Handy for different things!
  14. */
  15. public class FlxQuadTree extends FlxRect
  16. {
  17. /**
  18. * Flag for specifying that you want to add an object to the A list.
  19. */
  20. static public const A_LIST:uint = 0;
  21. /**
  22. * Flag for specifying that you want to add an object to the B list.
  23. */
  24. static public const B_LIST:uint = 1;
  25.  
  26. /**
  27. * Controls the granularity of the quad tree. Default is 6 (decent performance on large and small worlds).
  28. */
  29. static public var divisions:uint;
  30.  
  31. /**
  32. * Whether this branch of the tree can be subdivided or not.
  33. */
  34. protected var _canSubdivide:Boolean;
  35.  
  36. /**
  37. * Refers to the internal A and B linked lists,
  38. * which are used to store objects in the leaves.
  39. */
  40. protected var _headA:FlxList;
  41. /**
  42. * Refers to the internal A and B linked lists,
  43. * which are used to store objects in the leaves.
  44. */
  45. protected var _tailA:FlxList;
  46. /**
  47. * Refers to the internal A and B linked lists,
  48. * which are used to store objects in the leaves.
  49. */
  50. protected var _headB:FlxList;
  51. /**
  52. * Refers to the internal A and B linked lists,
  53. * which are used to store objects in the leaves.
  54. */
  55. protected var _tailB:FlxList;
  56.  
  57. /**
  58. * Internal, governs and assists with the formation of the tree.
  59. */
  60. static protected var _min:uint;
  61. /**
  62. * Internal, governs and assists with the formation of the tree.
  63. */
  64. protected var _northWestTree:FlxQuadTree;
  65. /**
  66. * Internal, governs and assists with the formation of the tree.
  67. */
  68. protected var _northEastTree:FlxQuadTree;
  69. /**
  70. * Internal, governs and assists with the formation of the tree.
  71. */
  72. protected var _southEastTree:FlxQuadTree;
  73. /**
  74. * Internal, governs and assists with the formation of the tree.
  75. */
  76. protected var _southWestTree:FlxQuadTree;
  77. /**
  78. * Internal, governs and assists with the formation of the tree.
  79. */
  80. protected var _leftEdge:Number;
  81. /**
  82. * Internal, governs and assists with the formation of the tree.
  83. */
  84. protected var _rightEdge:Number;
  85. /**
  86. * Internal, governs and assists with the formation of the tree.
  87. */
  88. protected var _topEdge:Number;
  89. /**
  90. * Internal, governs and assists with the formation of the tree.
  91. */
  92. protected var _bottomEdge:Number;
  93. /**
  94. * Internal, governs and assists with the formation of the tree.
  95. */
  96. protected var _halfWidth:Number;
  97. /**
  98. * Internal, governs and assists with the formation of the tree.
  99. */
  100. protected var _halfHeight:Number;
  101. /**
  102. * Internal, governs and assists with the formation of the tree.
  103. */
  104. protected var _midpointX:Number;
  105. /**
  106. * Internal, governs and assists with the formation of the tree.
  107. */
  108. protected var _midpointY:Number;
  109.  
  110. /**
  111. * Internal, used to reduce recursive method parameters during object placement and tree formation.
  112. */
  113. static protected var _object:FlxObject;
  114. /**
  115. * Internal, used to reduce recursive method parameters during object placement and tree formation.
  116. */
  117. static protected var _objectLeftEdge:Number;
  118. /**
  119. * Internal, used to reduce recursive method parameters during object placement and tree formation.
  120. */
  121. static protected var _objectTopEdge:Number;
  122. /**
  123. * Internal, used to reduce recursive method parameters during object placement and tree formation.
  124. */
  125. static protected var _objectRightEdge:Number;
  126. /**
  127. * Internal, used to reduce recursive method parameters during object placement and tree formation.
  128. */
  129. static protected var _objectBottomEdge:Number;
  130.  
  131. /**
  132. * Internal, used during tree processing and overlap checks.
  133. */
  134. static protected var _list:uint;
  135. /**
  136. * Internal, used during tree processing and overlap checks.
  137. */
  138. static protected var _useBothLists:Boolean;
  139. /**
  140. * Internal, used during tree processing and overlap checks.
  141. */
  142. static protected var _processingCallback:Function;
  143. /**
  144. * Internal, used during tree processing and overlap checks.
  145. */
  146. static protected var _notifyCallback:Function;
  147. /**
  148. * Internal, used during tree processing and overlap checks.
  149. */
  150. static protected var _iterator:FlxList;
  151.  
  152. /**
  153. * Internal, helpers for comparing actual object-to-object overlap - see <code>overlapNode()</code>.
  154. */
  155. static protected var _objectHullX:Number;
  156. /**
  157. * Internal, helpers for comparing actual object-to-object overlap - see <code>overlapNode()</code>.
  158. */
  159. static protected var _objectHullY:Number;
  160. /**
  161. * Internal, helpers for comparing actual object-to-object overlap - see <code>overlapNode()</code>.
  162. */
  163. static protected var _objectHullWidth:Number;
  164. /**
  165. * Internal, helpers for comparing actual object-to-object overlap - see <code>overlapNode()</code>.
  166. */
  167. static protected var _objectHullHeight:Number;
  168.  
  169. /**
  170. * Internal, helpers for comparing actual object-to-object overlap - see <code>overlapNode()</code>.
  171. */
  172. static protected var _checkObjectHullX:Number;
  173. /**
  174. * Internal, helpers for comparing actual object-to-object overlap - see <code>overlapNode()</code>.
  175. */
  176. static protected var _checkObjectHullY:Number;
  177. /**
  178. * Internal, helpers for comparing actual object-to-object overlap - see <code>overlapNode()</code>.
  179. */
  180. static protected var _checkObjectHullWidth:Number;
  181. /**
  182. * Internal, helpers for comparing actual object-to-object overlap - see <code>overlapNode()</code>.
  183. */
  184. static protected var _checkObjectHullHeight:Number;
  185. /**
  186. * A pool to prevent repeated <code>new</code> calls.
  187. */
  188. static public var quadTreePool:ObjectPool = new ObjectPool(FlxQuadTree);
  189.  
  190. protected var _listPool:ObjectPool;
  191. /**
  192. * Instantiate a new Quad Tree node.
  193. *
  194. * @param X The X-coordinate of the point in space.
  195. * @param Y The Y-coordinate of the point in space.
  196. * @param Width Desired width of this node.
  197. * @param Height Desired height of this node.
  198. * @param Parent The parent branch or node. Pass null to create a root.
  199. */
  200. public function init(X:Number, Y:Number, Width:Number, Height:Number, Parent:FlxQuadTree=null):void
  201. {
  202. _listPool = FlxList.listPool;
  203.  
  204. make(X,Y,Width,Height);
  205. _headA = _tailA = _listPool.getNew();
  206. _headB = _tailB = _listPool.getNew();
  207.  
  208. //Copy the parent's children (if there are any)
  209. if(Parent != null)
  210. {
  211. var iterator:FlxList;
  212. var ot:FlxList;
  213. if(Parent._headA.object != null)
  214. {
  215. iterator = Parent._headA;
  216. while(iterator != null)
  217. {
  218. if(_tailA.object != null)
  219. {
  220. ot = _tailA;
  221. _tailA = _listPool.getNew();
  222. ot.next = _tailA;
  223. }
  224. _tailA.object = iterator.object;
  225. iterator = iterator.next;
  226. }
  227. }
  228. if(Parent._headB.object != null)
  229. {
  230. iterator = Parent._headB;
  231. while(iterator != null)
  232. {
  233. if(_tailB.object != null)
  234. {
  235. ot = _tailB;
  236. _tailB = _listPool.getNew();
  237. ot.next = _tailB;
  238. }
  239. _tailB.object = iterator.object;
  240. iterator = iterator.next;
  241. }
  242. }
  243. }
  244. else
  245. _min = (width + height)/(2*divisions);
  246. _canSubdivide = (width > _min) || (height > _min);
  247.  
  248. //Set up comparison/sort helpers
  249. _northWestTree = null;
  250. _northEastTree = null;
  251. _southEastTree = null;
  252. _southWestTree = null;
  253. _leftEdge = x;
  254. _rightEdge = x+width;
  255. _halfWidth = width/2;
  256. _midpointX = _leftEdge+_halfWidth;
  257. _topEdge = y;
  258. _bottomEdge = y+height;
  259. _halfHeight = height/2;
  260. _midpointY = _topEdge+_halfHeight;
  261. }
  262.  
  263. /**
  264. * Clean up memory.
  265. */
  266. public function destroy():void
  267. {
  268. _headA.destroy();
  269. _headA = null;
  270. //_tailA.destroy();
  271. _tailA = null;
  272. _headB.destroy();
  273. _headB = null;
  274. //_tailB.destroy();
  275. _tailB = null;
  276.  
  277. if(_northWestTree != null)
  278. _northWestTree.destroy();
  279. _northWestTree = null;
  280. if(_northEastTree != null)
  281. _northEastTree.destroy();
  282. _northEastTree = null;
  283. if(_southEastTree != null)
  284. _southEastTree.destroy();
  285. _southEastTree = null;
  286. if(_southWestTree != null)
  287. _southWestTree.destroy();
  288. _southWestTree = null;
  289.  
  290. _object = null;
  291. _processingCallback = null;
  292. _notifyCallback = null;
  293.  
  294. quadTreePool.disposeObject(this);
  295. }
  296.  
  297. /**
  298. * Load objects and/or groups into the quad tree, and register notify and processing callbacks.
  299. *
  300. * @param ObjectOrGroup1 Any object that is or extends FlxObject or FlxGroup.
  301. * @param ObjectOrGroup2 Any object that is or extends FlxObject or FlxGroup. If null, the first parameter will be checked against itself.
  302. * @param NotifyCallback A function with the form <code>myFunction(Object1:FlxObject,Object2:FlxObject):void</code> that is called whenever two objects are found to overlap in world space, and either no ProcessCallback is specified, or the ProcessCallback returns true.
  303. * @param ProcessCallback A function with the form <code>myFunction(Object1:FlxObject,Object2:FlxObject):Boolean</code> that is called whenever two objects are found to overlap in world space. The NotifyCallback is only called if this function returns true. See FlxObject.separate().
  304. */
  305. public function load(ObjectOrGroup1:FlxBasic, ObjectOrGroup2:FlxBasic=null, NotifyCallback:Function=null, ProcessCallback:Function=null):void
  306. {
  307. add(ObjectOrGroup1, A_LIST);
  308. if(ObjectOrGroup2 != null)
  309. {
  310. add(ObjectOrGroup2, B_LIST);
  311. _useBothLists = true;
  312. }
  313. else
  314. _useBothLists = false;
  315. _notifyCallback = NotifyCallback;
  316. _processingCallback = ProcessCallback;
  317. }
  318.  
  319. /**
  320. * Call this function to add an object to the root of the tree.
  321. * This function will recursively add all group members, but
  322. * not the groups themselves.
  323. *
  324. * @param ObjectOrGroup FlxObjects are just added, FlxGroups are recursed and their applicable members added accordingly.
  325. * @param List A <code>uint</code> flag indicating the list to which you want to add the objects. Options are <code>A_LIST</code> and <code>B_LIST</code>.
  326. */
  327. public function add(ObjectOrGroup:FlxBasic, List:uint):void
  328. {
  329. _list = List;
  330. if(ObjectOrGroup is FlxGroup)
  331. {
  332. var i:uint = 0;
  333. var basic:FlxBasic;
  334. var members:Array = (ObjectOrGroup as FlxGroup).members;
  335. var l:uint = (ObjectOrGroup as FlxGroup).length;
  336. while(i < l)
  337. {
  338. basic = members[i++] as FlxBasic;
  339. if((basic != null) && basic.exists)
  340. {
  341. if(basic is FlxGroup)
  342. add(basic,List);
  343. else if(basic is FlxObject)
  344. {
  345. _object = basic as FlxObject;
  346. if(_object.exists && _object.allowCollisions)
  347. {
  348. _objectLeftEdge = _object.x;
  349. _objectTopEdge = _object.y;
  350. _objectRightEdge = _object.x + _object.width;
  351. _objectBottomEdge = _object.y + _object.height;
  352. addObject();
  353. }
  354. }
  355. }
  356. }
  357. }
  358. else
  359. {
  360. _object = ObjectOrGroup as FlxObject;
  361. if(_object.exists && _object.allowCollisions)
  362. {
  363. _objectLeftEdge = _object.x;
  364. _objectTopEdge = _object.y;
  365. _objectRightEdge = _object.x + _object.width;
  366. _objectBottomEdge = _object.y + _object.height;
  367. addObject();
  368. }
  369. }
  370. }
  371.  
  372. /**
  373. * Internal function for recursively navigating and creating the tree
  374. * while adding objects to the appropriate nodes.
  375. */
  376. protected function addObject():void
  377. {
  378. //If this quad (not its children) lies entirely inside this object, add it here
  379. if(!_canSubdivide || ((_leftEdge >= _objectLeftEdge) && (_rightEdge <= _objectRightEdge) && (_topEdge >= _objectTopEdge) && (_bottomEdge <= _objectBottomEdge)))
  380. {
  381. addToList();
  382. return;
  383. }
  384.  
  385. //See if the selected object fits completely inside any of the quadrants
  386. if((_objectLeftEdge > _leftEdge) && (_objectRightEdge < _midpointX))
  387. {
  388. if((_objectTopEdge > _topEdge) && (_objectBottomEdge < _midpointY))
  389. {
  390. if(_northWestTree == null)
  391. {
  392. _northWestTree = quadTreePool.getNew();
  393. _northWestTree.init(_leftEdge, _topEdge, _halfWidth, _halfHeight, this);
  394. }
  395. _northWestTree.addObject();
  396. return;
  397. }
  398. if((_objectTopEdge > _midpointY) && (_objectBottomEdge < _bottomEdge))
  399. {
  400. if(_southWestTree == null)
  401. {
  402. _southWestTree = quadTreePool.getNew();
  403. _southWestTree.init(_leftEdge, _midpointY, _halfWidth, _halfHeight, this);
  404. }
  405. _southWestTree.addObject();
  406. return;
  407. }
  408. }
  409. if((_objectLeftEdge > _midpointX) && (_objectRightEdge < _rightEdge))
  410. {
  411. if((_objectTopEdge > _topEdge) && (_objectBottomEdge < _midpointY))
  412. {
  413. if(_northEastTree == null)
  414. {
  415. _northEastTree = quadTreePool.getNew();
  416. _northEastTree.init(_midpointX, _topEdge, _halfWidth, _halfHeight, this);
  417. }
  418. _northEastTree.addObject();
  419. return;
  420. }
  421. if((_objectTopEdge > _midpointY) && (_objectBottomEdge < _bottomEdge))
  422. {
  423. if (_southEastTree == null)
  424. {
  425. _southEastTree = quadTreePool.getNew();
  426. _southEastTree.init(_midpointX, _midpointY, _halfWidth, _halfHeight, this);
  427. }
  428. _southEastTree.addObject();
  429. return;
  430. }
  431. }
  432.  
  433. //If it wasn't completely contained we have to check out the partial overlaps
  434. if((_objectRightEdge > _leftEdge) && (_objectLeftEdge < _midpointX) && (_objectBottomEdge > _topEdge) && (_objectTopEdge < _midpointY))
  435. {
  436. if (_northWestTree == null)
  437. {
  438. _northWestTree = quadTreePool.getNew();
  439. _northWestTree.init(_leftEdge, _topEdge, _halfWidth, _halfHeight, this);
  440. }
  441. _northWestTree.addObject();
  442. }
  443. if((_objectRightEdge > _midpointX) && (_objectLeftEdge < _rightEdge) && (_objectBottomEdge > _topEdge) && (_objectTopEdge < _midpointY))
  444. {
  445. if (_northEastTree == null)
  446. {
  447. _northEastTree = quadTreePool.getNew();
  448. _northEastTree.init(_midpointX, _topEdge, _halfWidth, _halfHeight, this);
  449. }
  450. _northEastTree.addObject();
  451. }
  452. if((_objectRightEdge > _midpointX) && (_objectLeftEdge < _rightEdge) && (_objectBottomEdge > _midpointY) && (_objectTopEdge < _bottomEdge))
  453. {
  454. if(_southEastTree == null)
  455. {
  456. _southEastTree = quadTreePool.getNew();
  457. _southEastTree.init(_midpointX, _midpointY, _halfWidth, _halfHeight, this);
  458. }
  459. _southEastTree.addObject();
  460. }
  461. if((_objectRightEdge > _leftEdge) && (_objectLeftEdge < _midpointX) && (_objectBottomEdge > _midpointY) && (_objectTopEdge < _bottomEdge))
  462. {
  463. if (_southWestTree == null)
  464. {
  465. _southWestTree = quadTreePool.getNew();
  466. _southWestTree.init(_leftEdge, _midpointY, _halfWidth, _halfHeight, this);
  467. }
  468. _southWestTree.addObject();
  469. }
  470. }
  471.  
  472. /**
  473. * Internal function for recursively adding objects to leaf lists.
  474. */
  475. protected function addToList():void
  476. {
  477. var ot:FlxList;
  478. if(_list == A_LIST)
  479. {
  480. if(_tailA.object != null)
  481. {
  482. ot = _tailA;
  483. _tailA = _listPool.getNew();
  484. ot.next = _tailA;
  485. }
  486. _tailA.object = _object;
  487. }
  488. else
  489. {
  490. if(_tailB.object != null)
  491. {
  492. ot = _tailB;
  493. _tailB = _listPool.getNew();
  494. ot.next = _tailB;
  495. }
  496. _tailB.object = _object;
  497. }
  498. if(!_canSubdivide)
  499. return;
  500. if(_northWestTree != null)
  501. _northWestTree.addToList();
  502. if(_northEastTree != null)
  503. _northEastTree.addToList();
  504. if(_southEastTree != null)
  505. _southEastTree.addToList();
  506. if(_southWestTree != null)
  507. _southWestTree.addToList();
  508. }
  509.  
  510. /**
  511. * <code>FlxQuadTree</code>'s other main function. Call this after adding objects
  512. * using <code>FlxQuadTree.load()</code> to compare the objects that you loaded.
  513. *
  514. * @return Whether or not any overlaps were found.
  515. */
  516. public function execute():Boolean
  517. {
  518. var overlapProcessed:Boolean = false;
  519. var iterator:FlxList;
  520.  
  521. if(_headA.object != null)
  522. {
  523. iterator = _headA;
  524. while(iterator != null)
  525. {
  526. _object = iterator.object;
  527. if(_useBothLists)
  528. _iterator = _headB;
  529. else
  530. _iterator = iterator.next;
  531. if( _object.exists && (_object.allowCollisions > 0) &&
  532. (_iterator != null) && (_iterator.object != null) &&
  533. _iterator.object.exists &&overlapNode())
  534. {
  535. overlapProcessed = true;
  536. }
  537. iterator = iterator.next;
  538. }
  539. }
  540.  
  541. //Advance through the tree by calling overlap on each child
  542. if((_northWestTree != null) && _northWestTree.execute())
  543. overlapProcessed = true;
  544. if((_northEastTree != null) && _northEastTree.execute())
  545. overlapProcessed = true;
  546. if((_southEastTree != null) && _southEastTree.execute())
  547. overlapProcessed = true;
  548. if((_southWestTree != null) && _southWestTree.execute())
  549. overlapProcessed = true;
  550.  
  551. return overlapProcessed;
  552. }
  553.  
  554. /**
  555. * An internal function for comparing an object against the contents of a node.
  556. *
  557. * @return Whether or not any overlaps were found.
  558. */
  559. protected function overlapNode():Boolean
  560. {
  561. //Walk the list and check for overlaps
  562. var overlapProcessed:Boolean = false;
  563. var checkObject:FlxObject;
  564. while(_iterator != null)
  565. {
  566. if(!_object.exists || (_object.allowCollisions <= 0))
  567. break;
  568.  
  569. checkObject = _iterator.object;
  570. if((_object === checkObject) || !checkObject.exists || (checkObject.allowCollisions <= 0))
  571. {
  572. _iterator = _iterator.next;
  573. continue;
  574. }
  575.  
  576. //calculate bulk hull for _object
  577. _objectHullX = (_object.x < _object.last.x)?_object.x:_object.last.x;
  578. _objectHullY = (_object.y < _object.last.y)?_object.y:_object.last.y;
  579. _objectHullWidth = _object.x - _object.last.x;
  580. _objectHullWidth = _object.width + ((_objectHullWidth>0)?_objectHullWidth:-_objectHullWidth);
  581. _objectHullHeight = _object.y - _object.last.y;
  582. _objectHullHeight = _object.height + ((_objectHullHeight>0)?_objectHullHeight:-_objectHullHeight);
  583.  
  584. //calculate bulk hull for checkObject
  585. _checkObjectHullX = (checkObject.x < checkObject.last.x)?checkObject.x:checkObject.last.x;
  586. _checkObjectHullY = (checkObject.y < checkObject.last.y)?checkObject.y:checkObject.last.y;
  587. _checkObjectHullWidth = checkObject.x - checkObject.last.x;
  588. _checkObjectHullWidth = checkObject.width + ((_checkObjectHullWidth>0)?_checkObjectHullWidth:-_checkObjectHullWidth);
  589. _checkObjectHullHeight = checkObject.y - checkObject.last.y;
  590. _checkObjectHullHeight = checkObject.height + ((_checkObjectHullHeight>0)?_checkObjectHullHeight:-_checkObjectHullHeight);
  591.  
  592. //check for intersection of the two hulls
  593. if( (_objectHullX + _objectHullWidth > _checkObjectHullX) &&
  594. (_objectHullX < _checkObjectHullX + _checkObjectHullWidth) &&
  595. (_objectHullY + _objectHullHeight > _checkObjectHullY) &&
  596. (_objectHullY < _checkObjectHullY + _checkObjectHullHeight) )
  597. {
  598. //Execute callback functions if they exist
  599. if((_processingCallback == null) || _processingCallback(_object,checkObject))
  600. overlapProcessed = true;
  601. if(overlapProcessed && (_notifyCallback != null))
  602. _notifyCallback(_object,checkObject);
  603. }
  604. _iterator = _iterator.next;
  605. }
  606.  
  607. return overlapProcessed;
  608. }
  609. }
  610. }
Add Comment
Please, Sign In to add comment