A few years ago, I released an AS2 version of ProximityManager class, which allows you to efficiently track the proximity of large numbers of sprites. You can read a full description of the approach and uses here.
In the last month a couple of people have left comments indicating that they were having difficulty porting it to AS3. This prompted me to port it and do some significant optimizations. The new class runs a lot faster than the original, and is worth taking a quick look at in comparison with the AS2 version even if you don't use it in a project.
Optimizations:
- removed two-dimensional arrays (which are very inefficient, especially in AS3) in favor of using a single array using an aggregate x/y index. The aggregate index is assembled with bit operators to make it even more efficient.
- added a simple caching mechanism, so that subsequent calls to getNeighbor for the same grid position do not need to recalculate the results
- used a Dictionary instance to hold managed items, which makes it much more efficient to remove objects on the fly.
- took full advantage of types and casting
- other minor tweaks
I thought I would recreate the same demo as in my original post to see how it performed. It has five times as many sprites (600 vs 120), and ten times as many connections (~2800 vs ~280), despite the main bottleneck in this demo being the graphics performance. I benchmarked it without graphics, and it seems handle a couple thousand sprites quite easily.
You can grab the source code for the demo and the ProximityManager class here.

Comments (20)
The second link isn't working. misspelled href!
Posted by: Tim at January 4, 2008 02:54 PMURL:
Very cool though
Posted by: Tim at January 4, 2008 02:58 PMURL:
Fixed. Thanks for the heads up Tim!
Posted by: Grant Skinner at January 4, 2008 03:08 PMURL: http://gskinner.com/blog/
Great work Grant. I just ported over your AS2 version to AS3 only a couple days ago. I'm glad to see the update and that this new class is more optimized than the previous version.
Thanks again for the release!
Posted by: Seth at January 4, 2008 08:38 PMURL:
[quote]Fixed. Thanks for the heads up Tim![/quote]
um... not quite!
Posted by: dAN at January 5, 2008 02:04 AMURL:
You absolute legend! I've been waiting for an upgrade to this class for ages. This class is going to be so useful! Thanks!
Posted by: Vyper at January 5, 2008 05:30 AMURL: http://www.fatal-exception.co.uk
Thank you! Thank you! Thank you!
-t.
Posted by: Timbot at January 5, 2008 08:54 AMURL:
dAN / Tim - fixed for sure this time. Not sure why Moveable Type didn't publish the change the first time. *shrug*
All - glad people are finding this useful. I'd love to see what it gets used for. Cheers.
Posted by: Grant Skinner at January 5, 2008 02:51 PMURL: http://gskinner.com/blog/
I was looking for something like that. Thanks.
Posted by: Simon at January 24, 2008 05:05 PMURL:
It would be nice to see an example that combines this and hittesting. For example, when in proximity, hittest between neighbors to see if they're touching (for odd shapes sprites/movieclips). I tried something like:
if (neighbor.y > sprite.y) {
if (sprite.hitTestPoint(neighbor.x, neighbor.y, true)){ }
}
But this didn't seem to work correctly.
Posted by: Seth at February 1, 2008 12:37 PMURL: http://ssandler.wordpress.com
Great job. In the sample you could add some alpha channel when the sprites are farer away and the alpha gets smaller when they are closer. This would give a nice effect. And gravity or springing between the sprites would be great too. I think it is calld "i don't know more who's" garden
Posted by: Pedro at March 5, 2008 07:51 AMURL:
If this is as useful as it appears then: THANK YOU VERY MUCH :D
I was just grimacing at the idea of tracking collisions for all these items but convinced myself it was worth looking for ideas online. I don't usually use other peoples' code outright, fear of not knowing what's going on I suppose, but I think this warrants it.
If you're ever in Sheffield, UK and feel thirsty, give me a shout :)
Posted by: Martin Lyne at August 10, 2008 03:56 PMURL:
Hi Grant, and congratulatiion for your whole work wish is a real source of knowledge for me !
I'm currently workin on a flocking (like birds) manager for 3D as3 renderer (away3D, papervision). exemple:
http://www;agence-anonyme.com/lab/treeflocking.html
And the proximity manager can be a great help when you have to deal with 500 object3D interactions + the whole renderer pipeline...
If I understand this method,in order to create a 3D proximity manager, I would only have to cast mc as Object3D instead of DisplayObject and set a z parameter in the array.
Am I wrong ???
Could I do this that way by changin this only line ??I don't see other way...
var index:uint = ((mc.x+off)/gridSize)
thanks for the help !
Posted by: Ben at January 9, 2009 08:37 AMURL:
AAARRGHHH!
Posted by: Ben at January 9, 2009 08:41 AMMy last comment had a bug when published,
it deleted most of my code...
well, it was about adding a z parameter the same way as the y in the line begining with var index:uint=mc.x+off)/gridSize)....
thanks.
URL:
I fixed the ProximityManager 3D for away3D, and I'm gonna make it for Papervision.
Posted by: Ben at January 10, 2009 09:15 AMI just would like to know if I could release it and share it with the community ????
Waiting for your agreement...
thanks.
URL:
please release the PV3D flock manager. I don't see why you can't release it, his code has been released to the public so as long as you post in your code a comment showing where the original code was taken from I don't see how its any different? Your demo is cool. thx.
Posted by: zurie at March 25, 2009 03:25 PMURL:
In .fla file you have:
if (neighbor.y > sprite.y)
{ g.moveTo(sprite.x,sprite.y); g.lineTo(neighbor.x,neighbor.y);
}
but, it can be avoided (and make further optimization) if in getNeighbors() avoid querying for Array for cells with smaller indexes.
In other hand, this would make ProximityManager non-universal.
Posted by: krdr at May 14, 2009 05:00 AMURL:
I just found one more optimization. Effectively, you connect sprites that can be 2,8*grid size distant from target sprite. By checking distance, number of connections will be reduced, and drawing will be faster.
Posted by: krdr at May 14, 2009 06:08 AMURL:
very nice. can i ask what your reason for scaling down the objects?
sprite.scaleX = sprite.scaleY = 0.5 + l * 0.05;
Posted by: Aaron at November 18, 2009 08:31 AMURL:
if you want to modify it to use the mouse position all you need to do is alter the getNeighbours function to pass a dynamic variable instead of display object and then pass a Point object: new Point(mouseX, mouseY);
Posted by: Dan at January 27, 2010 10:31 PMURL: http://visualjazz.com.au