Libgdx – Lập trình Game Super Jumper

1. Cấu trúc game

A. Khởi tạo dự án và cấu hình ban đầu

  1. Tạo dự án Libgdx: Sử dụng công cụ setup của Libgdx để tạo một dự án mới với các module cần thiết cho desktop, Android, iOS và HTML5.
  2. Cấu hình dự án: Thiết lập các thông số cơ bản như tên dự án, package, các module tích hợp và các thư viện phụ trợ.

B. Cấu trúc thư mục

core/main: Tôi chia thành các thư mục sau:

  1. Assets.java: Quản lý tài nguyên của trò chơi.
  2. MainSuperJumper.java: Lớp khởi động trò chơi chính.
  3. Settings.java: Quản lý cài đặt trò chơi.
  4. game: Chứa các lớp quản lý logic và render của trò chơi.
    • GameScreen.java: Màn hình chính của trò chơi.
    • WorldGame.java: Quản lý logic của thế giới game.
    • WorldGameRender.java: Chịu trách nhiệm vẽ các đối tượng trong thế giới game lên màn hình.
  5. objetos: Chứa các lớp đại diện cho các đối tượng trong trò chơi.
    • Bullet.java
    • Enemigo.java
    • Item.java
    • Moneda.java
    • Nube.java
    • Personaje.java
    • PiezaPlataformas.java
    • Plataformas.java
    • Rayo.java
  6. scene2d: Chứa các lớp liên quan đến Scene2D.
    • AnimatedSpriteActor.java
    • Ventana.java
    • VentanaGameOver.java
    • VentanaPause.java
  7. screens: Chứa các màn hình khác của trò chơi.
    • MainMenuScreen.java
    • Screens.java

C.Các phần chính của game

MainSuperJumper.java

public class MainSuperJumper extends Game {
	// Các biến dịch vụ và xử lý yêu cầu cần thiết cho trò chơi
	public final GameServicesHandler gameServiceHandler;
	public final RequestHandler reqHandler;
	public final FacebookHandler facebookHandler;

	public I18NBundle idiomas; // Đối tượng cho việc đa ngôn ngữ

	// Constructor nhận các xử lý yêu cầu và dịch vụ trò chơi làm tham số
	public MainSuperJumper(RequestHandler reqHandler, GameServicesHandler gameServiceHandler, FacebookHandler facebookHandler) {
		this.reqHandler = reqHandler;
		this.gameServiceHandler = gameServiceHandler;
		this.facebookHandler = facebookHandler;
	}
	// Các biến thể hiện Stage và SpriteBatch
	public Stage stage;
	public SpriteBatch batcher;

	@Override
	public void create() {
		// idiomas = I18NBundle.createBundle(Gdx.files.internal("strings/strings"));

		// Khởi tạo Stage với kích thước tương thích với màn hình
		stage = new Stage(new StretchViewport(Screens.SCREEN_WIDTH, Screens.SCREEN_HEIGHT));


		// Khởi tạo SpriteBatch để vẽ đồ họa
		batcher = new SpriteBatch();
		// Tải cài đặt trò chơi
		Settings.load();

		// Tải tài nguyên của trò chơi
		Assets.load();
		// Achievements.init(this);

		// Đặt màn hình chính của trò chơi là MainMenuScreen
		setScreen(new MainMenuScreen(this));
	}
}

Quản lý tài nguyên (Assets)

public class Assets {

	public static BitmapFont fontChico;
	public static BitmapFont fontGrande;

	public static AtlasRegion fondo;
	public static TextureRegionDrawable titulo;

	/**
	 * Personaje
	 */
	public static AtlasRegion personajeJump;
	public static AtlasRegion personajeStand;
	public static Animation<TextureRegion> personajeWalk;

	public static AtlasRegion coin;
	public static AtlasRegion gun;
	public static AtlasRegion bullet;
	public static AtlasRegion spring;
	public static AtlasRegion bubbleSmall;
	public static AtlasRegion jetpackSmall;
	public static AtlasRegion bubble;
	public static AtlasRegion jetpack;
	public static Animation<TextureRegion> jetpackFire;

	public static Animation<TextureRegion> enemigo;

	public static AtlasRegion nubeHappy;
	public static AtlasRegion nubeAngry;

	public static Animation<TextureRegion> rayo;
	public static AtlasRegion nubeViento;
	/**
	 * Plataformas
	 */

	public static AtlasRegion plataformaBeige;
	public static AtlasRegion plataformaBeigeLight;
	public static AtlasRegion plataformaBeigeBroken;
	public static AtlasRegion plataformaBeigeLeft;
	public static AtlasRegion plataformaBeigeRight;

	public static AtlasRegion plataformaBlue;
	public static AtlasRegion plataformaBlueLight;
	public static AtlasRegion plataformaBlueBroken;
	public static AtlasRegion plataformaBlueLeft;
	public static AtlasRegion plataformaBlueRight;

	public static AtlasRegion plataformaGray;
	public static AtlasRegion plataformaGrayLight;
	public static AtlasRegion plataformaGrayBroken;
	public static AtlasRegion plataformaGrayLeft;
	public static AtlasRegion plataformaGrayRight;
	public static AtlasRegion plataformaGreen;
	public static AtlasRegion plataformaGreenLight;
	public static AtlasRegion plataformaGreenBroken;
	public static AtlasRegion plataformaGreenLeft;
	public static AtlasRegion plataformaGreenRight;

	public static AtlasRegion plataformaMulticolor;
	public static AtlasRegion plataformaMulticolorLight;
	public static AtlasRegion plataformaMulticolorBroken;
	public static AtlasRegion plataformaMulticolorLeft;
	public static AtlasRegion plataformaMulticolorRight;

	public static AtlasRegion plataformaPink;
	public static AtlasRegion plataformaPinkLight;
	public static AtlasRegion plataformaPinkBroken;
	public static AtlasRegion plataformaPinkLeft;
	public static AtlasRegion plataformaPinkRight;

	public static TextureRegionDrawable btPause;

	public static LabelStyle labelStyleChico;
	public static LabelStyle labelStyleGrande;
	public static TextButtonStyle textButtonStyleGrande;

	public static NinePatchDrawable pixelNegro;

	public static void loadStyles(TextureAtlas atlas) {
		// Label Style
		labelStyleChico = new LabelStyle(fontChico, Color.WHITE);
		labelStyleGrande = new LabelStyle(fontGrande, Color.WHITE);

		TextureRegionDrawable button = new TextureRegionDrawable(atlas.findRegion("button"));
		textButtonStyleGrande = new TextButtonStyle(button, button, null, fontGrande);

		pixelNegro = new NinePatchDrawable(new NinePatch(atlas.findRegion("pixelNegro"), 1, 1, 0, 0));
	}

