Representing a 2D map
Maps are another crucial part of having a decently complex game. For our purposes, we're going to be representing 2D maps that support different layers in order to fake 3D depth:
class Map : public FileLoader{ public: ... Tile* GetTile(unsigned int l_x, unsigned int l_y, unsigned int l_layer); TileInfo* GetDefaultTile(); TileSet* GetTileSet(); unsigned int GetTileSize()const; sf::Vector2u GetMapSize()const; sf::Vector2f GetPlayerStart()const; int GetPlayerId()const; void PurgeMap(); void AddLoadee(MapLoadee* l_loadee); void RemoveLoadee(MapLoadee* l_loadee); void Update(float l_dT); void Draw(unsigned int l_layer); protected: bool ProcessLine(std::stringstream& l_stream); ... };
As you can see, this class is actually inheriting from the FileLoader
, which we covered earlier. It also supports something that's referred to as MapLoadee*
, which are simply classes that will store certain data inside map files, and need to be notified when such data is encountered during the loading process. It's simply an interface that they have to implement:
class MapLoadee { public: virtual void ReadMapLine(const std::string& l_type, std::stringstream& l_stream) = 0; };
The map files themselves are fairly straightforward:
SIZE 64 64 DEFAULT_FRICTION 1.0 1.0 |ENTITY|Name|x|y|elevation| ENTITY Player 715 360 1 ENTITY Skeleton 256.0 768.0 1 |TILE|ID|x|y|layer|solid| TILE 0 0 0 0 0 TILE 0 0 1 0 0 TILE 0 0 2 0 0 ...
A good candidate for a MapLoadee
here would be a class that handles entities being spawned. The two entity lines would be directly handled by it, which creates a nice level of separation between codes that shouldn't really overlap.