package vooga.towerdefense.gameeditor.gameloader.xmlloaders; import java.awt.Dimension; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Scanner; import org.w3c.dom.Element; import util.Location; import vooga.towerdefense.util.Pixmap; import util.XMLTool; import vooga.towerdefense.gameeditor.controller.GameEditorController; import vooga.towerdefense.model.GameMap; import vooga.towerdefense.model.Tile; import vooga.towerdefense.model.tiles.factories.TileFactory; import vooga.towerdefense.model.tiles.factories.XMLTileFactory; /** * This class is responsible for constructing GameMap objects * from an xml file describing different game maps. * * An example of this xml file is shown below: * * <map> * <map1> * <image></image> * <dimension> * <width>800</width> * <height>600</height> * </dimension> * <tile_size>50</tile_size> * <grid> * 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 * 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 * 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 * 0 0 0 1 0 0 0 1 0 0 0 1 1 1 0 0 * 0 0 0 1 0 0 0 1 0 0 0 1 0 1 0 0 * 1 1 1 1 0 0 0 1 1 1 1 1 0 1 1 1 * 0 0 0 1 0 0 0 1 0 0 0 1 0 1 0 0 * 0 0 0 1 0 0 0 1 0 0 0 1 1 1 0 0 * 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 * 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 * 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 * 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 * </grid> * </map1> * <map2> * <image></image> * <dimension> * <width>800</width> * <height>600</height> * </dimension> * <tile_size>50</tile_size> * <grid> * 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 * 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 * 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 * 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 * 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 * 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 * 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 * 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 * 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 * 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 * 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 * 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 * </grid> * </map2> * </map> * * This file is read, and a List of GameMap objects can be returned. * * @author Erick Gonzalez */ public class MapXMLLoader { private static final String IMAGE_PATH = "/vooga/towerdefense/images/"; private static final String TILE_FACTORIES_CLASSPATH = "vooga.towerdefense.model.tiles.factories"; // map_loadfile.xml tags private static final String MAP_TAG = "map"; private static final String IMAGE_TAG = "image"; private static final String DIMENSION_TAG = "dimension"; private static final String WIDTH_TAG = "width"; private static final String HEIGHT_TAG = "height"; private static final String TILE_SIZE_TAG = "tile_size"; private static final String GRID_TAG = "grid"; private static final String TILE_TAG = "tileType"; private static final String TILE_ID_TAG = "ID"; private XMLTool myXMLTool; private Map<String, TileFactory> myTileIdMap; /** * * @param xmlTool an XMLTool with an xml file */ public MapXMLLoader(XMLTool xmlTool) { myXMLTool = xmlTool; myTileIdMap = getTileIdMap(); } /** * Loads all the maps described in the xml file. * * @return a list of GameMap objects */ public List<GameMap> loadMaps () { List<GameMap> gameMaps = new ArrayList<GameMap>(); // TODO: mapElement needs to be passed in as a parameter Element mapElement = myXMLTool.getElement(MAP_TAG); List<Element> subElements = myXMLTool.getChildrenList(mapElement); for (Element subElement : subElements) { GameMap map = loadMap(subElement); gameMaps.add(map); } return gameMaps; } private GameMap loadMap (Element mapNameElement) { Map<String, Element> subElements = myXMLTool.getChildrenElementMap(mapNameElement); Pixmap mapImage = loadMapImage(subElements.get(IMAGE_TAG)); Dimension mapDimensions = loadMapDimensions(subElements.get(DIMENSION_TAG)); Dimension tileSize = loadMapTileSize(subElements.get(TILE_SIZE_TAG)); GameMap map = new GameMap(mapImage, mapDimensions, tileSize); createAndSetGrid(subElements.get(GRID_TAG), map); return map; } private Pixmap loadMapImage (Element imageElement) { String imagePath = myXMLTool.getContent(imageElement); return new Pixmap(IMAGE_PATH + imagePath); } private Dimension loadMapDimensions (Element dimensionElement) { Map<String, Element> subElementMap = myXMLTool.getChildrenElementMap(dimensionElement); int width = getMapWidth(subElementMap.get(WIDTH_TAG)); int height = getMapHeight(subElementMap.get(HEIGHT_TAG)); return new Dimension(width, height); } private int getMapWidth (Element widthElement) { return Integer.parseInt(myXMLTool.getContent(widthElement)); } private int getMapHeight (Element heightElement) { return Integer.parseInt(myXMLTool.getContent(heightElement)); } private Dimension loadMapTileSize (Element tileSizeElement) { int tileSize = Integer.parseInt(myXMLTool.getContent(tileSizeElement)); return new Dimension(tileSize, tileSize); } private void createAndSetGrid (Element tilesElement, GameMap map) { Dimension mapDimensions = map.getSize(); Dimension tileDimensions = map.getTileSize(); String gridString = myXMLTool.getContent(tilesElement); Scanner reader = new Scanner(gridString); int horizontalTileCount = (int) (mapDimensions.getWidth() / tileDimensions.getWidth()); int verticalTileCount = (int) (mapDimensions.getHeight() / tileDimensions.getHeight()); Tile[][] grid = new Tile[horizontalTileCount][verticalTileCount]; for (int i = 0; i < grid[0].length; i++) { for (int j = 0; j < grid.length; j++) { int xCenter = (int) (j * tileDimensions.getWidth() + tileDimensions.getWidth() / 2); int yCenter = (int) (i * tileDimensions.getHeight() + tileDimensions.getHeight() / 2); String tileId = reader.next(); Location location = new Location(xCenter, yCenter); grid[j][i] = getTileFactory(tileId).createTile(location, map); } } map.setGrid(grid); } private TileFactory getTileFactory (String tileId) { return myTileIdMap.get(tileId); } @SuppressWarnings("rawtypes") private Map<String, TileFactory> getTileIdMap () { Map<String, TileFactory> tileIdMap = new HashMap<String, TileFactory>(); List<Class> tileFactoryClasses = GameEditorController. getClassesInPackage(TILE_FACTORIES_CLASSPATH); for (Class c : tileFactoryClasses) { Object tileFactory; try { tileFactory = c.newInstance(); Field f = c.getField("ID"); Object id = f.get(tileFactory); tileIdMap.put((String) id, (TileFactory) tileFactory); } catch (InstantiationException e) { // null behavior on purpose, don't initialize tile factory } catch (IllegalAccessException e) { // null behavior on purpose, don't initialize tile factory } catch (NoSuchFieldException e) { // null behavior on purpose, don't initialize tile factory } catch (SecurityException e) { // null behavior on purpose, don't initialize tile factory } } Element parentElement = myXMLTool.getElement(TILE_TAG); if (parentElement != null) { List<Element> tileElements = myXMLTool.getChildrenList(parentElement); for (Element e : tileElements) { String tag = myXMLTool.getTagName(e); tileIdMap .put(tag.substring(2), (TileFactory) new XMLTileFactory(myXMLTool, e, tag)); } } return tileIdMap; } }