	public static void load() {
		TextureAtlas atlas = new TextureAtlas(Gdx.files.internal("data/atlasMap.txt"));

		// fontChico = new BitmapFont(Gdx.files.internal("data/fontChico.fnt"), atlas.findRegion("fontChico"));
		fontChico = new BitmapFont(Gdx.files.internal("data/fontGrande.fnt"), atlas.findRegion("fontGrande"));
		fontGrande = new BitmapFont(Gdx.files.internal("data/fontGrande.fnt"), atlas.findRegion("fontGrande"));

		loadStyles(atlas);

		btPause = new TextureRegionDrawable(atlas.findRegion("btPause"));

		fondo = atlas.findRegion("Background");
		titulo = new TextureRegionDrawable(atlas.findRegion("titulo"));

		/**
		 * Personaje
		 */

		personajeJump = atlas.findRegion("personajeJump");
		personajeStand = atlas.findRegion("personajeStand");

		AtlasRegion walk1 = atlas.findRegion("personajeWalk1");
		AtlasRegion walk2 = atlas.findRegion("personajeWalk2");
		personajeWalk = new Animation(.5f, walk1, walk2);

		coin = atlas.findRegion("Coin");
		gun = atlas.findRegion("Pistol");
		bullet = atlas.findRegion("Bullet");
		spring = atlas.findRegion("Spring");
		bubbleSmall = atlas.findRegion("Bubble_Small");
		jetpackSmall = atlas.findRegion("Jetpack_Small");
		bubble = atlas.findRegion("Bubble_Big");
		jetpack = atlas.findRegion("Jetpack_Big");

		AtlasRegion jetpackFire1 = atlas.findRegion("JetFire1");
		AtlasRegion jetpackFire2 = atlas.findRegion("JetFire2");
		jetpackFire = new Animation(.085f, jetpackFire1, jetpackFire2);

		AtlasRegion enemigo1 = atlas.findRegion("HearthEnemy1");
		AtlasRegion enemigo2 = atlas.findRegion("HearthEnemy2");
		enemigo = new Animation(.2f, enemigo1, enemigo2);

		nubeHappy = atlas.findRegion("HappyCloud");
		nubeAngry = atlas.findRegion("AngryCloud");
		nubeViento = atlas.findRegion("CloudWind");

		AtlasRegion lightning1 = atlas.findRegion("Lightning1");
		AtlasRegion lightning2 = atlas.findRegion("Lightning2");
		rayo = new Animation(.08f, lightning1, lightning2);

		/**
		 * Plataformas
		 */

		plataformaBeige = atlas.findRegion("LandPiece_DarkBeige");
		plataformaBeigeLight = atlas.findRegion("LandPiece_LightBeige");
		plataformaBeigeBroken = atlas.findRegion("BrokenLandPiece_Beige");
		plataformaBeigeLeft = atlas.findRegion("HalfLandPiece_Left_Beige");
		plataformaBeigeRight = atlas.findRegion("HalfLandPiece_Right_Beige");

		plataformaBlue = atlas.findRegion("LandPiece_DarkBlue");
		plataformaBlueLight = atlas.findRegion("LandPiece_LightBlue");
		plataformaBlueBroken = atlas.findRegion("BrokenLandPiece_Blue");
		plataformaBlueLeft = atlas.findRegion("HalfLandPiece_Left_Blue");
		plataformaBlueRight = atlas.findRegion("HalfLandPiece_Right_Blue");

		plataformaGray = atlas.findRegion("LandPiece_DarkGray");
		plataformaGrayLight = atlas.findRegion("LandPiece_LightGray");
		plataformaGrayBroken = atlas.findRegion("BrokenLandPiece_Gray");
		plataformaGrayLeft = atlas.findRegion("HalfLandPiece_Left_Gray");
		plataformaGrayRight = atlas.findRegion("HalfLandPiece_Right_Gray");

		plataformaGreen = atlas.findRegion("LandPiece_DarkGreen");
		plataformaGreenLight = atlas.findRegion("LandPiece_LightGreen");
		plataformaGreenBroken = atlas.findRegion("BrokenLandPiece_Green");
		plataformaGreenLeft = atlas.findRegion("HalfLandPiece_Left_Green");
		plataformaGreenRight = atlas.findRegion("HalfLandPiece_Right_Green");

		plataformaMulticolor = atlas.findRegion("LandPiece_DarkMulticolored");
		plataformaMulticolorLight = atlas.findRegion("LandPiece_LightMulticolored");
		plataformaMulticolorBroken = atlas.findRegion("BrokenLandPiece_Multicolored");
		plataformaMulticolorLeft = atlas.findRegion("HalfLandPiece_Left_Multicolored");
		plataformaMulticolorRight = atlas.findRegion("HalfLandPiece_Right_Multicolored");

		plataformaPink = atlas.findRegion("LandPiece_DarkPink");
		plataformaPinkLight = atlas.findRegion("LandPiece_LightPink");
		plataformaPinkBroken = atlas.findRegion("BrokenLandPiece_Pink");
		plataformaPinkLeft = atlas.findRegion("HalfLandPiece_Left_Pink");
		plataformaPinkRight = atlas.findRegion("HalfLandPiece_Right_Pink");

	}
}

Settings.java

public class Settings {

	public final static int NUM_GEMS_SHARE_FACEBOOK = 250;
	public final static int NUM_GEMS_INVITE_FACEBOOK = 50;

	public static boolean isMusicOn;
	public static boolean isSoundOn;

	public static boolean didBuyNoAds;
	public static boolean didLikeFacebook;
	public static boolean didRate;

	public static int numeroVecesJugadas;

	public static int coinsTotal;
	public static int numBullets;

	public static int bestScore;

	public static int LEVEL_LIFE;
	public static int LEVEL_SHIELD;
	public static int LEVEL_SECOND_JUMP;
	public static int LEVEL_WEAPON;

	private final static Preferences pref = Gdx.app.getPreferences("com.nopalsoft.superjumper");

	public static void save() {	pref.putBoolean("isMusicOn", isMusicOn);
		pref.putBoolean("isSoundOn", isSoundOn);

		pref.putBoolean("didBuyNoAds", didBuyNoAds);
		pref.putBoolean("didLikeFacebook", didLikeFacebook);
		pref.putBoolean("didRate", didRate);

		pref.putInteger("numeroVecesJugadas", numeroVecesJugadas);
		pref.putInteger("coinsTotal", coinsTotal);
		pref.putInteger("numBullets", numBullets);
		pref.putInteger("bestScore", bestScore);

		pref.putInteger("LEVEL_WEAPON", LEVEL_WEAPON);
		pref.putInteger("LEVEL_SECOND_JUMP", LEVEL_SECOND_JUMP);
		pref.putInteger("LEVEL_LIFE", LEVEL_LIFE);
		pref.putInteger("LEVEL_SHIELD", LEVEL_SHIELD);



		pref.flush();

	}

	public static void load() {

		isMusicOn = pref.getBoolean("isMusicOn", true);
		isSoundOn = pref.getBoolean("isSoundOn", true);

		didBuyNoAds = pref.getBoolean("didBuyNoAds", false);
		didLikeFacebook = pref.getBoolean("didLikeFacebook", false);
		didRate = pref.getBoolean("didRate", false);

		numeroVecesJugadas = pref.getInteger("numeroVecesJugadas", 0);

		coinsTotal = pref.getInteger("coinsTotal", 0);
		numBullets = pref.getInteger("numBullets", 30);
		bestScore = pref.getInteger("bestScore", 0);

		LEVEL_WEAPON = pref.getInteger("LEVEL_WEAPON", 0);
		LEVEL_SECOND_JUMP = pref.getInteger("LEVEL_SECOND_JUMP", 0);
		LEVEL_LIFE = pref.getInteger("LEVEL_LIFE", 0);
		LEVEL_SHIELD = pref.getInteger("LEVEL_SHIELD", 0);

	}

	public static void setBestScore(int distance) {
		if (bestScore < distance) {
			bestScore = distance;
			save();
		}

	}

}

GameScreen.java

public class GameScreen extends Screens {

	// Các trạng thái của màn hình game
	static final int STATE_RUNNING = 2;
	static final int STATE_PAUSED = 3;
	static final int STATE_GAME_OVER = 4;
	static int state;

	public WorldGame oWorld;
	WorldGameRender renderer;

	Vector3 touchPositionWorldCoords;
	boolean didFire;

	Label lbDistancia, lbMonedas, lbBullets;

	Button btPause;

	VentanaPause ventanPause;

	public GameScreen(MainSuperJumper game) {
		super(game);

		// Khởi tạo các thành phần UI và thực thể trong màn hình chơi game
		ventanPause = new VentanaPause(this);

		oWorld = new WorldGame();
		renderer = new WorldGameRender(batcher, oWorld);
		touchPositionWorldCoords = new Vector3();

		// Thiết lập trạng thái ban đầu của màn hình game
		state = STATE_RUNNING;
		Settings.numeroVecesJugadas++;

		// Tạo bảng điều khiển hiển thị điểm và thông tin khác
		Table menuMarcador = new Table();
		menuMarcador.setSize(SCREEN_WIDTH, 40);
		menuMarcador.setY(SCREEN_HEIGHT - menuMarcador.getHeight());

		lbMonedas = new Label("", Assets.labelStyleGrande);
		lbDistancia = new Label("", Assets.labelStyleGrande);
		lbBullets = new Label("", Assets.labelStyleGrande);

		menuMarcador.add(new Image(new TextureRegionDrawable(Assets.coin))).left().padLeft(5);
		menuMarcador.add(lbMonedas).left();

		menuMarcador.add(lbDistancia).center().expandX();

		menuMarcador.add(new Image(new TextureRegionDrawable(Assets.gun))).height(45).width(30).left();
		menuMarcador.add(lbBullets).left().padRight(5);

		// Tạo nút pause
		btPause = new Button(Assets.btPause);
		btPause.setSize(35, 35);
		btPause.setPosition(SCREEN_WIDTH - 40, SCREEN_HEIGHT - 80);
		addEfectoPress(btPause); // Thêm hiệu ứng khi nút được nhấn
		btPause.addListener(new ClickListener() {
			@Override
			public void clicked(InputEvent event, float x, float y) {
				setPaused(); // Gọi hàm tạm dừng khi nút được nhấn
			}
		});

		// Thêm các thành phần UI vào Stage
		stage.addActor(menuMarcador);
		stage.addActor(btPause);

	}

