package com.digitalwolf.world; import java.util.ArrayList; import java.util.List; import com.badlogic.gdx.maps.MapProperties; import com.badlogic.gdx.maps.tiled.TiledMap; import com.badlogic.gdx.maps.tiled.TiledMapTileLayer; import com.badlogic.gdx.maps.tiled.TiledMapTileLayer.Cell; import com.badlogic.gdx.maps.tiled.TmxMapLoader; import com.badlogic.gdx.math.Rectangle; import com.badlogic.gdx.utils.Array; import com.badlogic.gdx.utils.Pool; import com.digitalwolf.assets.Assets; import com.digitalwolf.creatures.Dragon; import com.digitalwolf.creatures.Pumma; import com.digitalwolf.creatures.Snake; import com.digitalwolf.creatures.Spring; import com.digitalwolf.gamedata.DoorData; import com.digitalwolf.gamedata.DragonData; import com.digitalwolf.gamedata.EggData; import com.digitalwolf.gamedata.GemData; import com.digitalwolf.gamedata.KeyData; import com.digitalwolf.gamedata.PlayerData; import com.digitalwolf.gamedata.SnakeData; import com.digitalwolf.gamedata.SpringData; import com.digitalwolf.screens.GameScreen; import com.moribitotech.mtx.settings.AppSettings; import com.mtx.scene2dactors.Door; import com.mtx.scene2dactors.Egg; import com.mtx.scene2dactors.Gem; import com.mtx.scene2dactors.Key; public class World { public interface WorldListener { public void fall(); public void grabgem(); public void grabegg(); public void cry(); public void ow(); public void success(); } public static final float WORLD_WIDTH = 30; public static final float WORLD_HEIGHT = 20; public static final int WORLD_STATE_RUNNING = 0; public static final int WORLD_STATE_NEXT_LEVEL = 1; public static final int WORLD_STATE_GAME_OVER = 2; public static final float GRAVITY = -2.5f; public static final float WORLD_UNIT =1/16f; public int state; public static int levelID =1; //The time spent after the world is created (in seconds) private float startTime = System.nanoTime(); public static float SECONDS_TIME = 0; //VARIABLES FOR LEVEL MAPS AND THEIR PROPERTIES public TiledMap map; public MapProperties prop; public static int mapWidth; public static int mapHeight; public final WorldListener listener; //Create the Player here public Pumma pumma; public Key key; public Door door; public ArrayList<Dragon> dragons; public ArrayList<Snake> snakes; public ArrayList<Spring> springs; public List<Egg> eggs; public List<Gem> gems; //VARIABLES FOR PLAYER ACHIEVEMENTS/SCORES/HURTS public static int score; public boolean pummaAtdoor; public int eggsPummaHave, gemsPummaHave; private int numTotalEggs, numTotalGems; private float[][] snakePosition, eggPosition, dragonPosition, keyPosition, doorPosition, gemPosition, springPoition; //Rectangles for Checking Bounds between Player and Level map private Pool<Rectangle> rectPool = new Pool<Rectangle>() { @Override protected Rectangle newObject() { return new Rectangle(); } }; private Array<Rectangle> tiles = new Array<Rectangle>(); public World(WorldListener listener) { this.listener = listener; this.state = WORLD_STATE_RUNNING; SECONDS_TIME = 0; //TAKE THIS LEVEL ID FROM GAMESCREEN AS A PARAMETER //IF THE GAME IS CONTINUED THEN IT WILL READ THE CURRENTLEVEL FROM JSON/PREFERENCES/DATABASES //IDEA IS SAVE BOOLEAN GAMECONTINUED IF THE CONTINUE BUTTON IS PRESSED AND USE IF O DETERMINE levelID = GameScreen.currentlevel; generateLevelMap(levelID); //score = 0; //CREATE THE PUMMA this.pumma = new Pumma(0,0); pumma.setPosition(PlayerData.getPlayerPosition(levelID)[0][0], PlayerData.getPlayerPosition(levelID)[0][1]); pummaAtdoor = false; //INITIALIZE SNAKES HERE this.snakes = new ArrayList<Snake>(); snakePosition = SnakeData.getSnakePosition(levelID); placeSnakes(); //INITIALIZE DRAGONS HERE this.dragons = new ArrayList<Dragon>(); dragonPosition = DragonData.getDragonPosition(levelID); placeDragons(); //PLACE THE KEY HERE keyPosition = KeyData.getKeyPosition(levelID); this.key = new Key(Key.width, Key.height, true ); placeKey(); //PLACE THE DOOR HERE doorPosition = DoorData.getDoorPosition(levelID); this.door = new Door(Door.width, Door.height, true ); placeDoor(); //PLACE THE EGGS HERE eggs = new ArrayList<Egg>(); eggPosition = EggData.getEggPosition(levelID); numTotalEggs = EggData.getEggPosition(levelID).length; placeEggs(); //PLACE THE GEMS HERE gems = new ArrayList<Gem>(); gemPosition = GemData.getGemPosition(levelID); numTotalGems = GemData.getGemPosition(levelID).length; placeGems(); //PLACE THE GEMS HERE springs = new ArrayList<Spring>(); springPoition = SpringData.getSpringPosition(levelID); placeSprings(); placeDoor(); //initialize gemsPummaHave =0; eggsPummaHave =0; } private void placeSprings() { // TODO Auto-generated method stub for(int i=0;i<springPoition.length;i++){ Spring spring1 = new Spring(springPoition[i][0],springPoition[i][1]); springs.add(spring1); } } private void placeGems() { // TODO Auto-generated method stub for(int i=0;i<gemPosition.length;i++){ Gem gem1 = new Gem(Gem.width, Gem.height, true); gem1.setOrigin(0, 0); gem1.setPosition(gemPosition[i][0],gemPosition[i][1]); gem1.setSize(Gem.width, Gem.height); gem1.setTextureRegion(Assets.snake_gem, true); gems.add(gem1); } } private void placeDoor() { // TODO Auto-generated method stub door.setOrigin(0, 0); door.setPosition(doorPosition[0][0],doorPosition[0][1]); door.setSize(Door.width, Door.height); door.setTextureRegion(Assets.door, true); } private void placeKey() { // TODO Auto-generated method stub key.setOrigin(0, 0); key.setPosition(keyPosition[0][0],keyPosition[0][1]); key.setSize(Key.width, Key.height); key.setTextureRegion(Assets.key, true); } private void placeDragons() { for(int i=0;i< dragonPosition.length;i++){ Dragon e = new Dragon(dragonPosition[i][0],dragonPosition[i][1]); dragons.add(e); e.velocity.x-=e.MAX_VELOCITY; } } private void placeEggs() { for(int i=0;i<eggPosition.length;i++){ Egg egg1 = new Egg(Egg.width, Egg.height, true); egg1.setOrigin(0, 0); egg1.setPosition(eggPosition[i][0],eggPosition[i][1]); egg1.setSize(Egg.width, Egg.height); egg1.setTextureRegion(Assets.egg, true); eggs.add(egg1); } } private void placeSnakes() { // TODO Auto-generated method stub for(int i=0;i<snakePosition.length;i++){ Snake e = new Snake(snakePosition[i][0],snakePosition[i][1]); snakes.add(e); e.velocity.x-=e.MAX_VELOCITY; } } private void generateLevelMap(int levelID) { // Load the map map = new TmxMapLoader().load("data/level/level"+levelID+".tmx"); prop = map.getProperties(); //Get the properties mapWidth = prop.get("width", Integer.class); mapHeight = prop.get("height", Integer.class); } /** * MOST IMPORTANT METHOD THAT UPDATES THE WHOLE GAME WORLD * JUST THE INPUT EVENTS FOR PLAYER AND GAME PAUSE ARE HANDLED IN THE GAMESCREEN * UPDATES THE PLAYER AND ALL OTHER GAME OBJECTS * CHECKS FOR COLLISION BETWEEN VARIOUS GAME OBJECTS INCLUDING LAYER TILES * CHECKS FOR THE CONDITION FOR GAME OVER, LEVEL END * **/ public void update(float deltaTime) { if (deltaTime == 0) return; checkPoomaAtDoor(); updatePumma(deltaTime); updateSnakes(deltaTime); updateDragons(deltaTime); updateKey(deltaTime); checkCollisions(deltaTime); checkGameOver(); if (System.nanoTime() - startTime >= 1000000000) { SECONDS_TIME++; startTime = System.nanoTime(); } if(SECONDS_TIME % 5 ==0) pumma.health--; } private void updateKey(float deltaTime) { // TODO Auto-generated method stub if(key.visible){ key.update(deltaTime); } else key.remove(); } private void updateDragons(float deltaTime) { // TODO Auto-generated method stub for(int i=0;i< dragons.size();i++){ Dragon e = dragons.get(i); if(e.visible){ e.update(deltaTime); } else{ dragons.remove(e); } } } private void updateSnakes(float deltaTime) { for(int i=0;i< snakes.size();i++){ Snake e = snakes.get(i); if(e.visible){ e.update(deltaTime); } else{ snakes.remove(e); } } } private void checkGameOver() { //IF THE PLAYER FALLS DOWN if (pumma.position.y <= -AppSettings.SCREEN_H/10) { state = WORLD_STATE_GAME_OVER; listener.fall(); GameScreen.gameoverinfo ="Pumma Fell Down"; } if (pumma.health <= 0) { state = WORLD_STATE_GAME_OVER; GameScreen.gameoverinfo ="Pumma lost Health"; listener.fall(); } //Conditions for Level Completion if(pummaAtdoor && pumma.hasKey && (eggsPummaHave >= numTotalEggs/2) && (gemsPummaHave >= numTotalGems/2)){ state = WORLD_STATE_NEXT_LEVEL; } } //UPDATES NECESSARY FOR THE PLAYER LIKE APPLYING GRAVITY, CLAMPING ETC private void updatePumma(float deltaTime) { if (deltaTime == 0) return; pumma.stateTime+= deltaTime; //Updates the Player helping not to cross the map Boundaries pumma.update(deltaTime); //Apply gravity if we are falling pumma.velocity.add(0, GRAVITY); //Clamp the velocity to the maximum, x-axis only if(Math.abs(pumma.velocity.x) > pumma.MAX_VELOCITY) { pumma.velocity.x = Math.signum(pumma.velocity.x) * pumma.MAX_VELOCITY; } // clamp the velocity to 0 if it's < 1, and set the state to Standing if(Math.abs(pumma.velocity.x) < 1) { pumma.velocity.x = 0; if(pumma.grounded) pumma.setState(Pumma.STILL); } // multiply by delta time so we know how far we go // in this frame pumma.velocity.scl(deltaTime); } //CHECK FOR COLLISION REGULARLY IN GAMES private void checkCollisions(float deltaTime) { checkCollisionsPlayervsMap(deltaTime); checkCollisionsPlayervsSnakes(deltaTime); checkCollisionsPlayervsEggs(deltaTime); checkCollisionsPlayervsGems(deltaTime); checkCollisionsPlayervsDragons(deltaTime); if(key.visible) checkCollisionsPlayervsKey(deltaTime); checkCollisionsPlayervsSpring(deltaTime); } private void checkCollisionsPlayervsSpring(float deltaTime) { // TODO Auto-generated method stub for(int i=0;i<springs.size();i++){ Spring e = springs.get(i); e.update(deltaTime); Rectangle springBounds = new Rectangle(e.position.x,e.position.y,Spring.width,Spring.height); if(springBounds.overlaps(pumma.getBounds())){ listener.ow(); e.state = Spring.ACTIVE; pumma.velocity.y+= pumma.JUMP_VELOCITY/2; if(pumma.velocity.y >= pumma.JUMP_VELOCITY*1.5f) pumma.velocity.y = pumma.JUMP_VELOCITY*1.5f; } else{ e.state = Spring.NORMAL; } } } private void checkCollisionsPlayervsGems(float deltaTime) { // TODO Auto-generated method stub for (int j = 0; j<gems.size(); j++) { Gem e = (Gem) gems.get(j); Rectangle gemBounds = new Rectangle(e.getX(),e.getY(),e.getWidth(),e.getHeight()); if(pumma.getBounds().overlaps(gemBounds)){ listener.grabgem(); score+=20; gemsPummaHave++; e.visible = false; gems.remove(e); } } } private void checkCollisionsPlayervsKey(float deltaTime) { // TODO Auto-generated method stub Rectangle keyBounds = new Rectangle(key.getX(),key.getY(),key.getWidth(),key.getHeight()); if(pumma.getBounds().overlaps(keyBounds)){ listener.success(); key.visible = false; pumma.hasKey = true; score+=500; } } private void checkPoomaAtDoor(){ Rectangle doorBounds = new Rectangle(door.getX(),door.getY(), door.getWidth(),door.getHeight()); if(pumma.getBounds().overlaps(doorBounds)){ pummaAtdoor = true; if(pumma.hasKey && (eggsPummaHave >= numTotalEggs/2) && (gemsPummaHave >= numTotalGems/2)){ door.setTextureRegion(Assets.transparent, true); } } else{ pummaAtdoor = false; } } private void checkCollisionsPlayervsDragons(float deltaTime) { // TODO Auto-generated method stub for (int j = 0; j<dragons.size(); j++) { Dragon e = (Dragon) dragons.get(j); Rectangle dragonBounds = new Rectangle(e.position.x,e.position.y,Dragon.width,Dragon.height); if(pumma.getBounds().overlaps(dragonBounds)){ e.visible = false; listener.cry(); state = WORLD_STATE_GAME_OVER; GameScreen.gameoverinfo ="Devil Dragon Attacked"; } } } private void checkCollisionsPlayervsEggs(float deltaTime) { // TODO Auto-generated method stub for (int j = 0; j<eggs.size(); j++) { Egg e = (Egg) eggs.get(j); Rectangle eggBounds = new Rectangle(e.getX(),e.getY(),e.getWidth(),e.getHeight()); if(pumma.getBounds().overlaps(eggBounds)){ //EffectCreator.create_FO(e, 0.5f, null, true); //EffectCreator.create_SC_FO(e, 0.5f, 0.5f, 0.3f, 0.0f, null, true); listener.grabegg(); score+=100; eggsPummaHave++; pumma.health+=100; e.visible = false; eggs.remove(e); } } } private void checkCollisionsPlayervsSnakes(float deltaTime) { // TODO Auto-generated method stub for(int i=0;i<snakes.size();i++){ Snake e = snakes.get(i); Rectangle snakeBounds = e.getBounds(); if(snakeBounds.overlaps(pumma.getBounds())){ listener.ow(); state = WORLD_STATE_GAME_OVER; GameScreen.gameoverinfo ="snake poisoned pumma"; } else{ } } } private void checkCollisionsPlayervsMap(float deltaTime) { // perform collision detection & response, on each axis, separately // if the koala is moving right, check the tiles to the right of it's // right bounding box edge, otherwise check the ones to the left Rectangle pummaRect = rectPool.obtain(); pummaRect.set(pumma.position.x , pumma.position.y, Pumma.width, Pumma.height); int startX, startY, endX, endY; if (pumma.velocity.x > 0) { startX = endX = (int) (pumma.position.x + Pumma.width+ pumma.velocity.x); } else { startX = endX = (int) (pumma.position.x + pumma.velocity.x); } startY = (int) (pumma.position.y); endY = (int) (pumma.position.y + Pumma.height); getTiles(startX, startY, endX, endY, tiles); pummaRect.x += pumma.velocity.x; for (Rectangle tile : tiles) { if (pummaRect.overlaps(tile)) { pumma.velocity.x = 0; break; } } pummaRect.x = pumma.position.x; // if the koala is moving upwards, check the tiles to the top of it's // top bounding box edge, otherwise check the ones to the bottom if (pumma.velocity.y > 0) { startY = endY = (int) (pumma.position.y + Pumma.height + pumma.velocity.y); } else { startY = endY = (int) (pumma.position.y + pumma.velocity.y); } startX = (int) (pumma.position.x); endX = (int) (pumma.position.x + 3*Pumma.width/4); getTiles(startX, startY, endX, endY, tiles); pummaRect.y += pumma.velocity.y; //Stores the property of the tile the player collides with in the foreground layer String type =""; for (Rectangle tile : tiles) { if (pummaRect.overlaps(tile)) { //Here we are checking for the tile properties that can be set using Tiled TiledMapTileLayer layer = (TiledMapTileLayer) map.getLayers().get(1); try{ type = layer.getCell((int) tile.x, (int) tile.y).getTile().getProperties().get("type").toString(); } catch(Exception e){ System.out.print("Tile "+type+" :not found : Exception in Tiles Property :" +e); type="unknown"; } if (pumma.velocity.y > 0) { listener.ow(); if(("1up".equals(type))){ //TiledMapTileSet tileset = map.getTileSets().getTileSet("worldmaptileset1"); layer.setCell((int) tile.x, (int) tile.y, layer.getCell(22, 5)); layer.setCell((int) tile.x+1, (int) tile.y, layer.getCell(22, 5)); layer.setCell((int) tile.x, (int) tile.y+1, layer.getCell(22, 5)); layer.setCell((int) tile.x+1, (int) tile.y+1, layer.getCell(22, 5)); score+=100; } if(("breakable1".equals(type))){ layer.setCell((int) tile.x, (int) tile.y, null); score+=20; } pumma.position.y = (tile.y - Pumma.height); } else { //If the player is falling down this tile i.e.Velocity<=0 //Let us change this tile with other pumma.position.y = (tile.y + tile.height); // if we hit the ground, mark us as grounded so we can jump pumma.grounded = true; } pumma.velocity.y =0; break; } } rectPool.free(pummaRect); // unscale the velocity by the inverse delta time and set // the latest position pumma.position.add(pumma.velocity); //koala.getVelocityVector().scl(1 / deltaTime); pumma.velocity.scl(1 /deltaTime); // Apply damping to the velocity on the x-axis so we don't // walk infinitely once a key was pressed pumma.velocity.x *= Pumma.DAMPING; } //RESAERCH THIS METHOD private void getTiles(int startX, int startY, int endX, int endY, Array<Rectangle> tiles) { TiledMapTileLayer layer = (TiledMapTileLayer) map.getLayers().get(1); //test = (String) layer.getCell(22, 9).getTile().getProperties().get("tileType"); rectPool.freeAll(tiles); tiles.clear(); for (int y = startY; y <= endY; y++) { for (int x = startX; x <= endX; x++) { Cell cell = layer.getCell(x, y); if (cell != null) { Rectangle rect = rectPool.obtain(); rect.set(x, y, 1, 1); tiles.add(rect); } } } } }