diff --git a/projects/atlanti/src/java/com/samskivert/atlanti/TileGeometryTest.java b/projects/atlanti/src/java/com/samskivert/atlanti/TileGeometryTest.java new file mode 100644 index 00000000..db2a7e1c --- /dev/null +++ b/projects/atlanti/src/java/com/samskivert/atlanti/TileGeometryTest.java @@ -0,0 +1,132 @@ +// +// $Id: TileGeometryTest.java,v 1.1 2001/10/15 19:55:15 mdb Exp $ + +package com.threerings.venison; + +import java.awt.*; +import javax.swing.*; +import java.util.ArrayList; + +import com.samskivert.swing.util.SwingUtil; +import com.samskivert.util.IntTuple; + +/** + * A simple class for testing the tile geometry specifications by drawing + * them. + */ +public class TileGeometryTest + extends JPanel implements TileCodes +{ + public TileGeometryTest () + { + ArrayList polys = new ArrayList(); + ArrayList colors = new ArrayList(); + + // create polygons from the various tile features + for (int i = 1; i < TileUtil.TILE_FEATURES.length; i++) { + // convert tile index into x and y coordinates (in tile + // feature coords which will be converted to screen coords) + int x = 4 * (i % 5), y = 4 * (i / 5); + + // the first feature is the background color + Object[] features = (Object[])TileUtil.TILE_FEATURES[i]; + IntTuple base = (IntTuple)features[0]; + + // add a polygon containing the whole tile colored with the + // background color + colors.add(COLOR_MAP[base.left]); + Polygon poly = new Polygon(); + poly.addPoint(((x + 0) * TILE_WIDTH) / 4, + ((y + 0) * TILE_HEIGHT) / 4); + poly.addPoint(((x + 4) * TILE_WIDTH) / 4, + ((y + 0) * TILE_HEIGHT) / 4); + poly.addPoint(((x + 4) * TILE_WIDTH) / 4, + ((y + 4) * TILE_HEIGHT) / 4); + poly.addPoint(((x + 0) * TILE_WIDTH) / 4, + ((y + 4) * TILE_HEIGHT) / 4); + polys.add(poly); + + // the remainder are tuple/coordinate pairs + for (int f = 1; f < features.length; f += 2) { + IntTuple type = (IntTuple)features[f]; + int[] coords = (int[])features[f+1]; + + // create a color for this polygon + colors.add(COLOR_MAP[type.left]); + + // if this is a road segment, we need to create a special + // polygon + if (type.left == ROAD) { + poly = TileUtil.roadSegmentToPolygon( + coords[0], coords[1], coords[2], coords[3]); + // translate the polygon into our coordinate space + poly.translate((x * TILE_WIDTH)/4, (y * TILE_HEIGHT)/4); + + } else { + // otherwise create the polygon directly from the coords + poly = new Polygon(); + for (int c = 0; c < coords.length; c += 2) { + // translate and scale the coords accordingly + int fx = ((x + coords[c]) * TILE_WIDTH) / 4; + int fy = ((y + coords[c+1]) * TILE_HEIGHT) / 4; + poly.addPoint(fx, fy); + } + } + + polys.add(poly); + } + } + + // create our arrays + _polys = new Polygon[polys.size()]; + polys.toArray(_polys); + _colors = new Color[colors.size()]; + colors.toArray(_colors); + } + + public void paintComponent (Graphics g) + { + super.paintComponent(g); + + // paint our polygons + for (int i = 0; i < _polys.length; i++) { + g.setColor(_colors[i]); + g.fillPolygon(_polys[i]); + } + + // outline the tiles + g.setColor(Color.black); + for (int i = 0; i < 20; i++) { + int x = i % 5, y = i / 5; + g.drawRect(TILE_WIDTH * x, TILE_HEIGHT * y, + TILE_WIDTH, TILE_HEIGHT); + } + } + + public Dimension getPreferredSize () + { + // we want to be five tiles wide by four tiles tall + return new Dimension(TILE_WIDTH * 5, TILE_HEIGHT * 4); + } + + public static void main (String[] args) + { + JFrame frame = new JFrame("Tile geometry test"); + // quit if we're closed + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + TileGeometryTest panel = new TileGeometryTest(); + frame.getContentPane().add(panel); + frame.pack(); + SwingUtil.centerWindow(frame); + frame.show(); + } + + protected Polygon[] _polys; + protected Color[] _colors; + + protected static Color[] COLOR_MAP = { + Color.red, // CITY + Color.green, // GRASS + Color.black // ROAD + }; +} diff --git a/projects/atlanti/src/java/com/samskivert/atlanti/util/TileUtil.java b/projects/atlanti/src/java/com/samskivert/atlanti/util/TileUtil.java index 923da7e3..20e3c23b 100644 --- a/projects/atlanti/src/java/com/samskivert/atlanti/util/TileUtil.java +++ b/projects/atlanti/src/java/com/samskivert/atlanti/util/TileUtil.java @@ -1,12 +1,16 @@ // -// $Id: TileUtil.java,v 1.2 2001/10/11 04:00:49 mdb Exp $ +// $Id: TileUtil.java,v 1.3 2001/10/15 19:55:15 mdb Exp $ package com.threerings.venison; +import java.awt.Polygon; + import java.util.ArrayList; import java.util.List; import java.util.Iterator; +import com.samskivert.util.IntTuple; + /** * Utility functions relating to the Venison tiles. */ @@ -176,6 +180,65 @@ public class TileUtil implements TileCodes return TILE_EDGES[4*tileType + edge]; } + /** + * Massages a road segment (specified in tile feature coordinates) + * into a polygon (in screen coordinates) that can be used to render + * or hit test the road. The coordinates must obey the following + * constraints: (x1 < x2 and y1 == y2) or (x1 == x2 and y1 < y2) or + * (x1 < x2 and y1 > y2). + * + * @return a polygon representing the road segment (with origin at 0, + * 0). + */ + public static Polygon roadSegmentToPolygon ( + int x1, int y1, int x2, int y2) + { + // first convert the coordinates into screen coordinates + x1 = (x1 * TILE_WIDTH) / 4; + y1 = (y1 * TILE_HEIGHT) / 4; + x2 = (x2 * TILE_WIDTH) / 4; + y2 = (y2 * TILE_HEIGHT) / 4; + + Polygon poly = new Polygon(); + int dx = 4, dy = 4; + + // figure out what sort of line segment it is + if (x1 == x2) { // vertical + // make adjustments to ensure that we stay inside the tile + // bounds + if (y1 == 0) { + y1 += dy; + } else if (y2 == TILE_HEIGHT) { + y2 -= dy; + } + poly.addPoint(x1 - dx, y1 - dy); + poly.addPoint(x1 + dx, y1 - dy); + poly.addPoint(x2 + dx, y2 + dy); + poly.addPoint(x2 - dx, y2 + dy); + + } else if (y1 == y2) { // horizontal + // make adjustments to ensure that we stay inside the tile + // bounds + if (x1 == 0) { + x1 += dx; + } else if (x2 == TILE_WIDTH) { + x2 -= dx; + } + poly.addPoint(x1 - dx, y1 - dy); + poly.addPoint(x1 - dx, y1 + dy); + poly.addPoint(x2 + dx, y2 + dy); + poly.addPoint(x2 + dx, y2 - dy); + + } else { // diagonal + poly.addPoint(x1 - dx, y1); + poly.addPoint(x1 + dx, y1); + poly.addPoint(x2, y2 + dy); + poly.addPoint(x2, y2 - dy); + } + + return poly; + } + /** Used to generate our standard tile set. */ protected static void addTiles (int count, List list, VenisonTile tile) { @@ -254,4 +317,128 @@ public class TileUtil implements TileCodes ROAD, GRASS, ROAD, GRASS, // STRAIGHT_ROAD GRASS, GRASS, ROAD, ROAD, // CURVED_ROAD }; + + /** A table describing the geometry of the features (cities, roads, + * etc.) of each tile. */ + protected static final Object[] TILE_FEATURES = new Object[] { + new Object[0], // null tile + + new Object[] { new IntTuple(CITY, 0), }, // CITY_FOUR + + new Object[] { new IntTuple(CITY, 0), // CITY_THREE + new IntTuple(GRASS, 0), + new int[] { 0, 4, 1, 3, 3, 3, 4, 4 }}, + + new Object[] { new IntTuple(CITY, 0), // CITY_THREE_ROAD + new IntTuple(GRASS, 0), + new int[] { 0, 4, 1, 3, 2, 3, 2, 4 }, + new IntTuple(GRASS, 1), + new int[] { 2, 4, 2, 3, 3, 3, 4, 4 }, + new IntTuple(ROAD, 0), + new int[] { 2, 3, 2, 4 }}, + + new Object[] { new IntTuple(CITY, 0), // CITY_TWO + new IntTuple(GRASS, 0), + new int[] { 0, 4, 4, 0, 4, 4 }}, + + new Object[] { new IntTuple(CITY, 0), // CITY_TWO_ROAD + new IntTuple(GRASS, 0), + new int[] { 0, 4, 4, 0, 4, 2, 2, 4 }, + new IntTuple(ROAD, 0), + new int[] { 2, 4, 4, 2 }, + new IntTuple(GRASS, 0), + new int[] { 2, 4, 4, 2, 4, 4 }}, + + new Object[] { new IntTuple(CITY, 0), // CITY_TWO_ACROSS + new IntTuple(GRASS, 0), + new int[] { 0, 4, 1, 3, 3, 3, 4, 4 }, + new IntTuple(GRASS, 1), + new int[] { 0, 0, 1, 1, 3, 1, 4, 0 }}, + + new Object[] { new IntTuple(GRASS, 0), // DISCONNECTED_CITY_TWO + new IntTuple(CITY, 0), + new int[] { 0, 0, 1, 1, 3, 1, 4, 0 }, + new IntTuple(CITY, 1), + new int[] { 4, 0, 3, 1, 3, 3, 4, 4 }}, + + new Object[] { new IntTuple(GRASS, 0), // DISCONNECTED_CITY_TWO_ACROSS + new IntTuple(CITY, 0), + new int[] { 0, 0, 1, 1, 1, 3, 0, 4 }, + new IntTuple(CITY, 1), + new int[] { 4, 0, 3, 1, 3, 3, 4, 4 }}, + + new Object[] { new IntTuple(GRASS, 0), // CITY_ONE + new IntTuple(CITY, 0), + new int[] { 0, 0, 1, 1, 3, 1, 4, 0 }}, + + new Object[] { new IntTuple(GRASS, 0), // CITY_ONE_ROAD_RIGHT + new IntTuple(CITY, 0), + new int[] { 0, 0, 1, 1, 3, 1, 4, 0 }, + new IntTuple(ROAD, 0), + new int[] { 2, 2, 2, 4 }, + new IntTuple(ROAD, 0), + new int[] { 2, 2, 4, 2 }}, + + new Object[] { new IntTuple(GRASS, 0), // CITY_ONE_ROAD_LEFT + new IntTuple(CITY, 0), + new int[] { 0, 0, 1, 1, 3, 1, 4, 0 }, + new IntTuple(ROAD, 0), + new int[] { 2, 2, 2, 4 }, + new IntTuple(ROAD, 0), + new int[] { 0, 2, 2, 2 }}, + + new Object[] { new IntTuple(GRASS, 0), // CITY_ONE_ROAD_TEE + new IntTuple(CITY, 0), + new int[] { 0, 0, 1, 1, 3, 1, 4, 0 }, + new IntTuple(ROAD, 0), + new int[] { 0, 2, 2, 2 }, + new IntTuple(ROAD, 1), + new int[] { 2, 2, 4, 2 }, + new IntTuple(ROAD, 2), + new int[] { 2, 2, 2, 4 }}, + + new Object[] { new IntTuple(GRASS, 0), // CITY_ONE_ROAD_STRAIGHT + new IntTuple(CITY, 0), + new int[] { 0, 0, 1, 1, 3, 1, 4, 0 }, + new IntTuple(ROAD, 0), + new int[] { 0, 2, 4, 2 }}, + + new Object[] { new IntTuple(GRASS, 0), // CLOISTER + new IntTuple(CITY, 0), + new int[] { 1, 1, 3, 1, 3, 3, 1, 3 }}, + + new Object[] { new IntTuple(GRASS, 0), // CLOISTER_ROAD + new IntTuple(CITY, 0), + new int[] { 1, 1, 3, 1, 3, 3, 1, 3 }, + new IntTuple(ROAD, 0), + new int[] { 2, 3, 2, 4 }}, + + new Object[] { new IntTuple(GRASS, 0), // FOUR_WAY_ROAD + new IntTuple(ROAD, 0), + new int[] { 2, 0, 2, 2 }, + new IntTuple(ROAD, 1), + new int[] { 2, 2, 4, 2 }, + new IntTuple(ROAD, 2), + new int[] { 2, 2, 2, 4 }, + new IntTuple(ROAD, 3), + new int[] { 0, 2, 2, 2 }}, + + new Object[] { new IntTuple(GRASS, 0), // THREE_WAY_ROAD + new IntTuple(ROAD, 0), + new int[] { 0, 2, 2, 2 }, + new IntTuple(ROAD, 1), + new int[] { 2, 2, 4, 2 }, + new IntTuple(ROAD, 2), + new int[] { 2, 2, 2, 4 }}, + + new Object[] { new IntTuple(GRASS, 0), // STRAIGHT_ROAD + new IntTuple(ROAD, 0), + new int[] { 2, 0, 2, 4 }}, + + new Object[] { new IntTuple(GRASS, 0), // CURVED_ROAD + new IntTuple(ROAD, 0), + new int[] { 2, 2, 2, 4 }, + new IntTuple(ROAD, 0), + new int[] { 0, 2, 2, 2 }}, + }; }