	// Cập nhật logic game
	@Override
	public void update(float delta) {
		switch (state) {
			case STATE_RUNNING:
				updateRunning(delta);
				break;
			case STATE_GAME_OVER:
				updateGameOver(delta);
				break;
		}
	}

	private void updateRunning(float delta) {
		// Cập nhật các thông số trong trạng thái chạy game
		float acelX = 0;

		acelX = -(Gdx.input.getAccelerometerX() / 3f);

		if (Gdx.input.isKeyPressed(Keys.A))
			acelX = -1;
		else if (Gdx.input.isKeyPressed(Keys.D))
			acelX = 1;

		oWorld.update(delta, acelX, didFire, touchPositionWorldCoords);

		lbMonedas.setText("x" + oWorld.coins);
		lbDistancia.setText("Score " + oWorld.distanciaMax);
		lbBullets.setText("x" + Settings.numBullets);

		if (oWorld.state == WorldGame.STATE_GAMEOVER) {
			setGameover();
		}

		didFire = false;
	}

	private void updateGameOver(float delta) {
		oWorld.update(delta, 0, false, touchPositionWorldCoords);
	}

	// Vẽ đồ họa
	@Override
	public void draw(float delta) {
		// Vẽ nền và các thành phần game
		batcher.begin();
		batcher.draw(Assets.fondo, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
		batcher.end();

		// Nếu không trong trạng thái tạm dừng, vẽ các đối tượng game
		if (state != STATE_PAUSED) {
			renderer.render(delta);
		}
	}

	// Hàm tạm dừng game
	private void setPaused() {
		if (state == STATE_RUNNING) {
			state = STATE_PAUSED;
			ventanPause.show(stage);
		}
	}

	// Hàm khi game đang chạy
	public void setRunning() {
		state = STATE_RUNNING;
	}

	// Hàm khi game kết thúc
	private void setGameover() {
		state = STATE_GAME_OVER;
		Settings.setBestScore(oWorld.distanciaMax);
		game.gameServiceHandler.submitScore(oWorld.distanciaMax);
		new VentanaGameover(this).show(stage);
	}

	// Ẩn màn hình game
	@Override
	public void hide() {
		if (Settings.numeroVecesJugadas % 7 == 0)
			game.reqHandler.showInterstitial();
		super.hide();
	}

	// Xử lý sự kiện khi người chơi chạm vào màn hình
	@Override
	public boolean touchDown(int screenX, int screenY, int pointer, int button) {
		touchPositionWorldCoords.set(screenX, 0, 0);
		renderer.unprojectToWorldCoords(touchPositionWorldCoords);

		didFire = true;
		return false;
	}

	// Xử lý sự kiện khi người chơi nhấn phím
	@Override
	public boolean keyDown(int keycode) {
		if (keycode == Keys.ESCAPE || keycode == Keys.BACK) {
			if (ventanPause.isVisible())
				ventanPause.hide();
			else
				setPaused();
			return true;
		}
		return super.keyDown(keycode);
	}

}

WorldGame.java

public class WorldGame {
	final float WIDTH = Screens.WORLD_WIDTH;
	final float HEIGHT = Screens.WORLD_HEIGHT;

	final public static int STATE_RUNNING = 0;
	final public static int STATE_GAMEOVER = 1;
	int state;

	float TIME_TO_CREATE_NUBE = 15;
	float timeToCreateNube;

	public World oWorldBox;

	Personaje oPer;
	private Array<Body> arrBodies;
	Array<Plataformas> arrPlataformas;
	Array<PiezaPlataformas> arrPiezasPlataformas;
	Array<Moneda> arrMonedas;
	Array<Enemigo> arrEnemigo;
	Array<Item> arrItem;
	Array<Nube> arrNubes;
	Array<Rayo> arrRayos;
	Array<Bullet> arrBullets;

	public int coins;
	public int distanciaMax;
	float mundoCreadoHastaY;

	public WorldGame() {
		oWorldBox = new World(new Vector2(0, -9.8f), true);
		oWorldBox.setContactListener(new Colisiones());

		arrBodies = new Array<Body>();
		arrPlataformas = new Array<Plataformas>();
		arrPiezasPlataformas = new Array<PiezaPlataformas>();
		arrMonedas = new Array<Moneda>();
		arrEnemigo = new Array<Enemigo>();
		arrItem = new Array<Item>();
		arrNubes = new Array<Nube>();
		arrRayos = new Array<Rayo>();
		arrBullets = new Array<Bullet>();

		timeToCreateNube = 0;

		state = STATE_RUNNING;

		crearPiso();
		crearPersonaje();

		mundoCreadoHastaY = oPer.position.y;
		crearSiguienteParte();

	}

	private void crearSiguienteParte() {
		float y = mundoCreadoHastaY + 2;

		for (int i = 0; mundoCreadoHastaY < (y + 10); i++) {
			mundoCreadoHastaY = y + (i * 2);

			crearPlataforma(mundoCreadoHastaY);
			crearPlataforma(mundoCreadoHastaY);

			if (MathUtils.random(100) < 5)
				Moneda.createMoneda(oWorldBox, arrMonedas, mundoCreadoHastaY);

			if (MathUtils.random(20) < 5)
				Moneda.createUnaMoneda(oWorldBox, arrMonedas, mundoCreadoHastaY + .5f);

			if (MathUtils.random(20) < 5)
				crearEnemigo(mundoCreadoHastaY + .5f);

			if (timeToCreateNube >= TIME_TO_CREATE_NUBE) {
				crearNubes(mundoCreadoHastaY + .7f);
				timeToCreateNube = 0;
			}

			if (MathUtils.random(50) < 5)
				createItem(mundoCreadoHastaY + .5f);
		}

	}

	/**
	 * El piso solo aparece 1 vez, al principio del juego
	 */
	private void crearPiso() {
		BodyDef bd = new BodyDef();
		bd.type = BodyType.StaticBody;

		Body body = oWorldBox.createBody(bd);

		EdgeShape shape = new EdgeShape();
		shape.set(0, 0, Screens.WORLD_WIDTH, 0);

		FixtureDef fixutre = new FixtureDef();
		fixutre.shape = shape;

		body.createFixture(fixutre);
		body.setUserData("piso");

		shape.dispose();

	}

	private void crearPersonaje() {
		oPer = new Personaje(2.4f, .5f);

		BodyDef bd = new BodyDef();
		bd.position.set(oPer.position.x, oPer.position.y);
		bd.type = BodyType.DynamicBody;

		Body body = oWorldBox.createBody(bd);

		PolygonShape shape = new PolygonShape();
		shape.setAsBox(Personaje.WIDTH / 2f, Personaje.HEIGTH / 2f);

		FixtureDef fixutre = new FixtureDef();
		fixutre.shape = shape;
		fixutre.density = 10;
		fixutre.friction = 0;
		fixutre.restitution = 0;

		body.createFixture(fixutre);
		body.setUserData(oPer);
		body.setFixedRotation(true);

		shape.dispose();
	}

	private void crearPlataforma(float y) {

		Plataformas oPlat = Pools.obtain(Plataformas.class);
		oPlat.init(MathUtils.random(Screens.WORLD_WIDTH), y, MathUtils.random(1));

		BodyDef bd = new BodyDef();
		bd.position.set(oPlat.position.x, oPlat.position.y);
		bd.type = BodyType.KinematicBody;

		Body body = oWorldBox.createBody(bd);

		PolygonShape shape = new PolygonShape();
		shape.setAsBox(Plataformas.WIDTH_NORMAL / 2f, Plataformas.HEIGTH_NORMAL / 2f);

		FixtureDef fixutre = new FixtureDef();
		fixutre.shape = shape;

		body.createFixture(fixutre);
		body.setUserData(oPlat);
		arrPlataformas.add(oPlat);

		shape.dispose();

	}

