tilegrid

Started by
1 comment, last by jpetrie 15 years, 3 months ago
I have found I need to have a large 2D array with images and I cant get around this .Each tile has a number and I get the image depending on what tilenumber appears in a gridmap of numbers to load I can either 1)have a public 2D array for the entire tileMap of the screen or 2)make the 2D array private and pass it around to all classes needed. 3)or have a 2D public array of just numbers and just get the images needed from public functions . Is option 2,3 the most memory efficient and option 1 a bad idea?
Advertisement
I would create a map object with a public method to query what tile is at a particular location.

That way, you can change your implementation without affecting your game code.

E.g.
#include <string>#include <vector>class MapTile{    // Define your map tile here};class GameMap{public:    // Get a map tile from a specific location on the map    MapTile* getTileAt(int const x, int const y);    int loadMap( std::string const mapName );private:    class mapRow    {        std::vector<MapTile> m_Tiles;    };    std::vector<mapRow> m_rows;};
Quote:
I have found I need to have a large 2D array with images and I cant get around this

You can always replace a 2D array of width and height by a 1D array of width * height elements, and use simple indexing math (x + width * y) to access the element at (x,y). This is generally the most efficient storage mechanism for 2D data, especially if the width and height of the data are determined at runtime (the nature of C++'s 'multidimensional array' support means that runtime-sized n-D arrays require allocation of each dimension in a loop, which fragments the array storage rather than leaving it contiguous). In the case of compile-time determined sizes of pure arrays, it's exactly as efficient.

Quote:
I can either
1)have a public 2D array for the entire tileMap of the screen
or
2)make the 2D array private and pass it around to all classes needed.
3)or have a 2D public array of just numbers and just get the images needed from public functions .

Is option 2,3 the most memory efficient and option 1 a bad idea?

All of those options are sub-par compared to OldProgie2's suggestion of creating an object that represents the tile map, with accessor methods allowing appropriate access to the map as if if were a 2D grid of data, while allowing you to choose a more efficient storage representation, such as a 1D array. This also allows you to imbue the object with higher-level semantics, making it a richer, more pleasant thing to work with in client code.

OldProgie2's example has some issues, but the interface he provides for the map object is reasonably sane, so I will use this as an example to further illustrate the point we both raised about improving the implementation without impacting other code.

Let's pretend you wrote your entire game using OldProgie2's map class. Now, the problem with his implementation is that it is modelled as a collection of rows -- essentially a vector-of-vectors, which is not a grid (neccessarily), but rather a jagged array. That is, all rows are not necessarily the same size. This is semantically invalid for a tilemap, typically. Also because of this, and because of the way std::vector is implemented, it has the additional performance problem of having noncontiguous tile storage. This means that all the tiles are not located next to eachother in memory, which is a minor efficiency concern (all elements in a given row are contiguous, in his example, but not every tile in every row).

Using the 1D storage mechanism I mentioned above, we can replace the entire "private" section of his class with this:
private:  int m_Width;  std::vector<MapTile> m_Tiles;

and then we can modify the implementation of getTileAt() to become:
MapTile* GameMap::getTileAt( int const x, int const y ) {  return &m_Tiles[x + m_Width * y];}

Please note that we've added a "width" member variable, which we'd need to set when the map is loaded in loadMap. I won't provide an example since that gets into how the map is serialized on disk, which could be done any of a hundred ways.

Thus we now have a more efficient storage mechanism without having to change any of the code that uses the map -- all of your original options, jagguy2, would require you to rewrite every piece of code that ever touched that 2D array directly. So this method is vastly more efficient in terms of development time.

Finally, there are a few additional potential problems with OldProgie2's interface to the map, depending on how you plan to manipulate the map and the other member functions one might add to it. Can you spot them?

This topic is closed to new replies.

Advertisement