The grid-based proximity sensor class by Grant Skinner is implemented and working fine. Caught a bit of a break on that one, though it took some careful study, as Mr. Skinner is a bit stingy on comments in this particular bit of code. It works thusly:
- A proximity manager object is instantiated. This object is described in the external file ProximityManager.as. When instantiated, a grid size is specified - this size value should multiply evenly into the dimensions of the stage for best results.
- The proximity manager keeps track of managed objects in a two dimensional array, effectively creating a sort of virtual grid on the stage. When an object is attached to this proximity manager through its addItem method, its coordinates are mathematically approximated to a single cell on this grid, and a reference to that object is stored in that cell of the array.
- The business end of the proximity manager is its getNeighbours method. The main frame script invokes this method, passing it a reference to (get this) any movie clip in existence on the stage. The manager figures out where the referenced clip would be on its virtual grid, then it builds up a list of all of the managed clips in that cell and all of the neighboring cells. After that, it returns an array full of movie clip references (the neighbors) to whatever called getNeighbours.
We can do other things with this neighbor list once it is received. For example, distance calculations can get somewhat CPU-intensive, especially when you are doing a lot of them (we use the Pythagorean Theorem to determine distance, so we are calculating a lot of square roots). Using Skinner's proximity manager, we can filter out more distant objects using simple, computationally cheap division operations. This saves CPU time for more explicit distance calculations, and ultimately more artwork on the screen.
It should be noted that the grid size specified is pretty important. Let's say you want a 'shark' object to interact whenever it gets within 300 pixels of a 'fish' object. If the grid size is only set to, say, 25, this means that the shark will only really see the fish when it gets inside of 50 pixels. Let me illustrate this a bit better:
Let's say you have three fish swimming around on the stage:
The proximity manager will track references of these objects in a virtual grid, visualized here:
Let's say a shark is added to the stage, so that it looks like this:
Let's say the frame script calls the getNeighbours method of the manager, sending a reference to the shark clip as its parameter. The proximity manager checks all of the surrounding cells, ignoring the rest.
A list of tracked objects in these surrounding cells is built, and sent back as the list of neighbors. In this case, it would return 'fish3' as the only neighbor of 'shark.' If the shark were in the next cell up, the manager would return both 'fish1' and 'fish3' as its neighbors.
Part of the problem, though, is that the cell size is only 40 pixels across. If the shark fell into the lower left corner of one cell, and a fish into the upper right corner of the upper-right neighboring cell, the distance between them would be about 114 pixels. This becomes a problem if I want the shark to react when it is within 200 pixels of a fish; its "sense" range is a square 120 pixels across.
The solution, of course, is to increase the grid size, so that a fish within 200 pixels of the shark will never be outside of the proximity mask. Increasing the grid to this size, though, means that there will be a bit of a dead zone beyond this radius where fish can be returned as neighbors but will technically be over 200 pixels away.
The next step in the solution, then, is to run actual distance calculations on the neighbors returned by the manager, then do some stuff based on whatever passes
that test.
Ultimately, this means that the proximity manager is in place to augment distance calculations, not substitute for them.