	/**
	 * La plataforma rompible son 2 cuadros
	 * 
	 * @param i
	 */
	private void crearPiezasPlataforma(Plataformas oPlat) {
		crearPiezasPlataforma(oPlat, PiezaPlataformas.TIPO_LEFT);
		crearPiezasPlataforma(oPlat, PiezaPlataformas.TIPO_RIGHT);

	}

	private void crearPiezasPlataforma(Plataformas oPla, int tipo) {
		PiezaPlataformas oPieza;
		float x;
		float angularVelocity = 100;

		if (tipo == PiezaPlataformas.TIPO_LEFT) {
			x = oPla.position.x - PiezaPlataformas.WIDTH_NORMAL / 2f;
			angularVelocity *= -1;
		}
		else {
			x = oPla.position.x + PiezaPlataformas.WIDTH_NORMAL / 2f;
		}

		oPieza = Pools.obtain(PiezaPlataformas.class);
		oPieza.init(x, oPla.position.y, tipo, oPla.color);

		BodyDef bd = new BodyDef();
		bd.position.set(oPieza.position.x, oPieza.position.y);
		bd.type = BodyType.DynamicBody;

		Body body = oWorldBox.createBody(bd);

		PolygonShape shape = new PolygonShape();
		shape.setAsBox(PiezaPlataformas.WIDTH_NORMAL / 2f, PiezaPlataformas.HEIGTH_NORMAL / 2f);

		FixtureDef fixutre = new FixtureDef();
		fixutre.shape = shape;
		fixutre.isSensor = true;

		body.createFixture(fixutre);
		body.setUserData(oPieza);
		body.setAngularVelocity(MathUtils.degRad * angularVelocity);
		arrPiezasPlataformas.add(oPieza);

		shape.dispose();
	}

	private void crearEnemigo(float y) {
		Enemigo oEn = Pools.obtain(Enemigo.class);
		oEn.init(MathUtils.random(Screens.WORLD_WIDTH), y);

		BodyDef bd = new BodyDef();
		bd.position.set(oEn.position.x, oEn.position.y);
		bd.type = BodyType.DynamicBody;

		Body body = oWorldBox.createBody(bd);

		PolygonShape shape = new PolygonShape();
		shape.setAsBox(Enemigo.WIDTH / 2f, Enemigo.HEIGHT / 2f);

		FixtureDef fixutre = new FixtureDef();
		fixutre.shape = shape;
		fixutre.isSensor = true;

		body.createFixture(fixutre);
		body.setUserData(oEn);
		body.setGravityScale(0);

		float velocidad = MathUtils.random(1f, Enemigo.VELOCIDAD_X);

		if (MathUtils.randomBoolean())
			body.setLinearVelocity(velocidad, 0);
		else
			body.setLinearVelocity(-velocidad, 0);
		arrEnemigo.add(oEn);

		shape.dispose();
	}

	private void createItem(float y) {
		Item oItem = Pools.obtain(Item.class);
		oItem.init(MathUtils.random(Screens.WORLD_WIDTH), y);

		BodyDef bd = new BodyDef();
		bd.position.set(oItem.position.x, oItem.position.y);
		bd.type = BodyType.StaticBody;
		Body oBody = oWorldBox.createBody(bd);

		PolygonShape shape = new PolygonShape();
		shape.setAsBox(Item.WIDTH / 2f, Item.HEIGHT / 2f);

		FixtureDef fixture = new FixtureDef();
		fixture.shape = shape;
		fixture.isSensor = true;
		oBody.createFixture(fixture);
		oBody.setUserData(oItem);
		shape.dispose();
		arrItem.add(oItem);
	}

	private void crearNubes(float y) {
		Nube oNube = Pools.obtain(Nube.class);
		oNube.init(MathUtils.random(Screens.WORLD_WIDTH), y);

		BodyDef bd = new BodyDef();
		bd.position.set(oNube.position.x, oNube.position.y);
		bd.type = BodyType.DynamicBody;

		Body body = oWorldBox.createBody(bd);

		PolygonShape shape = new PolygonShape();
		shape.setAsBox(Nube.WIDTH / 2f, Nube.HEIGHT / 2f);

		FixtureDef fixutre = new FixtureDef();
		fixutre.shape = shape;
		fixutre.isSensor = true;

		body.createFixture(fixutre);
		body.setUserData(oNube);
		body.setGravityScale(0);

		float velocidad = MathUtils.random(1f, Nube.VELOCIDAD_X);

		if (MathUtils.randomBoolean())
			body.setLinearVelocity(velocidad, 0);
		else
			body.setLinearVelocity(-velocidad, 0);
		arrNubes.add(oNube);

		shape.dispose();
	}

	private void crearRayo(float x, float y) {
		Rayo oRayo = Pools.obtain(Rayo.class);
		oRayo.init(x, y);

		BodyDef bd = new BodyDef();
		bd.position.set(oRayo.position.x, oRayo.position.y);
		bd.type = BodyType.KinematicBody;

		Body body = oWorldBox.createBody(bd);

		PolygonShape shape = new PolygonShape();
		shape.setAsBox(Rayo.WIDTH / 2f, Rayo.HEIGHT / 2f);

		FixtureDef fixutre = new FixtureDef();
		fixutre.shape = shape;
		fixutre.isSensor = true;

		body.createFixture(fixutre);
		body.setUserData(oRayo);

		body.setLinearVelocity(0, Rayo.VELOCIDAD_Y);
		arrRayos.add(oRayo);

		shape.dispose();
	}

	private void crearBullet(float origenX, float origenY, float destinoX, float destinoY) {
		Bullet oBullet = Pools.obtain(Bullet.class);
		oBullet.init(origenX, origenY);

		BodyDef bd = new BodyDef();
		bd.position.set(oBullet.position.x, oBullet.position.y);
		bd.type = BodyType.KinematicBody;

		Body body = oWorldBox.createBody(bd);

		PolygonShape shape = new PolygonShape();
		shape.setAsBox(Bullet.SIZE / 2f, Bullet.SIZE / 2f);

		FixtureDef fixutre = new FixtureDef();
		fixutre.shape = shape;
		fixutre.isSensor = true;

		body.createFixture(fixutre);
		body.setUserData(oBullet);
		body.setBullet(true);

		Vector2 destino = new Vector2(destinoX, destinoY);
		destino.sub(oBullet.position).nor().scl(Bullet.VELOCIDAD_XY);

		body.setLinearVelocity(destino.x, destino.y);

		arrBullets.add(oBullet);

		shape.dispose();
	}

	public void update(float delta, float acelX, boolean fire, Vector3 touchPositionWorldCoords) {
		oWorldBox.step(delta, 8, 4);

		eliminarObjetos();

		/**
		 * REviso si es necesario generar la siquiete parte del mundo
		 */
		if (oPer.position.y + 10 > mundoCreadoHastaY) {
			crearSiguienteParte();
		}

		timeToCreateNube += delta;// Actualizo el tiempo para crear una nube

		oWorldBox.getBodies(arrBodies);
		Iterator<Body> i = arrBodies.iterator();

		while (i.hasNext()) {
			Body body = i.next();
			if (body.getUserData() instanceof Personaje) {
				updatePersonaje(body, delta, acelX, fire, touchPositionWorldCoords);
			}
			else if (body.getUserData() instanceof Plataformas) {
				updatePlataforma(body, delta);
			}
			else if (body.getUserData() instanceof PiezaPlataformas) {
				updatePiezaPlataforma(body, delta);
			}
			else if (body.getUserData() instanceof Moneda) {
				updateMoneda(body, delta);
			}
			else if (body.getUserData() instanceof Enemigo) {
				updateEnemigo(body, delta);
			}
			else if (body.getUserData() instanceof Item) {
				updateItem(body, delta);
			}
			else if (body.getUserData() instanceof Nube) {
				updateNube(body, delta);
			}
			else if (body.getUserData() instanceof Rayo) {
				updateRayo(body, delta);
			}
			else if (body.getUserData() instanceof Bullet) {
				updateBullet(body, delta);
			}

		}

		if (distanciaMax < (oPer.position.y * 10)) {
			distanciaMax = (int) (oPer.position.y * 10);
		}

		// Si el personaje esta 5.5f mas abajo de la altura maxima se muere (Se multiplica por 10 porque la distancia se multiplica por 10 )
		if (oPer.state == Personaje.STATE_NORMAL && distanciaMax - (5.5f * 10) > (oPer.position.y * 10)) {
			oPer.die();
		}
		if (oPer.state == Personaje.STATE_DEAD && distanciaMax - (25 * 10) > (oPer.position.y * 10)) {
			state = STATE_GAMEOVER;
		}

	}

