Hey folks, it's been a while. I've been busy helping to roll out a whole new architecture at work, so I haven't had a lot of time to have fun here.
Regardless, after the last entry, I wanted to create a TileMap object that wasn't really tied to the view. I wanted to be able to test that the visibility function was working correctly wherever the TileMap's location was, and I wanted to be able to test this without creating a JFrame, and visually inspecting it.
So, I started with a unit test, and the purpose of this unit test was to test the update method on my TileMap, to make sure it's setting the tiles visibility correctly.
My unit test started as such:
public class TileMapTest { public TileMapTest(){ } @Test public void testUpdate() { TileMap tileMap = new TileMap(); tileMap.setSize(640, 480); tileMap.setRows(10); tileMap.setColumns(30); tileMap.setLocation(50, 50); List<Tile> tiles = tileMap.getTiles(); Assert.assertNotNull(tiles != null); } }
I started basic, I just wanted to ensure that these methods exist on my TileMap. The size property is the spacial width and height the TileMap occupies. Rows and Columns represent how many tiles (down, and across respectively) are inside the TileMap, and Location is the spacial location (pixel point) inside the map. Lastly, I wanted to be able to get the list of tiles inside the TileMap, and I wanted to make sure that this list exists even if I haven't added any tiles to the map.
Next, I needed some way to determine the size of each Tile, and I wanted all the tiles in the map to be of the same size (so it'll be easier to find their locations in the future). This lead me to the idea of a TileSet which would contain information about what tiles were used in the map. This may include their sizes, perhaps a location to find their images on the file system, etc..
However, I didn't like the name TileSet because I didn't want the TileSet to contain the actual tiles, just the information about them. It's more of a Tile meta-data class than a collection, so I changed the name to TileKit. This way, in the future (when I get around to it), Tile's can consist of a common lanuage about their location and perhaps an ID of the type of tile they are, while the TileKit is used to "display" them. Essentially this lets me use one collection of Tiles, and have different TileKit's applied to them. Aka. one map, different looks.
That being what I decided, I updated my unit test to reflect these requirements.
public class TileMapTest { @Test public void testUpdate() { // tile map creation from above. // TileKit tilePack = new TileKit(); tilePack.setTileHeight(75); tilePack.setTileWidth(50); for (int row = 0; row < tileMap.getRows(); row++) { for (int col = 0; col < tileMap.getColumns(); col++) { Tile tile = new Tile(); tile.setLocationX(col * tilePack.getTileWidth()); tile.setLocationY(row * tilePack.getTileHeight()); tiles.add(tile); } } } }
As you can see, I simply created a TilePack with a tile width and height. These values were used to create my Tiles and set their locations. Ideally, this type of thing would be done in some sort of factory or utility class which takes the TilePack and Collection of Tiles, and returns a TileMap, but the need hasn't actually arisen yet so I'll wait until it does.
Now that I have my TileMap, TileKit, and Tile defined, and I have my Tiles set in my TileMap, it's time to update my map and make sure the right tiles are visible. The update method uses the TileMap's location, width, and height to determine if a Tile is visible or not.
For my test, a tile is visible when it's location is inside the spacial area of the TileMap. This means, it's 'x' position must be greater than the TileMap's location, and less than the TileMap's location added to it's width. Likewise for the 'y' position and the TileMap's height.
I updated my unit test to loop through each Tile and check it's location against the TileMap's location, width, and height.
public class TileMapTest { @Test public void testUpdate() { // tile map creation from above. // // tile kit and tiles creation from above. // tileMap.update(); for (Tile tile : tiles) { int x = tile.getLocationX(); int y = tile.getLocationY(); if ((x > 50) && (x < (50 + 640)) && (y > 50) && (y < (50 + 480))) { Assert.assertTrue(tile.isVisible()); } else { Assert.assertFalse(tile.isVisible()); } } } }
This visibility algorithm isn't great because you can technically have partially visible tiles. This is easily fixed by also checking to see if a Tile's location plus it's width/height is within the TileMap's spacial area, but this will do for now.
Thanks,
Eric