--- /dev/null
+package com.badlogic.gdx.tests.superkoalio;\r
+\r
+import com.badlogic.gdx.Gdx;\r
+import com.badlogic.gdx.Input.Keys;\r
+import com.badlogic.gdx.graphics.GL10;\r
+import com.badlogic.gdx.graphics.OrthographicCamera;\r
+import com.badlogic.gdx.graphics.Texture;\r
+import com.badlogic.gdx.graphics.g2d.Animation;\r
+import com.badlogic.gdx.graphics.g2d.SpriteBatch;\r
+import com.badlogic.gdx.graphics.g2d.TextureRegion;\r
+import com.badlogic.gdx.graphics.glutils.ShapeRenderer;\r
+import com.badlogic.gdx.graphics.glutils.ShapeRenderer.ShapeType;\r
+import com.badlogic.gdx.maps.tiled.TiledMap;\r
+import com.badlogic.gdx.maps.tiled.TiledMapTile;\r
+import com.badlogic.gdx.maps.tiled.TiledMapTileLayer;\r
+import com.badlogic.gdx.maps.tiled.TiledMapTileLayer.Cell;\r
+import com.badlogic.gdx.maps.tiled.TmxMapLoader;\r
+import com.badlogic.gdx.maps.tiled.renderers.OrthogonalTiledMapRenderer;\r
+import com.badlogic.gdx.math.Rectangle;\r
+import com.badlogic.gdx.math.Vector2;\r
+import com.badlogic.gdx.tests.utils.GdxTest;\r
+import com.badlogic.gdx.utils.Array;\r
+import com.badlogic.gdx.utils.Pool;\r
+\r
+/**\r
+ * Super Mario Brothers like platformer, using a tile map build\r
+ * via <a href="http://www.mapeditor.org/>Tiled</a> and a tileset\r
+ * and sprites by <a href="http://www.vickiwenderlich.com/">Vicky Wenderlich</a>\r
+ * @author mzechner\r
+ *\r
+ */\r
+public class SuperKoalio extends GdxTest {\r
+ \r
+ private static class Koala {\r
+ private static float WIDTH;\r
+ private static float HEIGHT;\r
+ private static float MAX_VELOCITY = 10f;\r
+ private static float WALK_VELOCITY = 2f;\r
+ private static float JUMP_VELOCITY = 40f;\r
+ private static float DAMPING = 0.87f;\r
+ \r
+ enum State {\r
+ Standing,\r
+ Walking,\r
+ Jumping\r
+ }\r
+ \r
+ final Vector2 position = new Vector2();\r
+ final Vector2 velocity = new Vector2();\r
+ State state = State.Walking;\r
+ float stateTime = 0;\r
+ boolean facesRight = true;\r
+ boolean grounded = false;\r
+ }\r
+ \r
+ private TiledMap map;\r
+ private OrthogonalTiledMapRenderer renderer;\r
+ private OrthographicCamera camera;\r
+ private Texture koalaTexture;\r
+ private Animation stand;\r
+ private Animation walk;\r
+ private Animation jump;\r
+ private Koala koala;\r
+ private Pool<Rectangle> rectPool = new Pool<Rectangle>() {\r
+ @Override\r
+ protected Rectangle newObject () {\r
+ return new Rectangle();\r
+ }\r
+ };\r
+ private Array<Rectangle> tiles = new Array<Rectangle>();\r
+ \r
+ private static final float GRAVITY = -2.5f;\r
+ \r
+ @Override\r
+ public void create () {\r
+ // load the koala frames, split them, and assign them to Animations\r
+ koalaTexture = new Texture("data/maps/tiled/super-koalio/koalio.png"); \r
+ TextureRegion[] regions = TextureRegion.split(koalaTexture, 18, 26)[0];\r
+ stand = new Animation(0, regions[0]);\r
+ jump = new Animation(0, regions[1]);\r
+ walk = new Animation(0.15f, regions[2], regions[3], regions[4]);\r
+ walk.setPlayMode(Animation.LOOP_PINGPONG);\r
+ \r
+ // figure out the width and height of the koala for collision\r
+ // detection and rendering by converting a koala frames pixel\r
+ // size into world units (1 unit == 16 pixels)\r
+ Koala.WIDTH = 1 / 16f * regions[0].getRegionWidth();\r
+ Koala.HEIGHT = 1 / 16f * regions[0].getRegionHeight();\r
+ \r
+ // load the map, set the unit scale to 1/16 (1 unit == 16 pixels)\r
+ map = new TmxMapLoader().load("data/maps/tiled/super-koalio/level1.tmx");\r
+ renderer = new OrthogonalTiledMapRenderer(map, 1 / 16f);\r
+ \r
+ // create an orthographic camera, shows us 30x20 units of the world\r
+ camera = new OrthographicCamera();\r
+ camera.setToOrtho(false, 30, 20);\r
+ camera.update();\r
+ \r
+ // create the Koala we want to move around the world\r
+ koala = new Koala();\r
+ koala.position.set(10, 2);\r
+ }\r
+\r
+ @Override\r
+ public void render () {\r
+ // clear the screen\r
+ Gdx.gl.glClearColor(0.7f, 0.7f, 1.0f, 1);\r
+ Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);\r
+ \r
+ // get the delta time\r
+ float deltaTime = Gdx.graphics.getDeltaTime();\r
+ \r
+ // update the koala (process input, collision detection, position update)\r
+ updateKoala(deltaTime);\r
+ \r
+ // let the camera follow the koala, x-axis only\r
+ camera.position.x = koala.position.x;\r
+ camera.update();\r
+ \r
+ // set the tile map rendere view based on what the\r
+ // camera sees and render the map\r
+ renderer.setView(camera);\r
+ renderer.render();\r
+ \r
+ // render the koala\r
+ renderKoala(deltaTime);\r
+ }\r
+ \r
+ private void updateKoala(float deltaTime) {\r
+ koala.stateTime += deltaTime;\r
+ \r
+ // check input and apply to velocity & state\r
+ if(Gdx.input.isKeyPressed(Keys.SPACE) & koala.grounded) {\r
+ koala.velocity.y += Koala.JUMP_VELOCITY;\r
+ koala.state = Koala.State.Jumping;\r
+ koala.grounded = false;\r
+ }\r
+ \r
+ if(Gdx.input.isKeyPressed(Keys.LEFT) || Gdx.input.isKeyPressed(Keys.A)) {\r
+ koala.velocity.x -= Koala.WALK_VELOCITY;\r
+ if(koala.state != Koala.State.Jumping) koala.state = Koala.State.Walking;\r
+ koala.facesRight = false;\r
+ }\r
+ \r
+ if(Gdx.input.isKeyPressed(Keys.RIGHT) || Gdx.input.isKeyPressed(Keys.D)) {\r
+ koala.velocity.x += Koala.WALK_VELOCITY;\r
+ if(koala.state != Koala.State.Jumping) koala.state = Koala.State.Walking;\r
+ koala.facesRight = true;\r
+ }\r
+ \r
+ // apply gravity if we are falling\r
+ koala.velocity.add(0, GRAVITY);\r
+ \r
+ // multiply by delta time so we know how far we go\r
+ // in this frame\r
+ koala.velocity.mul(deltaTime);\r
+ \r
+ // perform collision detection & response based on the current\r
+ // position and velocity. Collision detection will clamp the\r
+ // velocity if necessary and move the koala out of tiles\r
+ Rectangle koalaRect = rectPool.obtain();\r
+ System.out.println("frame");\r
+ koalaRect.set(koala.position.x, koala.position.y, Koala.WIDTH, Koala.HEIGHT);\r
+ \r
+ koalaRect.y += koala.velocity.y;\r
+ for (Rectangle rect: getCollidingTiles(koala.position, 0, koala.velocity.y)) {\r
+ if (koalaRect.overlaps(rect)) {\r
+ System.out.println("coll y");\r
+ if (koala.velocity.y < 0) {\r
+ koalaRect.y = rect.y + rect.height + 0.001f;\r
+ koala.grounded = true;\r
+ } else if(koala.velocity.y > 0 ){\r
+ koalaRect.y = rect.y - rect.height - 0.001f;\r
+ }\r
+ koala.velocity.y = 0;\r
+ }\r
+ }\r
+ koala.position.set(koalaRect.x, koalaRect.y);\r
+\r
+ koalaRect.x += koala.velocity.x;\r
+ for (Rectangle rect: getCollidingTiles(koala.position, koala.velocity.x, 0)) {\r
+ if (koalaRect.overlaps(rect)) {\r
+ System.out.println("coll x");\r
+ if (koala.velocity.x < 0) {\r
+ koalaRect.x = rect.x + rect.width + 0.001f;\r
+ } else if(koala.velocity.x > 0){\r
+ koalaRect.x = rect.x - rect.width - 0.001f;\r
+ }\r
+ koala.velocity.x = 0;\r
+ koala.state = Koala.State.Standing;\r
+ }\r
+ }\r
+ koala.position.set(koalaRect.x, koalaRect.y);\r
+\r
+ // unscale the velocity by the inverse delta time and set \r
+ // the latest position\r
+ koala.velocity.mul(1/deltaTime);\r
+ \r
+ // free the koala rectangle\r
+ rectPool.free(koalaRect);\r
+ \r
+ // Apply damping to the velocity on the x-axis so we don't\r
+ // walk infinitely once a key was pressed\r
+ koala.velocity.x *= Koala.DAMPING;\r
+ }\r
+ \r
+ private Array<Rectangle> getCollidingTiles(Vector2 position, float velocityX, float velocityY) {\r
+ // figure out the tiles within which the koala is moving in the current timestep\r
+ int startX, startY, endX, endY;\r
+ if(velocityX < 0) startX = (int)(position.x + velocityX);\r
+ else startX = (int)position.x;\r
+ if(velocityY < 0) startY = (int)(position.y + velocityY);\r
+ else startY = (int)position.y;\r
+ endX = (int)(startX + Koala.WIDTH + Math.abs(velocityX));\r
+ endY = (int)(startY + Koala.HEIGHT + Math.abs(velocityY));\r
+ \r
+ // get all the tiles that overlap this area\r
+ TiledMapTileLayer layer = (TiledMapTileLayer)map.getLayers().getLayer(1);\r
+ rectPool.freeAll(tiles);\r
+ tiles.clear();\r
+ for(int y = startY; y <= endY; y++) {\r
+ for(int x = startX; x <= endX; x++) {\r
+ Cell cell = layer.getCell(x, y);\r
+ if(cell.getTile() != null) {\r
+ Rectangle rect = rectPool.obtain();\r
+ rect.set(x, y, 1, 1);\r
+ tiles.add(rect);\r
+ }\r
+ }\r
+ }\r
+ return tiles;\r
+ }\r
+ \r
+ private void renderKoala(float deltaTime) {\r
+ // based on the koala state, get the animation frame\r
+ TextureRegion frame = null;\r
+ switch(koala.state) {\r
+ case Standing: frame = stand.getKeyFrame(koala.stateTime); break;\r
+ case Walking: frame = walk.getKeyFrame(koala.stateTime); break;\r
+ case Jumping: frame = jump.getKeyFrame(koala.stateTime); break; \r
+ }\r
+ \r
+ // draw the koala, depending on the current velocity\r
+ // on the x-axis, draw the koala facing either right\r
+ // or left\r
+ SpriteBatch batch = renderer.getSpriteBatch();\r
+ batch.begin();\r
+ if(koala.facesRight) {\r
+ batch.draw(frame, koala.position.x, koala.position.y, Koala.WIDTH, Koala.HEIGHT);\r
+ } else {\r
+ batch.draw(frame, koala.position.x + Koala.WIDTH, koala.position.y, -Koala.WIDTH, Koala.HEIGHT);\r
+ }\r
+ batch.end();\r
+ }\r
+\r
+ @Override\r
+ public void dispose () {\r
+ }\r
+}\r