	private void eliminarObjetos() {
		oWorldBox.getBodies(arrBodies);
		Iterator<Body> i = arrBodies.iterator();

		while (i.hasNext()) {
			Body body = i.next();

			if (!oWorldBox.isLocked()) {

				if (body.getUserData() instanceof Plataformas) {
					Plataformas oPlat = (Plataformas) body.getUserData();
					if (oPlat.state == Plataformas.STATE_DESTROY) {
						arrPlataformas.removeValue(oPlat, true);
						oWorldBox.destroyBody(body);
						if (oPlat.tipo == Plataformas.TIPO_ROMPIBLE)
							crearPiezasPlataforma(oPlat);
						Pools.free(oPlat);
					}
				}
				else if (body.getUserData() instanceof Moneda) {
					Moneda oMon = (Moneda) body.getUserData();
					if (oMon.state == Moneda.STATE_TAKEN) {
						arrMonedas.removeValue(oMon, true);
						oWorldBox.destroyBody(body);
						Pools.free(oMon);
					}
				}
				else if (body.getUserData() instanceof PiezaPlataformas) {
					PiezaPlataformas oPiez = (PiezaPlataformas) body.getUserData();
					if (oPiez.state == PiezaPlataformas.STATE_DESTROY) {
						arrPiezasPlataformas.removeValue(oPiez, true);
						oWorldBox.destroyBody(body);
						Pools.free(oPiez);
					}
				}
				else if (body.getUserData() instanceof Enemigo) {
					Enemigo oEnemy = (Enemigo) body.getUserData();
					if (oEnemy.state == Enemigo.STATE_DEAD) {
						arrEnemigo.removeValue(oEnemy, true);
						oWorldBox.destroyBody(body);
						Pools.free(oEnemy);
					}
				}
				else if (body.getUserData() instanceof Item) {
					Item oItem = (Item) body.getUserData();
					if (oItem.state == Item.STATE_TAKEN) {
						arrItem.removeValue(oItem, true);
						oWorldBox.destroyBody(body);
						Pools.free(oItem);
					}
				}
				else if (body.getUserData() instanceof Nube) {
					Nube oNube = (Nube) body.getUserData();
					if (oNube.state == Nube.STATE_DEAD) {
						arrNubes.removeValue(oNube, true);
						oWorldBox.destroyBody(body);
						Pools.free(oNube);
					}
				}
				else if (body.getUserData() instanceof Rayo) {
					Rayo oRayo = (Rayo) body.getUserData();
					if (oRayo.state == Rayo.STATE_DESTROY) {
						arrRayos.removeValue(oRayo, true);
						oWorldBox.destroyBody(body);
						Pools.free(oRayo);
					}
				}
				else if (body.getUserData() instanceof Bullet) {
					Bullet oBullet = (Bullet) body.getUserData();
					if (oBullet.state == Bullet.STATE_DESTROY) {
						arrBullets.removeValue(oBullet, true);
						oWorldBox.destroyBody(body);
						Pools.free(oBullet);
					}
				}
				else if (body.getUserData().equals("piso")) {
					if (oPer.position.y - 5.5f > body.getPosition().y || oPer.state == Personaje.STATE_DEAD) {
						oWorldBox.destroyBody(body);
					}
				}
			}
		}
	}

	private void updatePersonaje(Body body, float delta, float acelX, boolean fire, Vector3 touchPositionWorldCoords) {
		oPer.update(body, delta, acelX);

		if (Settings.numBullets > 0 && fire) {
			crearBullet(oPer.position.x, oPer.position.y, touchPositionWorldCoords.x, touchPositionWorldCoords.y);
			Settings.numBullets--;

		}

	}

	private void updatePlataforma(Body body, float delta) {
		Plataformas obj = (Plataformas) body.getUserData();
		obj.update(delta);
		if (oPer.position.y - 5.5f > obj.position.y) {
			obj.setDestroy();
		}
	}

	private void updatePiezaPlataforma(Body body, float delta) {
		PiezaPlataformas obj = (PiezaPlataformas) body.getUserData();
		obj.update(delta, body);
		if (oPer.position.y - 5.5f > obj.position.y) {
			obj.setDestroy();
		}

	}

	private void updateMoneda(Body body, float delta) {
		Moneda obj = (Moneda) body.getUserData();
		obj.update(delta);
		if (oPer.position.y - 5.5f > obj.position.y) {
			obj.take();
		}

	}

	private void updateEnemigo(Body body, float delta) {
		Enemigo obj = (Enemigo) body.getUserData();
		obj.update(body, delta);
		if (oPer.position.y - 5.5f > obj.position.y) {
			obj.hit();
		}

	}

	private void updateItem(Body body, float delta) {
		Item obj = (Item) body.getUserData();
		obj.update(delta);
		if (oPer.position.y - 5.5f > obj.position.y) {
			obj.take();
		}
	}

	private void updateNube(Body body, float delta) {
		Nube obj = (Nube) body.getUserData();
		obj.update(body, delta);

		if (obj.isLighthing) {
			crearRayo(obj.position.x, obj.position.y - .65f);
			obj.fireLighting();
		}

		if (oPer.position.y - 5.5f > obj.position.y) {
			obj.destroy();
		}
	}

	private void updateRayo(Body body, float delta) {
		Rayo obj = (Rayo) body.getUserData();
		obj.update(body, delta);

		if (oPer.position.y - 5.5f > obj.position.y) {
			obj.destroy();
		}
	}

	private void updateBullet(Body body, float delta) {
		Bullet obj = (Bullet) body.getUserData();
		obj.update(body, delta);

		if (oPer.position.y - 5.5f > obj.position.y) {
			obj.destroy();
		}
	}

	class Colisiones implements ContactListener {

		@Override
		public void beginContact(Contact contact) {
			Fixture a = contact.getFixtureA();
			Fixture b = contact.getFixtureB();

			if (a.getBody().getUserData() instanceof Personaje)
				beginContactPersonaje(a, b);
			else if (b.getBody().getUserData() instanceof Personaje)
				beginContactPersonaje(b, a);

			if (a.getBody().getUserData() instanceof Bullet)
				beginContactBullet(a, b);
			else if (b.getBody().getUserData() instanceof Bullet)
				beginContactBullet(b, a);

		}

		private void beginContactPersonaje(Fixture fixPersonaje, Fixture fixOtraCosa) {
			Object otraCosa = fixOtraCosa.getBody().getUserData();

			if (otraCosa.equals("piso")) {
				oPer.jump();

				if (oPer.state == Personaje.STATE_DEAD) {
					state = STATE_GAMEOVER;
				}
			}
			else if (otraCosa instanceof Plataformas) {
				Plataformas obj = (Plataformas) otraCosa;

				if (oPer.velocidad.y <= 0) {
					oPer.jump();
					if (obj.tipo == Plataformas.TIPO_ROMPIBLE) {
						obj.setDestroy();
					}
				}

			}
			else if (otraCosa instanceof Moneda) {
				Moneda obj = (Moneda) otraCosa;
				obj.take();
				coins++;
				oPer.jump();
			}
			else if (otraCosa instanceof Enemigo) {
				oPer.hit();
			}
			else if (otraCosa instanceof Rayo) {
				oPer.hit();
			}
			else if (otraCosa instanceof Item) {
				Item obj = (Item) otraCosa;
				obj.take();

				switch (obj.tipo) {
				case Item.TIPO_BUBBLE:
					oPer.setBubble();
					break;
				case Item.TIPO_JETPACK:
					oPer.setJetPack();
					break;
				case Item.TIPO_GUN:
					Settings.numBullets += 10;
					break;

				}

			}

		}

