import java.awt.Point; import pulpcore.animation.Fixed; import pulpcore.image.CoreGraphics; import pulpcore.image.CoreImage; import pulpcore.sprite.Sprite; /** * a map in the isometric projection */ class IsoMap extends Sprite { private int tileWidth; private int tileHeight; private int tileWidth2; private int tileHeight2; private int numTilesAxisX; private int numTilesAxisY; public final Fixed viewX = new Fixed(this); public final Fixed viewY = new Fixed(this); private CoreImage[][] tileMap; private double tangent; /** * numTilesAxisX is the number of lines that will be draw, from the top of * the map to the right each line should be draw to the left, then skip to * the next line, the next line is the axis X * * constructor of the class * * @param tileMap * @param tileWidth * @param tileHeight */ public IsoMap(CoreImage[][] tileMap, int tileWidth, int tileHeight) { super(0, 0, tileWidth * tileMap.length, tileHeight * tileMap[0].length); this.tileMap = tileMap; this.tileWidth = tileWidth; this.tileWidth2 = tileWidth / 2; this.tileHeight = tileHeight; this.tileHeight2 = tileHeight / 2; this.tangent = getTileWidth() / getTileHeight(); numTilesAxisX = tileMap.length; numTilesAxisY = tileMap[0].length; pixelSnapping.set(true); } /** * convert from screen coordinates to map coordinates know bug - when the * map is not at the zero y, gives wrong coordinates * * @param screenX * @param screenY * @return */ public Point getTileCoordsFromScreen(int screenX, int screenY) { // shift the X/Y based on the current position of the map screenX = screenX - this.x.getAsInt(); screenY = screenY - this.y.getAsInt(); // identify the box int xDiv = screenX / getTileWidth2(); int yDiv = screenY / getTileHeight2(); // left corner of the box int xCornerOfTheBox = xDiv * getTileWidth2(); int yCornerOfTheBox = yDiv * getTileHeight2(); // distance from the left corner of the box int xDistanceFromCornerOfTheBox = screenX - xCornerOfTheBox; int yDistanceFromCornerOfTheBox = screenY - yCornerOfTheBox; boolean above = isAbovetheTileLine(xDiv, yDiv, xDistanceFromCornerOfTheBox, yDistanceFromCornerOfTheBox); // the top tile int xTopTile = getMapWidth() / 2 / getTileWidth2(); int yTopTile = 0; // shift from the top to the current piece of tile int shiftX = xDiv - xTopTile; int shiftY = yDiv - yTopTile; // piece of the NorthWest of the tile double x = shiftX + ((shiftY - shiftX) / 2.0); double y = (shiftY - shiftX) / 2.0; int xInt = (int) x; int yInt = (int) y; // identify if the piece of tile is NorthWest / SouthWest / // NorthEast // NorthWest if ((xInt + yInt) == (x + y)) { if (above) { xInt = xInt - 1; } } else { // southwest if (y > yInt) { if (!above) { yInt = yInt + 1; } } // northeast else { if (above) { yInt = yInt - 1; } } } return new Point(xInt, yInt); } /** * based on the property of the triangle, tangent (tan) = opposite/adjacent, * we will use to calculate the expected Y for a given X to identify if the * point is above or under the tile line, and make the conversion from * screen corrdinates to tile coodinates * */ private boolean isAbovetheTileLine(int xDiv, int yDiv, int xDistanceFromCornerOfTheBox, int yDistanceFromCornerOfTheBox) { boolean above = true; // calculate if the point is under or over the tile line boolean even = true; if ((xDiv + yDiv) % 2 > 0) { even = false; } int xToCalculateAdjacent = xDistanceFromCornerOfTheBox; int yToCalculateAdjacent = yDistanceFromCornerOfTheBox; if (even) { xToCalculateAdjacent = getTileWidth2() - xDistanceFromCornerOfTheBox; } /* * tangent = oposite / adjacent adjacent => x => tangent = x / adjacent => * adjacent = x / tangent to identify to adjacent that reaches the line * of the tile */ int adjacent = (int) (xToCalculateAdjacent / getTangent()); if (yToCalculateAdjacent > adjacent) { above = false; } return above; } /** * return the value of tangent * * @return the tangent */ public double getTangent() { return tangent; } public int getMapWidth() { return this.tileWidth * numTilesAxisY; } public int getMapHeight() { return height.getAsInt(); } public boolean isScrolling() { return viewX.isAnimating() || viewY.isAnimating(); } public void update(int elapsedTime) { super.update(elapsedTime); viewX.update(elapsedTime); viewY.update(elapsedTime); } protected void drawSprite(CoreGraphics g) { // set the map to the horizontal center int x = getMapWidth() / 2; int y = 0; int fHalfTileWidth = tileWidth / 2; int fHalfTileHeight = tileHeight / 2; for (int j = 0; j < numTilesAxisX; j++) { // draw one line for (int i = 0; i < numTilesAxisY; i++) { g.drawImage(tileMap[j][i], x, y); g.drawString(j + "," + i, x + 15, y + 15); x -= fHalfTileWidth; y += fHalfTileHeight; } // back to the original place x += ((numTilesAxisY) * fHalfTileWidth); y += ((numTilesAxisY) * -fHalfTileHeight); // shift to the next line x += fHalfTileWidth; y += fHalfTileHeight; } } /** * return the value of tileHeight * * @return the tileHeight */ public int getTileHeight() { return tileHeight; } /** * return the value of tileWidth * * @return the tileWidth */ public int getTileWidth() { return tileWidth; } /** * return the value of tileHeight2 * * @return the tileHeight2 */ public int getTileHeight2() { return tileHeight2; } /** * return the value of tileWidth2 * * @return the tileWidth2 */ public int getTileWidth2() { return tileWidth2; } /** * center in the screen, if is bigger than the screen set the view port in * the center of the map * * @param width * @param height */ public void centerInScreen(int width, int height) { System.out.println("map = " + getMapWidth() + "/" + getMapHeight()); int xShiftInScreen = (width - getMapWidth()) / 2; int yShiftInScreen = (height - getMapHeight()) / 2; // make it proportional to the xShiftInScreen = ((int) (xShiftInScreen / getTileWidth())) * getTileWidth(); yShiftInScreen = ((int) (yShiftInScreen / getTileHeight())) * getTileHeight(); setLocation(xShiftInScreen, yShiftInScreen); } }