/** * Build a navigation mesh based on a tile map * * @param map The map to build the navigation mesh from * @param tileBased True if we'll use the tiles for the mesh initially * rather than quad spacing * @return The newly created navigation mesh */ public NavMesh build(TileBasedMap map, boolean tileBased) { this.tileBased = tileBased; ArrayList spaces = new ArrayList(); if (tileBased) { for (int x=0;x<map.getWidthInTiles();x++) { for (int y=0;y<map.getHeightInTiles();y++) { if (!map.blocked(this, x, y)) { spaces.add(new Space(x,y,1,1)); } } } } else { Space space = new Space(0,0,map.getWidthInTiles(),map.getHeightInTiles()); subsection(map, space, spaces); } while (mergeSpaces(spaces)) {} linkSpaces(spaces); return new NavMesh(spaces); }
/** * Subsection a space into smaller spaces if required to find a non-blocked * area. * * @param map The map being processed * @param space The space being sections * @param spaces The list of spaces that have been created */ private void subsection(TileBasedMap map, Space space, ArrayList spaces) { if (!clear(map, space)) { float width2 = space.getWidth()/2; float height2 = space.getHeight()/2; if ((width2 < smallestSpace) && (height2 < smallestSpace)) { return; } subsection(map, new Space(space.getX(), space.getY(), width2, height2), spaces); subsection(map, new Space(space.getX(), space.getY()+height2, width2, height2), spaces); subsection(map, new Space(space.getX()+width2, space.getY(), width2, height2), spaces); subsection(map, new Space(space.getX()+width2, space.getY()+height2, width2, height2), spaces); } else { spaces.add(space); } }
/** * @see AStarHeuristic#getCost(TileBasedMap, Mover, int, int, int, int) */ public float getCost(TileBasedMap map, Mover mover, int x, int y, int tx, int ty) { float dx = tx - x; float dy = ty - y; return ((dx*dx)+(dy*dy)); }
/** * @see AStarHeuristic#getCost(TileBasedMap, Mover, int, int, int, int) */ public float getCost(TileBasedMap map, Mover mover, int x, int y, int tx, int ty) { float dx = tx - x; float dy = ty - y; float result = (float) (Math.sqrt((dx*dx)+(dy*dy))); return result; }
/** * Check if a particular space is clear of blockages * * @param map The map the spaces are being built from * @param space The space to check * @return True if there are no blockages in the space */ public boolean clear(TileBasedMap map, Space space) { if (tileBased) { return true; } float x = 0; boolean donex = false; while (x < space.getWidth()) { float y = 0; boolean doney = false; while (y < space.getHeight()) { sx = (int) (space.getX()+x); sy = (int) (space.getY()+y); if (map.blocked(this, sx, sy)) { return false; } y += 0.1f; if ((y > space.getHeight()) && (!doney)) { y = space.getHeight(); doney = true; } } x += 0.1f; if ((x > space.getWidth()) && (!donex)) { x = space.getWidth(); donex = true; } } return true; }
@Override public float getCost(TileBasedMap ctx, Mover mover, int x, int y, int goalX, int goalY) { return Math.max(Math.abs(x - goalX), Math.abs(y - goalY)); /* float diagonal = Math.min(Math.abs(x - goalX), Math.abs(y - goalY)); float straight = (Math.abs(x - goalX) + Math.abs(y - goalY)); float h = (DIAGONAL_COST * diagonal) + (ADJACENT_COST * (straight - (2f * diagonal))); return h;*/ }
/** * Create a new npc controller. * * @param gameController * The GameController to be used. * @param model * The model that this controller should control. * @param map * The tile based map to be used. */ AbstractNpcController(GameController gameController, AbstractNpcModel model, TileBasedMap map) { super(gameController); this.setPathFinder(new AStarPathFinder(map, 500, true)); this.setModel(model); this.setView(new CharacterView(model)); this.setDefaultTiles(model.getMinTileX(), model.getMaxTileX(), model.getMinTileY(), model.getMaxTileY()); this.pauseTime = 0; }