		private void beginContactBullet(Fixture fixBullet, Fixture fixOtraCosa) {
			Object otraCosa = fixOtraCosa.getBody().getUserData();
			Bullet oBullet = (Bullet) fixBullet.getBody().getUserData();

			if (otraCosa instanceof Enemigo) {
				Enemigo obj = (Enemigo) otraCosa;
				obj.hit();
				oBullet.destroy();

			}

			else if (otraCosa instanceof Nube) {
				Nube obj = (Nube) otraCosa;
				obj.hit();
				oBullet.destroy();

			}
		}

		@Override
		public void endContact(Contact contact) {

		}

		@Override
		public void preSolve(Contact contact, Manifold oldManifold) {
			Fixture a = contact.getFixtureA();
			Fixture b = contact.getFixtureB();

			if (a.getBody().getUserData() instanceof Personaje)
				preSolveHero(a, b, contact);
			else if (b.getBody().getUserData() instanceof Personaje)
				preSolveHero(b, a, contact);

		}

		private void preSolveHero(Fixture fixPersonaje, Fixture otraCosa, Contact contact) {
			Object oOtraCosa = otraCosa.getBody().getUserData();

			if (oOtraCosa instanceof Plataformas) {
				// Si va para arriba atraviesa la plataforma

				Plataformas obj = (Plataformas) oOtraCosa;

				float ponyY = fixPersonaje.getBody().getPosition().y - .30f;
				float pisY = obj.position.y + Plataformas.HEIGTH_NORMAL / 2f;

				if (ponyY < pisY)
					contact.setEnabled(false);

				if (obj.tipo == Plataformas.TIPO_NORMAL && oPer.state == Personaje.STATE_DEAD) {
					contact.setEnabled(false);
				}

			}

		}

		@Override
		public void postSolve(Contact contact, ContactImpulse impulse) {
			// TODO Auto-generated method stub

		}

	}

}

WorldGameRender.java

public class WorldGameRender {
	final float WIDTH = Screens.WORLD_WIDTH;
	final float HEIGHT = Screens.WORLD_HEIGHT;

	WorldGame oWorld;
	SpriteBatch batcher;
	OrthographicCamera oCam;
	Box2DDebugRenderer boxRender;

	public WorldGameRender(SpriteBatch batcher, WorldGame oWorld) {
		this.oWorld = oWorld;
		this.batcher = batcher;

		oCam = new OrthographicCamera(WIDTH, HEIGHT);
		oCam.position.set(WIDTH / 2f, HEIGHT / 2f, 0);

		boxRender = new Box2DDebugRenderer();
	}

	public void unprojectToWorldCoords(Vector3 touchPoint) {
		oCam.unproject(touchPoint);
	}

	public void render(float delta) {
		if (oWorld.state == WorldGame.STATE_RUNNING)
			oCam.position.y = oWorld.oPer.position.y;

		if (oCam.position.y < Screens.WORLD_HEIGHT / 2f) {
			oCam.position.y = Screens.WORLD_HEIGHT / 2f;
		}

		oCam.update();
		batcher.setProjectionMatrix(oCam.combined);

		batcher.begin();

		renderPersonaje();
		renderPlataformas();
		renderPiezasPlataformas();
		renderCoins();
		renderItems();
		renderEnemigo();
		renderNube();
		renderRayo();
		renderBullet();

		batcher.end();

		// boxRender.render(oWorld.oWorldBox, oCam.combined);

	}

	private void renderPersonaje() {
		AtlasRegion keyframe = null;

		Personaje obj = oWorld.oPer;

		if (obj.velocidad.y > 0)
			keyframe = Assets.personajeJump;
		else
			keyframe = Assets.personajeStand;

		if (obj.velocidad.x > 0)
			batcher.draw(keyframe, obj.position.x + Personaje.DRAW_WIDTH / 2f, obj.position.y - Personaje.DRAW_HEIGTH / 2f,
					-Personaje.DRAW_WIDTH / 2f, Personaje.DRAW_HEIGTH / 2f, -Personaje.DRAW_WIDTH, Personaje.DRAW_HEIGTH, 1, 1, obj.angleDeg);

		else
			batcher.draw(keyframe, obj.position.x - Personaje.DRAW_WIDTH / 2f, obj.position.y - Personaje.DRAW_HEIGTH / 2f,
					Personaje.DRAW_WIDTH / 2f, Personaje.DRAW_HEIGTH / 2f, Personaje.DRAW_WIDTH, Personaje.DRAW_HEIGTH, 1, 1, obj.angleDeg);

		if (obj.isJetPack) {
			batcher.draw(Assets.jetpack, obj.position.x - .45f / 2f, obj.position.y - .7f / 2f, .45f, .7f);

			TextureRegion fireFrame = Assets.jetpackFire.getKeyFrame(obj.durationJetPack, true);
			batcher.draw(fireFrame, obj.position.x - .35f / 2f, obj.position.y - .95f, .35f, .6f);

		}
		if (obj.isBubble) {
			batcher.draw(Assets.bubble, obj.position.x - .5f, obj.position.y - .5f, 1, 1);
		}

	}

	private void renderPlataformas() {
		Iterator<Plataformas> i = oWorld.arrPlataformas.iterator();
		while (i.hasNext()) {
			Plataformas obj = i.next();

			AtlasRegion keyframe = null;

			if (obj.tipo == Plataformas.TIPO_ROMPIBLE) {
				switch (obj.color) {
				case Plataformas.COLOR_BEIGE:
					keyframe = Assets.plataformaBeigeBroken;
					break;
				case Plataformas.COLOR_BLUE:
					keyframe = Assets.plataformaBlueBroken;
					break;
				case Plataformas.COLOR_GRAY:
					keyframe = Assets.plataformaGrayBroken;
					break;
				case Plataformas.COLOR_GREEN:
					keyframe = Assets.plataformaGreenBroken;
					break;
				case Plataformas.COLOR_MULTICOLOR:
					keyframe = Assets.plataformaMulticolorBroken;
					break;
				case Plataformas.COLOR_PINK:
					keyframe = Assets.plataformaPinkBroken;
					break;

				}
			}
			else {
				switch (obj.color) {
				case Plataformas.COLOR_BEIGE:
					keyframe = Assets.plataformaBeige;
					break;
				case Plataformas.COLOR_BLUE:
					keyframe = Assets.plataformaBlue;
					break;
				case Plataformas.COLOR_GRAY:
					keyframe = Assets.plataformaGray;
					break;
				case Plataformas.COLOR_GREEN:
					keyframe = Assets.plataformaGreen;
					break;
				case Plataformas.COLOR_MULTICOLOR:
					keyframe = Assets.plataformaMulticolor;
					break;
				case Plataformas.COLOR_PINK:
					keyframe = Assets.plataformaPink;
					break;
				case Plataformas.COLOR_BEIGE_LIGHT:
					keyframe = Assets.plataformaBeigeLight;
					break;
				case Plataformas.COLOR_BLUE_LIGHT:
					keyframe = Assets.plataformaBlueLight;
					break;
				case Plataformas.COLOR_GRAY_LIGHT:
					keyframe = Assets.plataformaGrayLight;
					break;
				case Plataformas.COLOR_GREEN_LIGHT:
					keyframe = Assets.plataformaGreenLight;
					break;
				case Plataformas.COLOR_MULTICOLOR_LIGHT:
					keyframe = Assets.plataformaMulticolorLight;
					break;
				case Plataformas.COLOR_PINK_LIGHT:
					keyframe = Assets.plataformaPinkLight;
					break;
				}

			}
			batcher.draw(keyframe, obj.position.x - Plataformas.DRAW_WIDTH_NORMAL / 2f, obj.position.y - Plataformas.DRAW_HEIGTH_NORMAL / 2f,
					Plataformas.DRAW_WIDTH_NORMAL, Plataformas.DRAW_HEIGTH_NORMAL);
		}
	}

