Java tutorial
package com.tm4rkus.screens; /** * Copyright 2011 David Kirchner dpk@dpk.net * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * TiledMapHelper can simplify your game's tiled map operations. You can find * some sample code using this class at my blog: * * http://dpk.net/2011/05/08/libgdx-box2d-tiled-maps-full-working-example-part-2/ * * Note: This code does have some limitations. It only supports single-layered * maps. * * This code is based on TiledMapTest.java found at: * http://code.google.com/p/libgdx/ */ import com.badlogic.gdx.Gdx; import com.badlogic.gdx.graphics.GL10; import com.badlogic.gdx.graphics.Mesh; import com.badlogic.gdx.graphics.OrthographicCamera; import com.badlogic.gdx.graphics.PerspectiveCamera; import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.g2d.Sprite; import com.badlogic.gdx.graphics.g2d.SpriteBatch; import com.badlogic.gdx.graphics.g2d.TextureRegion; import com.badlogic.gdx.graphics.g3d.ModelBatch; import com.badlogic.gdx.math.Intersector; import com.badlogic.gdx.math.Matrix4; import com.badlogic.gdx.math.Plane; import com.badlogic.gdx.math.Vector3; import com.badlogic.gdx.math.collision.Ray; import com.badlogic.gdx.scenes.scene2d.Stage; import com.badlogic.gdx.scenes.scene2d.ui.Image; import com.badlogic.gdx.scenes.scene2d.ui.Label; import com.badlogic.gdx.scenes.scene2d.ui.ScrollPane; import com.badlogic.gdx.scenes.scene2d.utils.TextureRegionDrawable; import com.tm4rkus.conquertheempire.Game; import com.tm4rkus.conquertheempire.Tile; import com.tm4rkus.helperclasses.InteractiveObjectHandler; import com.tm4rkus.helperclasses.MyFPSLogger; import com.tm4rkus.helperclasses.MyGrid; import com.tm4rkus.helperclasses.MyGrid3D; import com.tm4rkus.helperclasses.MyTextureRegion; import com.tm4rkus.objects.Interactive3DObject; import com.tm4rkus.objects.MovableI3DO; public class MapScreenOld extends Stage { public final static int MAPSIZE_SMALL = 50; public final static int MAPSIZE_MEDIUM = 75; public final static int MAPSIZE_BIG = 100; public final static int MAPSIZE_HUGE = 125; public final static int MAPSIZE_GIANT = 200; public static int tiles; protected TextureRegion[] grasses, stones, leaves, sands, grassesStones, grassesLeaves, grassesSands, stonesLeaves, stonesSands, leavesSands; protected TextureRegion backgroundImage; protected Texture scene2dTexture; protected OrthographicCamera cam; protected Sprite[][] tilesBackground; protected MyGrid tilesForeground; protected MyGrid3D tilesForeground3D; protected Image topLine; protected boolean touchDragged = false; protected InteractiveObjectHandler interactiveObjectHandler; private static int tilesOnSight = 10; private Texture texture; private TextureRegion grassRegion, stoneRegion, leavesRegion, sandRegion, grassStoneRegion, grassLeavesRegion, grassSandRegion, stoneLeavesRegion, stoneSandRegion, leavesSandRegion; private SpriteBatch batch; private ModelBatch modelBatch; private final Matrix4 matrix = new Matrix4(); private MyFPSLogger logger = new MyFPSLogger(); private int tilesInView[] = new int[4]; private Label fps; public ScrollPane scrollPane; public boolean creativeMode; public MapScreenOld(int size) { //super(Game.stageWidth, Game.stageHeight, true); tiles = size; tilesBackground = new Sprite[tiles * 2][tiles * 2]; tilesForeground = new MyGrid(tiles); tilesForeground3D = new MyGrid3D(tiles); interactiveObjectHandler = new InteractiveObjectHandler(); texture = new Texture(Gdx.files.internal("data/packer/texture.png")); int tWidth = texture.getWidth(); //pure grass, stone, leaves grassRegion = new TextureRegion(texture, 0, 0, tWidth, 32); grasses = new TextureRegion[tWidth / 32]; stoneRegion = new TextureRegion(texture, 0, 32, tWidth, 32); stones = new TextureRegion[tWidth / 32]; leavesRegion = new TextureRegion(texture, 0, 64, tWidth, 32); leaves = new TextureRegion[tWidth / 32]; sandRegion = new TextureRegion(texture, 0, 96, tWidth, 32); sands = new TextureRegion[tWidth / 32]; //merge regions grassStoneRegion = new TextureRegion(texture, 0, 128, tWidth, 32); grassesStones = new TextureRegion[tWidth / 32]; grassLeavesRegion = new TextureRegion(texture, 0, 160, tWidth, 32); grassesLeaves = new TextureRegion[tWidth / 32]; grassSandRegion = new TextureRegion(texture, 0, 192, tWidth, 32); grassesSands = new TextureRegion[tWidth / 32]; stoneLeavesRegion = new TextureRegion(texture, 0, 224, tWidth, 32); stonesLeaves = new TextureRegion[tWidth / 32]; stoneSandRegion = new TextureRegion(texture, 0, 256, tWidth, 32); stonesSands = new TextureRegion[tWidth / 32]; leavesSandRegion = new TextureRegion(texture, 0, 288, tWidth, 32); leavesSands = new TextureRegion[tWidth / 32]; for (int x = 0; x < 16; x++) { grasses[x] = new MyTextureRegion(grassRegion, x * 32, 0, 32, 32, MyTextureRegion.GRASS); stones[x] = new MyTextureRegion(stoneRegion, x * 32, 0, 32, 32, MyTextureRegion.STONE); leaves[x] = new MyTextureRegion(leavesRegion, x * 32, 0, 32, 32, MyTextureRegion.LEAVES); sands[x] = new MyTextureRegion(sandRegion, x * 32, 0, 32, 32, MyTextureRegion.SAND); } //cam = new PerspectiveCamera(10, tilesOnSight, tilesOnSight * (Gdx.graphics.getHeight() / (float)Gdx.graphics.getWidth()) ); cam = new OrthographicCamera(tilesOnSight, tilesOnSight * (Gdx.graphics.getHeight() / (float) Gdx.graphics.getWidth())); cam.direction.set((float) -0.0002, -1, 0); cam.position.set((float) ((tiles / 2) - cam.direction.x * 10), (float) (10), (float) (tiles / 2)); //cam.zoom = 3; cam.near = 1; cam.far = 100; matrix.setToRotation(new Vector3(1, 0, 0), 90); //create the map for (int z = 0; z < tiles; z++) { for (int x = 0; x < tiles; x++) { int tileNumber = (int) (Math.random() * 16); if ((x + z) % 2 == 0) tilesBackground[x][z] = new Tile((MyTextureRegion) grasses[tileNumber]); else tilesBackground[x][z] = new Tile((MyTextureRegion) stones[tileNumber]); tilesBackground[x][z].setPosition(x, z); tilesBackground[x][z].setSize(1, 1); } } batch = new SpriteBatch(); modelBatch = new ModelBatch(); setTilesInView(); createOverlay(); } private void createOverlay() { scene2dTexture = new Texture(Gdx.files.internal("data/packer/scene2d.png")); backgroundImage = new TextureRegion(scene2dTexture, 0, 0, 400, 240); //Unit unit = new Unit(); topLine = new Image(new TextureRegionDrawable(backgroundImage)); topLine.setHeight(42); topLine.setWidth(820); topLine.setX(-10); topLine.setY(440); fps = new Label("fps: 0", Game.skin); fps.setX(Game.stageWidth - 100); fps.setY(Game.stageHeight - 35); addActor(topLine); addActor(fps); //addActor(unit); } int frame = 0; long deltaTime = 0; long oldTime = System.currentTimeMillis(); long newTime = System.currentTimeMillis(); public void draw() { if (Game.objectManager.isLoading() && Game.objectManager.update()) { Game.objectManager.getModels(); for (int i = 0; i < 2; i++) { // tilesForeground3D.add(new MovableI3DO(Game.objectManager.villager, (float)Math.random()*4+98, (float)Math.random()*4+98, cam)); } } if (!Game.objectManager.isLoading()) { frame++; fps.setText(logger.log()); oldTime = System.currentTimeMillis(); deltaTime = oldTime - newTime; newTime = System.currentTimeMillis(); act(); // do not forget this one!! Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT); cam.update(); batch.setProjectionMatrix(cam.combined); batch.setTransformMatrix(matrix); batch.begin(); //tilesInView stores, which tiles are visible to the user, so there is no unnecessary rendering of other tiles //rendering background //disable blending, because background doesn't need to merge with other pixels batch.disableBlending(); for (int z = tilesInView[2]; z <= tilesInView[3]; z++) { for (int x = tilesInView[0]; x <= tilesInView[1]; x++) { if (tilesBackground[x][z].getTexture() != null) tilesBackground[x][z].draw(batch); } } //rendering Foreground //enable blending, because foreground needs to merge with background batch.enableBlending(); for (int z = tilesInView[2]; z <= tilesInView[3]; z++) { for (int x = tilesInView[0]; x <= tilesInView[1]; x++) { if (tilesForeground.get(x, z) != null) { tilesForeground.act(x, z, (float) 0.01); tilesForeground.draw(x, z, batch); } } } batch.end(); cam.apply(Gdx.gl10); modelBatch.begin(cam); for (int z = tilesInView[2] - 1 >= 0 ? tilesInView[2] - 1 : 0; z <= tilesInView[3]; z++) { for (int x = tilesInView[0] - 4 >= 0 ? tilesInView[0] - 4 : 0; x <= tilesInView[1] + 1; x++) { if (tilesForeground3D.get(x, z).size() != 0) { tilesForeground3D.draw(x, z, modelBatch); } } } modelBatch.end(); if (!stop) { tilesForeground3D.calcPositions(); tilesForeground3D.checkCollisions(); } super.draw(); } } private static boolean stop = false; public static void stop() { stop = true; } public static void run() { stop = false; } final Plane xzPlane = new Plane(new Vector3(0, 1, 0), 0); final Vector3 intersection = new Vector3(); Sprite lastSelectedTile = null; private void setTilesInView() { //smallest X tilesInView[0] = getIntersectedTiles(0, 0, xzPlane)[0]; //biggest X tilesInView[1] = getIntersectedTiles(Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), xzPlane)[0]; //smallest Z tilesInView[2] = getIntersectedTiles(Gdx.graphics.getWidth(), 0, xzPlane)[1]; //biggest Z tilesInView[3] = getIntersectedTiles(0, 0, xzPlane)[1]; for (int i = 0; i < 4; i++) { if (tilesInView[i] < 0) tilesInView[i] = 0; else if (tilesInView[i] >= tiles) tilesInView[i] = tiles - 1; } } @Override public boolean touchDragged(int x, int y, int pointer) { //move the camera Boolean isTouchDragged = super.touchDragged(x, y, pointer); if (!isTouchDragged && numberOfFingers == 1) { singleTapDragged(x, y); } // pinch to zoom // for pinch-to-zoom if (numberOfFingers == 2) { twoFingersDragged(x, y, pointer); } cam.update(); return false; } //get intersected tiles on the xzPlane //x, y: place on the screen, where to detect the intersected tile //return intersectedTiles: Array with two entries, storing the x and z coordinate of the intersected tile private int[] getIntersectedTiles(int x, int y, Plane plane) { cam.update(); Ray ray = cam.getPickRay(x, y); Vector3 myintersection = new Vector3(); int intersectedTiles[] = new int[2]; Intersector.intersectRayPlane(ray, plane, myintersection); intersectedTiles[0] = (int) myintersection.x; intersectedTiles[1] = (int) myintersection.z; return intersectedTiles; } /** * If no object selected: Select object (or add object to the already selected objects). * If object(s) selected: Send object to touched point on the map (or attack hostile object at that point) * @param x x-coordinate on the map * @param z z-coordinate on the map */ private void singleTap(float x, float z) { // TODO: select object // TODO: send object } /** * if object is touched: select all objects of that type within the viewport (delete all others from selected list) * @param x x-coordinate on the map * @param z z-coordinate on the map */ private void doubleTap(float x, float z) { // TODO: select all objects of that type } //end doubleTap /** * Move the camera to scroll over the map * @param x x-coordinate of the finger on screen * @param y y-coordinate of the finger on screen */ final Vector3 currentSingleTapDrag = new Vector3(); final Vector3 lastSingleTapDrag = new Vector3(-1, -1, -1); final Vector3 deltaSingleTapDrag = new Vector3(); private void singleTapDragged(int x, int y) { //System.out.println(batch.maxSpritesInBatch); Ray pickRay = cam.getPickRay(x, y); Intersector.intersectRayPlane(pickRay, xzPlane, currentSingleTapDrag); if (!(lastSingleTapDrag.x == -1 && lastSingleTapDrag.y == -1 && lastSingleTapDrag.z == -1)) { pickRay = cam.getPickRay(lastSingleTapDrag.x, lastSingleTapDrag.y); Intersector.intersectRayPlane(pickRay, xzPlane, deltaSingleTapDrag); deltaSingleTapDrag.sub(currentSingleTapDrag); cam.position.add(deltaSingleTapDrag.x, 0, deltaSingleTapDrag.z); cam.update(); Ray centerRay = cam.getPickRay(Gdx.graphics.getWidth() / 2, Gdx.graphics.getHeight() / 2); Intersector.intersectRayPlane(centerRay, xzPlane, intersection); float centerX = intersection.x; float centerZ = intersection.z; if (centerX < 2) { cam.position.x = (float) (2 - (cam.direction.x * cam.position.y)); } if (centerZ > tiles - 2) { cam.position.z = tiles - 2; } if (centerX > tiles - 2) { cam.position.x = (float) (tiles - 2 - (cam.direction.x * cam.position.y)); } if (centerZ < 2) { cam.position.z = 2; } } lastSingleTapDrag.set(x, y, 0); setTilesInView(); if (deltaSingleTapDrag.x != 0.0 || deltaSingleTapDrag.y != 0.0 || deltaSingleTapDrag.z != 0.0) { touchDragged = true; } } //end singleTapDragged /** * Create a selection rectangle and select all movable objects within it's range * @param x x-coordinate of the finger on screen * @param y y-coordinate of the finger on screen */ private Vector3 startDoubleTapDrag = new Vector3(); private void doubleTapDragged(float x, float y) { // TODO: create selection rectangle and select all movable objects within it's range } //end doubleTapDragged /** * If both fingers go up: tilt cam * If both fingers go apart: zoom cam * @param x x-coordinate of the finger on screen * @param y y-coordinate of the finger on screen * @param pointer pointer to identify the finger */ private void twoFingersDragged(int x, int y, int pointer) { if (pointer == fingerOnePointer) { fingerOne.set(x, y, 0); } if (pointer == fingerTwoPointer) { fingerTwo.set(x, y, 0); } float xDistance = Math.abs(fingerOne.x - fingerTwo.x); float xChange = xDistance - lastXDistance; float yChange = (fingerOne.y + fingerTwo.y) - (lastY1 + lastY2); if (((fingerOne.y > lastY1 && fingerTwo.y > lastY2) || (fingerOne.y < lastY1 && fingerTwo.y < lastY2)) && (Math.abs(yChange) > Math.abs(xChange))) { tiltCam(yChange); } else { // zoom in and out zoomCam(xChange); } lastXDistance = xDistance; //the method touchdragged registers only one pointer at once, so don't update both if (pointer == fingerTwoPointer) { lastY1 = fingerOne.y; } else if (pointer == fingerOnePointer) { lastY2 = fingerTwo.y; } setTilesInView(); } /** * Tilt camera to have a more 3-dimensional scene from the side or more 2-dimensional from above (like GTA2 ;P) * @param tiltFactor The Factor the declination changes with */ private void tiltCam(float tiltFactor) { cam.direction.x -= tiltFactor * 0.005; cam.position.x = (float) (centerX - (cam.direction.x * cam.position.y)); cam.update(); // don't tilt too much if (cam.direction.x < (float) -2.2) { cam.direction.x = (float) -2.2; } if (cam.direction.x > (float) -0.1) { cam.direction.x = (float) -0.1; } } /** * Zoom camera to have a wider or a closer view at the scene * @param zoomFactor The Factor the zoom changes with: (zoomFactor > 0) --> closer view ; (zoomFactor < 0) --> wider view */ private void zoomCam(float zoomFactor) { // multiply with cam.zoom to get rid of the different zoom speed, depending on whether it close or not. cam.zoom -= cam.zoom * zoomFactor * 0.005; cam.update(); // don't zoom in/out too much. if (cam.zoom > (float) (1.5)) { cam.zoom = (float) (1.5); } if (cam.zoom < (float) (0.8)) { cam.zoom = (float) (0.8); } touchDragged = true; } public boolean superTouchUp(int x, int y, int pointer, int button) { return super.touchUp(x, y, pointer, button); } private long touchTime; public boolean touchUp(int x, int y, int pointer, int button) { boolean isTouchUp = super.touchUp(x, y, pointer, button); lastSingleTapDrag.set(-1, -1, -1); // for pinch-to-zoom if (numberOfFingers == 1) { Vector3 touchPoint = new Vector3(x, y, 0); cam.unproject(touchPoint); if (!touchDragged) { Ray pickRay = cam.getPickRay(Gdx.input.getX(), Gdx.input.getY()); Intersector.intersectRayPlane(pickRay, xzPlane, intersection); float isctX = intersection.x; float isctZ = intersection.z; //debug stuff System.out.println("Map touched at: " + isctX + "|" + isctZ); //tilesForeground3D.clear(); //for(int i = 0; i < 10; i++) { //tilesForeground3D.add(new MovableI3DO(Game.objectManager.villager, (float)Math.random()*10+95, (float)Math.random()*10+95, cam)); MovableI3DO movable; /*movable = new MovableI3DO(Game.objectManager.villager, 102, 100, cam); movable.setDestination(100, 100); tilesForeground3D.add(movable); movable = new MovableI3DO(Game.objectManager.villager, (float)98.5, 100, cam); movable.setDestination(100, 100); tilesForeground3D.add(movable);*/ movable = new MovableI3DO(Game.objectManager.villager, isctX, isctZ); movable.setDestination(100, 100); tilesForeground3D.add(movable); // run(); //} if (isctX >= 0 && isctX < tiles && isctZ >= 0 && isctZ < tiles) { if (System.currentTimeMillis() - touchTime > 200) { touchTime = System.currentTimeMillis(); singleTap(isctX, isctZ); } else { touchTime = 0; doubleTap(isctX, isctZ); } } } touchDragged = false; } numberOfFingers--; //if there were more than 2 fingers on the screen if (numberOfFingers > 1) { numberOfFingers = 0; } //if something was not registered properly if (numberOfFingers < 0) { numberOfFingers = 0; } lastDistance = 0; return false; } @Override public boolean keyDown(int keycode) { super.keyDown(keycode); // TODO Auto-generated method stub return false; } @Override public boolean keyUp(int keycode) { super.keyUp(keycode); return false; } @Override public boolean keyTyped(char character) { super.keyTyped(character); return false; } // for pinch-to-zoom int numberOfFingers = 0; int fingerOnePointer; int fingerTwoPointer; float lastDistance = 0; float lastXDistance = 0; float lastY1 = 0; float lastY2 = 0; float centerX = 0; float centerZ = 0; Vector3 fingerOne = new Vector3(); Vector3 fingerTwo = new Vector3(); public boolean superTouchDown(int x, int y, int pointer, int button) { return super.touchDown(x, y, pointer, button); } @Override public boolean touchDown(int x, int y, int pointer, int button) { boolean isTouchDown = super.touchDown(x, y, pointer, button); if (!isTouchDown) { // for pinch-to-zoom numberOfFingers++; if (numberOfFingers == 1) { fingerOnePointer = pointer; fingerOne.set(x, y, 0); } else if (numberOfFingers == 2) { fingerTwoPointer = pointer; fingerTwo.set(x, y, 0); Ray centerRay = cam.getPickRay(Gdx.graphics.getWidth() / 2, Gdx.graphics.getHeight() / 2); Intersector.intersectRayPlane(centerRay, xzPlane, intersection); centerX = intersection.x; centerZ = intersection.z; float distance = fingerOne.dst(fingerTwo); lastDistance = distance; lastXDistance = Math.abs(fingerOne.x - fingerTwo.x); lastY1 = fingerOne.y; lastY2 = fingerTwo.y; } } return false; } public void pause() { numberOfFingers = 0; } @Override public void dispose() { super.dispose(); } @Override public boolean scrolled(int arg0) { super.scrolled(arg0); return false; } }