Why would this array be global? Every array can easily be made non-global by putting it in a .cpp file and just offer a global "getTilePrototype(id)" function. Or a static "get(id)" function of TilePrototype. The rule of "avoid globals" doesn't mean "avoid global functions" (in fact, you should avoid the opposite.. stuffing functions into classes when there is no reason for it).
However, it seems that even "hidden globals" can be bad too:
Hidden Globals -- hidden globals have a well-defined access scope, and would include, for example, private 'static' variables in classes and 'static' variables in '.c' files and variables in anonymous namespaces in C++. This solution cages and localizes globals rather than tames them - you'll still get bitten when it comes to concurrency and modularization and testing/confinement, but at least all such problems will be localized and easy to repair, and there won't be linking problems.
So, what to do? Or is this a case where a global may really be the best solution? Note that it mentions as one of the biggest, if not the biggest problem with globals is:
Non-locality seems much much more convincing than any of concurrency, namespace, and memory allocation. However, the non-locality issue is much bigger than it seems. I'm thinking of situations when you come back to the code 2 weeks later, look at String important = global.getSomeImportantInfo(), and have to figure out why 'important' is getting the wrong value. Sure, non-locality describes it, but if Bob (above) asks "Why?" and Alice replies "Non-locality", I don't think Bob would learn the lesson.
So how to avoid this? Or is it necessary in this case -- really necessary? I.e. are these pages to be taken as inflexible dogma, or to be taken instead as more stuff along the lines of "don't just use this thing [globals, in this case] willy-nilly"?
And what do you mean by "stuff the data into the prototype functions"?
Do you mean something like this?:
I mean that the prototype functions take the tiles unique data as parameter. In fact, forget that and just pass a pointer to the actual tile, since the function might have to modify the tile (activating a door will obviously have to change its state).
You mean have member functions of TilePrototype that take MapCells as argument? But doesn't that set up kind of a circular dependency between the two? Isn't that bad? Or what? What did you have in mind for the structure of the actual classes/data structures/etc. involved ("outline" code like I posted would be best)?
And I just noticed a new problem. Consider the "onMove" event. There may be certain kinds of things that should occur on a move to very specific tiles, e.g. one particular tile on a map, not one kind of tile. This means that "onMove" needs to be associated with individual map elements, no? Though I suppose one could then include in "MapCell" an onMove() function that mirrors that in TilePrototype (and probably have onXXXX() functions to mirror all events that need to go to TilePrototype and call the functions in the private TilePrototype member, but is this mirroring bad? If so, how to avoid it?) and include a functor that supplies an auxiliary move function, e.g. something like include a data member "AuxMoveFuncObject auxMoveFunc" in MapCell, which can be configured on a per-cell basis, and the onMove() function in MapCell wraps the calls to both. Is this good? Or what?