	private void renderPiezasPlataformas() {
		Iterator<PiezaPlataformas> i = oWorld.arrPiezasPlataformas.iterator();
		while (i.hasNext()) {
			PiezaPlataformas obj = i.next();

			AtlasRegion keyframe = null;

			if (obj.tipo == PiezaPlataformas.TIPO_LEFT) {
				switch (obj.color) {
				case Plataformas.COLOR_BEIGE:
					keyframe = Assets.plataformaBeigeLeft;
					break;
				case Plataformas.COLOR_BLUE:
					keyframe = Assets.plataformaBlueLeft;
					break;
				case Plataformas.COLOR_GRAY:
					keyframe = Assets.plataformaGrayLeft;
					break;
				case Plataformas.COLOR_GREEN:
					keyframe = Assets.plataformaGreenLeft;
					break;
				case Plataformas.COLOR_MULTICOLOR:
					keyframe = Assets.plataformaMulticolorLeft;
					break;
				case Plataformas.COLOR_PINK:
					keyframe = Assets.plataformaPinkLeft;
					break;

				}
			}
			else {
				switch (obj.color) {
				case Plataformas.COLOR_BEIGE:
					keyframe = Assets.plataformaBeigeRight;
					break;
				case Plataformas.COLOR_BLUE:
					keyframe = Assets.plataformaBlueRight;
					break;
				case Plataformas.COLOR_GRAY:
					keyframe = Assets.plataformaGrayRight;
					break;
				case Plataformas.COLOR_GREEN:
					keyframe = Assets.plataformaGreenRight;
					break;
				case Plataformas.COLOR_MULTICOLOR:
					keyframe = Assets.plataformaMulticolorRight;
					break;
				case Plataformas.COLOR_PINK:
					keyframe = Assets.plataformaPinkRight;
					break;

				}
			}

			batcher.draw(keyframe, obj.position.x - PiezaPlataformas.DRAW_WIDTH_NORMAL / 2f, obj.position.y - PiezaPlataformas.DRAW_HEIGTH_NORMAL
					/ 2f, PiezaPlataformas.DRAW_WIDTH_NORMAL / 2f, PiezaPlataformas.DRAW_HEIGTH_NORMAL / 2f, PiezaPlataformas.DRAW_WIDTH_NORMAL,
					PiezaPlataformas.DRAW_HEIGTH_NORMAL, 1, 1, obj.angleDeg);

		}
	}

	private void renderCoins() {
		Iterator<Moneda> i = oWorld.arrMonedas.iterator();
		while (i.hasNext()) {
			Moneda obj = i.next();

			batcher.draw(Assets.coin, obj.position.x - Moneda.DRAW_WIDTH / 2f, obj.position.y - Moneda.DRAW_HEIGHT / 2f, Moneda.DRAW_WIDTH,
					Moneda.DRAW_HEIGHT);
		}

	}

	private void renderItems() {
		Iterator<Item> i = oWorld.arrItem.iterator();
		while (i.hasNext()) {
			Item obj = i.next();

			TextureRegion keyframe = null;

			switch (obj.tipo) {
			case Item.TIPO_BUBBLE:
				keyframe = Assets.bubbleSmall;
				break;
			case Item.TIPO_JETPACK:
				keyframe = Assets.jetpackSmall;
				break;
			case Item.TIPO_GUN:
				keyframe = Assets.gun;
				break;

			}

			batcher.draw(keyframe, obj.position.x - Item.DRAW_WIDTH / 2f, obj.position.y - Item.DRAW_HEIGHT / 2f, Item.DRAW_WIDTH, Item.DRAW_HEIGHT);

		}

	}

	private void renderEnemigo() {
		Iterator<Enemigo> i = oWorld.arrEnemigo.iterator();
		while (i.hasNext()) {
			Enemigo obj = i.next();

			TextureRegion keyframe = Assets.enemigo.getKeyFrame(obj.stateTime, true);

			batcher.draw(keyframe, obj.position.x - Enemigo.DRAW_WIDTH / 2f, obj.position.y - Enemigo.DRAW_HEIGHT / 2f, Enemigo.DRAW_WIDTH,
					Enemigo.DRAW_HEIGHT);
		}

	}

	private void renderNube() {
		Iterator<Nube> i = oWorld.arrNubes.iterator();
		while (i.hasNext()) {
			Nube obj = i.next();

			TextureRegion keyframe = null;

			switch (obj.tipo) {
			case Nube.TIPO_ANGRY:
				keyframe = Assets.nubeAngry;
				break;
			case Nube.TIPO_HAPPY:
				keyframe = Assets.nubeHappy;
				break;

			}

			batcher.draw(keyframe, obj.position.x - Nube.DRAW_WIDTH / 2f, obj.position.y - Nube.DRAW_HEIGHT / 2f, Nube.DRAW_WIDTH, Nube.DRAW_HEIGHT);

			if (obj.isBlowing) {
				batcher.draw(Assets.nubeViento, obj.position.x - .35f, obj.position.y - .85f, .6f, .8f);
			}
		}

	}

	private void renderRayo() {
		Iterator<Rayo> i = oWorld.arrRayos.iterator();
		while (i.hasNext()) {
			Rayo obj = i.next();

			TextureRegion keyframe = Assets.rayo.getKeyFrame(obj.stateTime, true);

			batcher.draw(keyframe, obj.position.x - Rayo.DRAW_WIDTH / 2f, obj.position.y - Rayo.DRAW_HEIGHT / 2f, Rayo.DRAW_WIDTH, Rayo.DRAW_HEIGHT);
		}
	}

	private void renderBullet() {
		Iterator<Bullet> i = oWorld.arrBullets.iterator();
		while (i.hasNext()) {
			Bullet obj = i.next();
			batcher.draw(Assets.bullet, obj.position.x - Bullet.SIZE / 2f, obj.position.y - Bullet.SIZE / 2f, Bullet.SIZE, Bullet.SIZE);
		}
	}

}

Personaje.java

public class Personaje {
	public final static int STATE_NORMAL = 0;
	public final static int STATE_DEAD = 1;
	public int state;

	public final static float DRAW_WIDTH = .75f;
	public final static float DRAW_HEIGTH = .8f;

	public final static float WIDTH = .4f;
	public final static float HEIGTH = .6f;

	final float VELOCIDAD_JUMP = 7.5f;
	final float VELOCIDAD_X = 5;

	public final float DURATION_BUBBLE = 3;
	public float durationBubble;

	public final float DURATION_JETPACK = 3;
	public float durationJetPack;

	final public Vector2 position;
	public Vector2 velocidad;
	public float angleDeg;

	public float stateTime;

	boolean didJump;
	public boolean isBubble;
	public boolean isJetPack;

	public Personaje(float x, float y) {
		position = new Vector2(x, y);
		velocidad = new Vector2();

		stateTime = 0;
		state = STATE_NORMAL;

	}

	public void update(Body body, float delta, float acelX) {
		position.x = body.getPosition().x;
		position.y = body.getPosition().y;

		velocidad = body.getLinearVelocity();

		if (state == STATE_NORMAL) {

			if (didJump) {
				didJump = false;
				stateTime = 0;
				velocidad.y = VELOCIDAD_JUMP;

			}

			velocidad.x = acelX * VELOCIDAD_X;

			if (isBubble) {
				durationBubble += delta;
				if (durationBubble >= DURATION_BUBBLE) {
					durationBubble = 0;
					isBubble = false;
				}
			}

			if (isJetPack) {
				durationJetPack += delta;
				if (durationJetPack >= DURATION_JETPACK) {
					durationJetPack = 0;
					isJetPack = false;
				}
				velocidad.y = VELOCIDAD_JUMP;
			}

		}
		else {
			body.setAngularVelocity(MathUtils.degRad * 360);
			velocidad.x = 0;
		}

		body.setLinearVelocity(velocidad);

		if (position.x >= Screens.WORLD_WIDTH) {
			position.x = 0;
			body.setTransform(position, 0);
		}
		else if (position.x <= 0) {
			position.x = Screens.WORLD_WIDTH;
			body.setTransform(position, 0);
		}

		angleDeg = body.getAngle() * MathUtils.radDeg;

		velocidad = body.getLinearVelocity();
		stateTime += delta;

	}

	public void jump() {
		didJump = true;
	}

