/** Computes a list of the valid locations in this cluster. */ public static List<SceneLocation> getClusterLocs(Cluster cluster) { List<SceneLocation> list = Lists.newArrayList(); // convert our tile coordinates into a cartesian coordinate system // with units equal to one fine coordinate in size int fx = cluster.x * _metrics.finegran + 1, fy = cluster.y * _metrics.finegran + 1; int fwid = cluster.width * _metrics.finegran - 2, fhei = cluster.height * _metrics.finegran - 2; int cx = fx + fwid / 2, cy = fy + fhei / 2; // if it's a 1x1 cluster, return one location in the center of the // cluster if (cluster.width == 1) { StageLocation loc = new StageLocation( MisoUtil.toFull(cluster.x, 2), MisoUtil.toFull(cluster.y, 2), (byte) DirectionCodes.SOUTHWEST); list.add(new SceneLocation(loc, 0)); return list; } double radius = (double) fwid / 2; int clidx = cluster.width - 2; if (clidx >= CLUSTER_METRICS.length / 2 || clidx < 0) { log.warning("Requested locs from invalid cluster " + cluster + ".", new Exception()); return list; } for (double angle = CLUSTER_METRICS[clidx * 2]; angle < Math.PI * 2; angle += CLUSTER_METRICS[clidx * 2 + 1]) { int sx = cx + (int) Math.round(Math.cos(angle) * radius); int sy = cy + (int) Math.round(Math.sin(angle) * radius); // obtain the orientation facing toward the center int orient = 2 * (int) (Math.round(angle / (Math.PI / 4)) % 8); orient = DirectionUtil.rotateCW(DirectionCodes.SOUTH, orient); orient = DirectionUtil.getOpposite(orient); // convert them back to full coordinates for the location int tx = MathUtil.floorDiv(sx, _metrics.finegran); sx = MisoUtil.toFull(tx, sx - (tx * _metrics.finegran)); int ty = MathUtil.floorDiv(sy, _metrics.finegran); sy = MisoUtil.toFull(ty, sy - (ty * _metrics.finegran)); StageLocation loc = new StageLocation(sx, sy, (byte) orient); list.add(new SceneLocation(loc, 0)); } return list; }
/** * Locates a spot to stand near the supplied rectangular footprint. First a spot will be sought in * a tile immediately next to the footprint, then one tile removed, then two, up to the maximum * distance specified by <code>dist</code>. * * @param foot the tile coordinate footprint around which we are attempting to stand. * @param dist the maximum number of tiles away from the footprint to search before giving up. * @param pred a predicate that will be used to determine whether a particular spot can be stood * upon (we're hijacking the meaning of "traverse" in this case, but the interface is * otherwise so nice). * @param traverser the object that will be passed to the traversal predicate. * @param nearto a point (in tile coordinates) which will be used to select from among the valid * standing spots, the one nearest to the supplied point will be returned. * @param orient if not {@link DirectionCodes#NONE} this orientation will be used to override the * "natural" orientation of the spot which is facing toward the footprint. * @return the closest spot to the */ public static StageLocation findStandingSpot( Rectangle foot, int dist, AStarPathUtil.TraversalPred pred, Object traverser, final Point nearto, int orient) { // generate a list of the tile coordinates of all squares around // this footprint SortableArrayList<StageLocation> spots = new SortableArrayList<StageLocation>(); for (int dd = 1; dd <= dist; dd++) { int yy1 = foot.y - dd, yy2 = foot.y + foot.height + dd - 1; int xx1 = foot.x - dd, xx2 = foot.x + foot.width + dd - 1; // get the corners spots.add(new StageLocation(xx1, yy1, (byte) DirectionCodes.SOUTHWEST)); spots.add(new StageLocation(xx1, yy2, (byte) DirectionCodes.SOUTHEAST)); spots.add(new StageLocation(xx2, yy1, (byte) DirectionCodes.NORTHWEST)); spots.add(new StageLocation(xx2, yy2, (byte) DirectionCodes.NORTHEAST)); // then the sides for (int xx = xx1 + 1; xx < xx2; xx++) { spots.add(new StageLocation(xx, yy1, (byte) DirectionCodes.WEST)); spots.add(new StageLocation(xx, yy2, (byte) DirectionCodes.EAST)); } for (int yy = yy1 + 1; yy < yy2; yy++) { spots.add(new StageLocation(xx1, yy, (byte) DirectionCodes.SOUTH)); spots.add(new StageLocation(xx2, yy, (byte) DirectionCodes.NORTH)); } // sort them in order of closeness to the players current // coordinate spots.sort( new Comparator<StageLocation>() { public int compare(StageLocation o1, StageLocation o2) { return dist(o1) - dist(o2); } private final int dist(StageLocation l) { return Math.round(100 * MathUtil.distance(l.x, l.y, nearto.x, nearto.y)); } }); // return the first spot that can be "traversed" which we're // taking to mean "stood upon" for (int ii = 0, ll = spots.size(); ii < ll; ii++) { StageLocation loc = spots.get(ii); if (pred.canTraverse(traverser, loc.x, loc.y)) { // convert to full coordinates loc.x = MisoUtil.toFull(loc.x, 2); loc.y = MisoUtil.toFull(loc.y, 2); // see if we need to override the orientation if (DirectionCodes.NONE != orient) { loc.orient = (byte) orient; } return loc; } } // clear this list and try one further out spots.clear(); } return null; }
/** Converts Cartesian coordinates back to full coordinates. */ public static void coordsToLocation(int cx, int cy, Point loc) { loc.x = MisoUtil.toFull(cx / _metrics.finegran, cx % _metrics.finegran); loc.y = MisoUtil.toFull(cy / _metrics.finegran, cy % _metrics.finegran); }