33 * @version 1.0
44 * @author Timo Hausmann
55 *
6- * Optimised to reduce temp. var creation and increase performance by Richard Davey
6+ * @version 1.2, September 4th 2013
7+ * @author Richard Davey
8+ * The original code was a conversion of the Java code posted to GameDevTuts. However I've tweaked
9+ * it massively to add node indexing, removed lots of temp. var creation and significantly
10+ * increased performance as a result.
711 *
812 * Original version at https://github.com/timohausmann/quadtree-js/
913 */
@@ -37,8 +41,12 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
3741* @param Integer maxLevels (optional) total max levels inside root QuadTree (default: 4)
3842* @param Integer level (optional) deepth level, required for subnodes
3943*/
40- Phaser . QuadTree = function ( x , y , width , height , maxObjects , maxLevels , level ) {
44+ Phaser . QuadTree = function ( physicsManager , x , y , width , height , maxObjects , maxLevels , level ) {
4145
46+ this . physicsManager = physicsManager ;
47+ this . ID = physicsManager . quadTreeID ;
48+ physicsManager . quadTreeID ++ ;
49+
4250 this . maxObjects = maxObjects || 10 ;
4351 this . maxLevels = maxLevels || 4 ;
4452 this . level = level || 0 ;
@@ -66,67 +74,19 @@ Phaser.QuadTree.prototype = {
6674 */
6775 split : function ( ) {
6876
69- this . level + 1 ;
77+ this . level ++ ;
7078
7179 // top right node
72- this . nodes [ 0 ] = new Phaser . QuadTree ( this . bounds . right , this . bounds . y , this . bounds . subWidth , this . bounds . subHeight , this . maxObjects , this . maxLevels , this . level ) ;
80+ this . nodes [ 0 ] = new Phaser . QuadTree ( this . physicsManager , this . bounds . right , this . bounds . y , this . bounds . subWidth , this . bounds . subHeight , this . maxObjects , this . maxLevels , this . level ) ;
7381
7482 // top left node
75- this . nodes [ 1 ] = new Phaser . QuadTree ( this . bounds . x , this . bounds . y , this . bounds . subWidth , this . bounds . subHeight , this . maxObjects , this . maxLevels , this . level ) ;
83+ this . nodes [ 1 ] = new Phaser . QuadTree ( this . physicsManager , this . bounds . x , this . bounds . y , this . bounds . subWidth , this . bounds . subHeight , this . maxObjects , this . maxLevels , this . level ) ;
7684
7785 // bottom left node
78- this . nodes [ 2 ] = new Phaser . QuadTree ( this . bounds . x , this . bounds . bottom , this . bounds . subWidth , this . bounds . subHeight , this . maxObjects , this . maxLevels , this . level ) ;
86+ this . nodes [ 2 ] = new Phaser . QuadTree ( this . physicsManager , this . bounds . x , this . bounds . bottom , this . bounds . subWidth , this . bounds . subHeight , this . maxObjects , this . maxLevels , this . level ) ;
7987
8088 // bottom right node
81- this . nodes [ 3 ] = new Phaser . QuadTree ( this . bounds . right , this . bounds . bottom , this . bounds . subWidth , this . bounds . subHeight , this . maxObjects , this . maxLevels , this . level ) ;
82-
83- } ,
84-
85- /*
86- * Determine which node the object belongs to
87- * @param Object pRect bounds of the area to be checked, with x, y, width, height
88- * @return Integer index of the subnode (0-3), or -1 if pRect cannot completely fit within a subnode and is part of the parent node
89- */
90- getIndex : function ( rect ) {
91-
92- var index = - 1 ;
93-
94- // var verticalMidpoint = this.bounds.x + (this.bounds.width / 2);
95- var verticalMidpoint = this . bounds . right ;
96- // var horizontalMidpoint = this.bounds.y + (this.bounds.height / 2);
97- var horizontalMidpoint = this . bounds . bottom ;
98-
99- var topQuadrant = ( rect . y < this . bounds . bottom && rect . bottom < this . bounds . bottom ) ;
100- var bottomQuadrant = ( rect . y > this . bounds . bottom ) ;
101-
102- // rect can completely fit within the left quadrants
103- if ( rect . x < verticalMidpoint && rect . right < verticalMidpoint )
104- {
105- if ( topQuadrant )
106- {
107- // rect can completely fit within the top quadrants
108- index = 1 ;
109- }
110- else if ( bottomQuadrant )
111- {
112- // rect can completely fit within the bottom quadrants
113- index = 2 ;
114- }
115- }
116- else if ( rect . x > verticalMidpoint )
117- {
118- // rect can completely fit within the right quadrants
119- if ( topQuadrant )
120- {
121- index = 0 ;
122- }
123- else if ( bottomQuadrant )
124- {
125- index = 3 ;
126- }
127- }
128-
129- return index ;
89+ this . nodes [ 3 ] = new Phaser . QuadTree ( this . physicsManager , this . bounds . right , this . bounds . bottom , this . bounds . subWidth , this . bounds . subHeight , this . maxObjects , this . maxLevels , this . level ) ;
13090
13191 } ,
13292
@@ -142,7 +102,6 @@ Phaser.QuadTree.prototype = {
142102 var index ;
143103
144104 // if we have subnodes ...
145- // if (typeof this.nodes[0] !== 'undefined')
146105 if ( this . nodes [ 0 ] != null )
147106 {
148107 index = this . getIndex ( body . bounds ) ;
@@ -156,10 +115,9 @@ Phaser.QuadTree.prototype = {
156115
157116 this . objects . push ( body ) ;
158117
159- if ( this . objects . length > this . maxObjects && this . level < this . maxLevels )
118+ if ( this . objects . length > this . maxObjects && this . level < this . maxLevels )
160119 {
161120 // Split if we don't already have subnodes
162- // if (typeof this.nodes[0] === 'undefined')
163121 if ( this . nodes [ 0 ] == null )
164122 {
165123 this . split ( ) ;
@@ -170,7 +128,7 @@ Phaser.QuadTree.prototype = {
170128 {
171129 index = this . getIndex ( this . objects [ i ] . bounds ) ;
172130
173- if ( index !== - 1 )
131+ if ( index !== - 1 )
174132 {
175133 // this is expensive - see what we can do about it
176134 this . nodes [ index ] . insert ( this . objects . splice ( i , 1 ) [ 0 ] ) ;
@@ -183,32 +141,76 @@ Phaser.QuadTree.prototype = {
183141 }
184142 } ,
185143
144+ /*
145+ * Determine which node the object belongs to
146+ * @param Object pRect bounds of the area to be checked, with x, y, width, height
147+ * @return Integer index of the subnode (0-3), or -1 if pRect cannot completely fit within a subnode and is part of the parent node
148+ */
149+ getIndex : function ( rect ) {
150+
151+ // default is that rect doesn't fit, i.e. it straddles the internal quadrants
152+ var index = - 1 ;
153+
154+ if ( rect . x < this . bounds . right && rect . right < this . bounds . right )
155+ {
156+ if ( ( rect . y < this . bounds . bottom && rect . bottom < this . bounds . bottom ) )
157+ {
158+ // rect fits within the top-left quadrant of this quadtree
159+ index = 1 ;
160+ }
161+ else if ( ( rect . y > this . bounds . bottom ) )
162+ {
163+ // rect fits within the bottom-left quadrant of this quadtree
164+ index = 2 ;
165+ }
166+ }
167+ else if ( rect . x > this . bounds . right )
168+ {
169+ // rect can completely fit within the right quadrants
170+ if ( ( rect . y < this . bounds . bottom && rect . bottom < this . bounds . bottom ) )
171+ {
172+ // rect fits within the top-right quadrant of this quadtree
173+ index = 0 ;
174+ }
175+ else if ( ( rect . y > this . bounds . bottom ) )
176+ {
177+ // rect fits within the bottom-right quadrant of this quadtree
178+ index = 3 ;
179+ }
180+ }
181+
182+ return index ;
183+
184+ } ,
185+
186186 /*
187187 * Return all objects that could collide with the given object
188188 * @param Object pRect bounds of the object to be checked, with x, y, width, height
189189 * @Return Array array with all detected objects
190190 */
191191 retrieve : function ( sprite ) {
192192
193- var index = this . getIndex ( sprite . body . bounds ) ;
194193 var returnObjects = this . objects ;
195-
196- // if we have subnodes ...
197- // if (typeof this.nodes[0] !== 'undefined')
194+
195+ sprite . body . quadTreeIndex = this . getIndex ( sprite . body . bounds ) ;
196+
197+ // Temp store for the node IDs this sprite is in, we can use this for fast elimination later
198+ sprite . body . quadTreeIDs . push ( this . ID ) ;
199+
198200 if ( this . nodes [ 0 ] )
199201 {
200202 // if rect fits into a subnode ..
201- if ( index !== - 1 )
203+ if ( sprite . body . quadTreeIndex !== - 1 )
202204 {
203- returnObjects = returnObjects . concat ( this . nodes [ index ] . retrieve ( sprite ) ) ;
205+ returnObjects = returnObjects . concat ( this . nodes [ sprite . body . quadTreeIndex ] . retrieve ( sprite ) ) ;
204206 }
205207 else
206208 {
207- // if rect does not fit into a subnode, check it against all subnodes
208- for ( var i = 0 , len = this . nodes . length ; i < len ; i ++ )
209- {
210- returnObjects = returnObjects . concat ( this . nodes [ i ] . retrieve ( sprite ) ) ;
211- }
209+ // if rect does not fit into a subnode, check it against all subnodes (unrolled for speed)
210+ returnObjects = returnObjects . concat ( this . nodes [ 0 ] . retrieve ( sprite ) ) ;
211+ returnObjects = returnObjects . concat ( this . nodes [ 1 ] . retrieve ( sprite ) ) ;
212+ returnObjects = returnObjects . concat ( this . nodes [ 2 ] . retrieve ( sprite ) ) ;
213+ returnObjects = returnObjects . concat ( this . nodes [ 3 ] . retrieve ( sprite ) ) ;
212214 }
213215 }
214216
0 commit comments