	public void hit() {
		if (state == STATE_NORMAL && !isBubble && !isJetPack) {
			state = STATE_DEAD;
			stateTime = 0;

		}
	}

	public void die() {
		if (state == STATE_NORMAL) {
			state = STATE_DEAD;
			stateTime = 0;
		}
	}

	public void setBubble() {
		if (state == STATE_NORMAL) {
			isBubble = true;
			durationBubble = 0;
		}
	}

	public void setJetPack() {
		if (state == STATE_NORMAL) {
			isJetPack = true;
			durationJetPack = 0;
		}
	}
}

MainMenuScreen.java

public class MainMenuScreen extends Screens {

	Image titulo;

	TextButton btShop, btPlay, btLeaderboard, btRate;
	Button btMusica;
	Label lbBestScore;

	public MainMenuScreen(final MainSuperJumper game) {
		super(game);

		titulo = new Image(Assets.titulo);
		titulo.setPosition(SCREEN_WIDTH / 2f - titulo.getWidth() / 2f, 800);

		titulo.addAction(Actions.sequence(Actions.moveTo(titulo.getX(), 600, 1, Interpolation.bounceOut), Actions.run(new Runnable() {

			@Override
			public void run() {
				stage.addActor(lbBestScore);

			}
		})));

		lbBestScore = new Label("Best score " + Settings.bestScore, Assets.labelStyleChico);
		lbBestScore.setPosition(SCREEN_WIDTH / 2f - lbBestScore.getWidth() / 2f, 570);
		lbBestScore.getColor().a = 0;
		lbBestScore.addAction(Actions.alpha(1, .25f));

		btPlay = new TextButton("Play", Assets.textButtonStyleGrande);
		btPlay.setPosition(SCREEN_WIDTH / 2f - btPlay.getWidth() / 2f, 440);
		btPlay.pad(10);
		btPlay.pack();
		addEfectoPress(btPlay);
		btPlay.addListener(new ClickListener() {
			@Override
			public void clicked(InputEvent event, float x, float y) {
				changeScreenWithFadeOut(GameScreen.class, game);
			}
		});

		btShop = new TextButton("Shop", Assets.textButtonStyleGrande);
		btShop.setPosition(SCREEN_WIDTH / 2f - btShop.getWidth() / 2f, 340);
		btShop.pad(10);
		btShop.pack();
		addEfectoPress(btShop);
		btShop.addListener(new ClickListener() {
			@Override
			public void clicked(InputEvent event, float x, float y) {

			}
		});

		btRate = new TextButton("Rate", Assets.textButtonStyleGrande);
		btRate.setPosition(SCREEN_WIDTH / 2f - btRate.getWidth() / 2f, 340);
		btRate.pad(10);
		btRate.pack();
		addEfectoPress(btRate);
		btRate.addListener(new ClickListener() {
			@Override
			public void clicked(InputEvent event, float x, float y) {
				game.reqHandler.showRater();
			}
		});

		btLeaderboard = new TextButton("Leaderboard", Assets.textButtonStyleGrande);
		btLeaderboard.pad(10);
		btLeaderboard.pack();
		btLeaderboard.setPosition(SCREEN_WIDTH / 2f - btLeaderboard.getWidth() / 2f, 240);

		addEfectoPress(btLeaderboard);
		btLeaderboard.addListener(new ClickListener() {
			@Override
			public void clicked(InputEvent event, float x, float y) {
				if (game.gameServiceHandler.isSignedIn())
					game.gameServiceHandler.getLeaderboard();
				else
					game.gameServiceHandler.signIn();
			}
		});

		stage.addActor(titulo);
		stage.addActor(btPlay);
		stage.addActor(btRate);
		// stage.addActor(btShop);
		stage.addActor(btLeaderboard);

	}

	@Override
	public void update(float delta) {

	}

	@Override
	public void draw(float delta) {
		batcher.begin();
		batcher.draw(Assets.fondo, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
		batcher.draw(Assets.plataformaBeigeBroken, 100, 100, 125, 45);
		batcher.draw(Assets.plataformaBlue, 350, 280, 125, 45);
		batcher.draw(Assets.plataformaMulticolor, 25, 430, 125, 45);
		batcher.draw(Assets.personajeJump, 25, 270, 75, 80);
		batcher.draw(Assets.nubeHappy, 350, 500, 95, 60);
		batcher.end();
	}

	@Override
	public boolean keyDown(int keycode) {
		if (keycode == Keys.ESCAPE || keycode == Keys.BACK) {
			Gdx.app.exit();
		}
		return super.keyDown(keycode);
	}

}

Screens.java

public abstract class Screens extends InputAdapter implements Screen {
	public static final int SCREEN_WIDTH = 480;
	public static final int SCREEN_HEIGHT = 800;

	public static final float WORLD_WIDTH = 4.8f;
	public static final float WORLD_HEIGHT = 8f;

	public MainSuperJumper game;

	public OrthographicCamera oCam;
	public SpriteBatch batcher;
	public Stage stage;

	protected Music music;

	public Screens(MainSuperJumper game) {
		this.stage = game.stage;
		this.stage.clear();
		this.batcher = game.batcher;
		this.game = game;

		oCam = new OrthographicCamera(SCREEN_WIDTH, SCREEN_HEIGHT);
		oCam.position.set(SCREEN_WIDTH / 2f, SCREEN_HEIGHT / 2f, 0);

		InputMultiplexer input = new InputMultiplexer(this, stage);
		Gdx.input.setInputProcessor(input);

	}

	@Override
	public void render(float delta) {
		if (delta > .1f)
			delta = .1f;

		update(delta);
		stage.act(delta);

		oCam.update();
		batcher.setProjectionMatrix(oCam.combined);

		Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
		draw(delta);
		stage.draw();

	}

	public void addEfectoPress(final Actor actor) {
		actor.addListener(new InputListener() {
			@Override
			public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
				actor.setPosition(actor.getX(), actor.getY() - 5);
				event.stop();
				return true;
			}

			@Override
			public void touchUp(InputEvent event, float x, float y, int pointer, int button) {
				actor.setPosition(actor.getX(), actor.getY() + 5);
			}
		});
	}

	Image blackFadeOut;

	public void changeScreenWithFadeOut(final Class<?> newScreen, final MainSuperJumper game) {
		blackFadeOut = new Image(Assets.pixelNegro);
		blackFadeOut.setSize(SCREEN_WIDTH, SCREEN_HEIGHT);
		blackFadeOut.getColor().a = 0;
		blackFadeOut.addAction(Actions.sequence(Actions.fadeIn(.5f), Actions.run(new Runnable() {
			@Override
			public void run() {
				if (newScreen == GameScreen.class) {
					game.setScreen(new GameScreen(game));
				}
				else if (newScreen == MainMenuScreen.class) {
					game.setScreen(new MainMenuScreen(game));
				}
				// else if (newScreen == ShopScreen.class)
				//	game.setScreen(new ShopScreen(game));

				// El blackFadeOut se remueve del stage cuando se le da new Screens(game) "Revisar el constructor de la clase Screens" por lo que no hay necesidad de hacer
				// blackFadeout.remove();
			}
		})));

		Label lbl = new Label("Loading..", Assets.labelStyleGrande);
		lbl.setPosition(SCREEN_WIDTH / 2f - lbl.getWidth() / 2f, SCREEN_HEIGHT / 2f - lbl.getHeight() / 2f);
		lbl.getColor().a = 0;
		lbl.addAction(Actions.fadeIn(.6f));

		stage.addActor(blackFadeOut);
		stage.addActor(lbl);

	}

	public abstract void update(float delta);

	public abstract void draw(float delta);

	@Override
	public void resize(int width, int height) {
		stage.getViewport().update(width, height, true);
	}

	@Override
	public void show() {
	}

	@Override
	public void hide() {
		if (music != null) {
			music.stop();
			music.dispose();
			music = null;
		}

		Settings.save();
	}

	@Override
	public void pause() {
	}

	@Override
	public void resume() {

	}

	@Override
	public void dispose() {
		batcher.dispose();
	}

}

2.Thành viên và source code

Thành viên : Ngô Mạnh Thông , Trịnh Ngọc Quang
Lớp : 22CDTH11
source code :

https://github.com/quangk22/libgdx_new_super_jumper