com.mygdx.game.DesertGame.java Source code

Java tutorial

Introduction

Here is the source code for com.mygdx.game.DesertGame.java

Source

/*******************************************************************************
 * Copyright 2011 See AUTHORS file.
 *
 * 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.
 ******************************************************************************/

package com.mygdx.game;

import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input.Keys;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Animation;
import com.badlogic.gdx.graphics.g2d.Batch;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
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.maps.tiled.renderers.OrthogonalTiledMapRenderer;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.Pool;

import java.util.Arrays;
import java.util.Random;

/** Super Mario Brothers like very basic platformer, using a tile map build via <a href="http://www.mapeditor.org/">Tiled</a> and a
 * tileset and sprites by <a href="http://www.vickiwenderlich.com/">Vicky Wenderlich</a></p>
 *
 * Shows simple platformer collision detection as well as on-the-fly map modifications through destructable blocks!
 * @author mzechner */
public class DesertGame extends ApplicationAdapter {
    final public Random rand = new Random();

    /** The player character, has state and state time, */
    static class Wanderer {
        static float WIDTH;
        static float HEIGHT;
        static float MAX_VELOCITY = 10f;
        static float JUMP_VELOCITY = 50f;
        static float DAMPING = 0.87f;

        enum State {
            Standing, Walking, Jumping
        }

        enum Facing {
            North, East, South, West
        }

        final Vector2 position = new Vector2();
        final Vector2 velocity = new Vector2();
        State state = State.Walking;
        Facing facing = Facing.North;
        float stateTime = 0;
        //int facing = 0;
        boolean facesRight = true;
        boolean grounded = false;
    }

    private TiledMap[] map = new TiledMap[2];
    private OrthogonalTiledMapRenderer renderer;
    private OrthographicCamera camera;
    private Texture wandererTexture;
    private Animation standNorth;
    private Animation standEast;
    private Animation standSouth;
    private Animation standWest;
    private Animation walkNorth;
    private Animation walkEast;
    private Animation walkSouth;
    private Animation walkWest;

    private Wanderer wanderer;
    private Pool<Rectangle> rectPool = new Pool<Rectangle>() {
        @Override
        protected Rectangle newObject() {
            return new Rectangle();
        }
    };
    private Array<Rectangle> tiles = new Array<Rectangle>();

    //private static final float GRAVITY = -2.5f;

    @Override
    public void create() {
        // load the wanderer frames, split them, and assign them to Animations
        wandererTexture = new Texture("4LinkGreen1.png");
        TextureRegion[][] regions = TextureRegion.split(wandererTexture, 24, 32);

        // Animations (standing, walking) in the four directions
        standNorth = new Animation(0, regions[0][0]);
        standEast = new Animation(0, regions[1][0]);
        standSouth = new Animation(0, regions[2][0]);
        standWest = new Animation(0, regions[3][0]);
        walkNorth = new Animation(0.07f, Arrays.copyOfRange(regions[0], 1, 11));
        walkNorth.setPlayMode(Animation.PlayMode.LOOP);
        walkEast = new Animation(0.07f, Arrays.copyOfRange(regions[1], 1, 11));
        walkEast.setPlayMode(Animation.PlayMode.LOOP);
        walkSouth = new Animation(0.07f, Arrays.copyOfRange(regions[2], 1, 11));
        walkSouth.setPlayMode(Animation.PlayMode.LOOP);
        walkWest = new Animation(0.07f, Arrays.copyOfRange(regions[3], 1, 11));
        walkWest.setPlayMode(Animation.PlayMode.LOOP);

        // figure out the width and height of the wanderer for collision
        // detection and rendering by converting a wanderer frames pixel
        // size into world units (1 unit == 16 pixels)
        Wanderer.WIDTH = 1 / 16f * regions[0][0].getRegionWidth();
        Wanderer.HEIGHT = 1 / 16f * regions[0][0].getRegionHeight();

        // load the map, set the unit scale to 1/16 (1 unit == 16 pixels)
        map[0] = new TmxMapLoader().load("level1.tmx");
        map[1] = new TmxMapLoader().load("level2.tmx");

        renderer = new OrthogonalTiledMapRenderer(map[0], 1 / 16f);

        // create an orthographic camera, shows us 30x20 units of the world
        camera = new OrthographicCamera();
        camera.setToOrtho(false, 30, 20);
        camera.update();

        // create the Wanderer we want to move around the world
        wanderer = new Wanderer();
        wanderer.position.set(20, 20);
    }

    @Override
    public void resize(int width, int height) {

    }

    @Override
    public void render() {
        // clear the screen
        Gdx.gl.glClearColor(0.7f, 0.7f, 1.0f, 1);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);

        // get the delta time
        float deltaTime = Gdx.graphics.getDeltaTime();

        // update the koala (process input, collision detection, position update)
        updateKoala(deltaTime);

        // let the camera follow the koala
        camera.position.x = wanderer.position.x;
        camera.position.y = wanderer.position.y;
        camera.update();

        // set the tile map rendere view based on what the
        // camera sees and render the map
        renderer.setView(camera);
        renderer.render();

        // render the koala
        renderKoala(deltaTime);
    }

    private Vector2 tmp = new Vector2();

    private void updateKoala(float deltaTime) {
        if (deltaTime == 0)
            return;
        wanderer.stateTime += deltaTime;

        // check input and apply to velocity & state
        if (Gdx.input.isKeyPressed(Keys.Q)) {
            renderer.setMap(map[1]);
        }
        if (Gdx.input.isKeyPressed(Keys.UP) || Gdx.input.isKeyPressed(Keys.W)) {
            wanderer.facing = Wanderer.Facing.North;
            wanderer.velocity.y += Wanderer.MAX_VELOCITY / 2;
        }
        if (Gdx.input.isKeyPressed(Keys.DOWN) || Gdx.input.isKeyPressed(Keys.S)) {
            wanderer.facing = Wanderer.Facing.South;
            wanderer.velocity.y -= Wanderer.MAX_VELOCITY / 2;
        }
        if (Gdx.input.isKeyPressed(Keys.LEFT) || Gdx.input.isKeyPressed(Keys.A)) {
            wanderer.facing = Wanderer.Facing.West;
            wanderer.velocity.x = -Wanderer.MAX_VELOCITY;
            //if (koala.grounded) koala.state = Koala.State.Walking;
            //koala.facesRight = false;
        }
        if (Gdx.input.isKeyPressed(Keys.RIGHT) || Gdx.input.isKeyPressed(Keys.D)) {
            wanderer.facing = Wanderer.Facing.East;
            wanderer.velocity.x = Wanderer.MAX_VELOCITY;
            //if (koala.grounded) koala.state = Koala.State.Walking;
            //koala.facesRight = true;
        }

        // clamp the velocity to the maximum
        if (Math.abs(wanderer.velocity.x) > Wanderer.MAX_VELOCITY) {
            wanderer.velocity.x = Math.signum(wanderer.velocity.x) * Wanderer.MAX_VELOCITY;
        }
        if (Math.abs(wanderer.velocity.y) > Wanderer.MAX_VELOCITY) {
            wanderer.velocity.y = Math.signum(wanderer.velocity.y) * Wanderer.MAX_VELOCITY;

        }

        // clamp the velocity to 0 if it's < 1, and set the state to standign
        if (Math.abs(wanderer.velocity.x) < 1) {
            wanderer.velocity.x = 0;
            if (wanderer.grounded)
                wanderer.state = Wanderer.State.Standing;
        }
        if (Math.abs(wanderer.velocity.y) < 1) {
            wanderer.velocity.y = 0;
            if (wanderer.grounded)
                wanderer.state = Wanderer.State.Standing;
        }

        // multiply by delta time so we know how far we go
        // in this frame
        wanderer.velocity.scl(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 koalaRect = rectPool.obtain();
        koalaRect.set(wanderer.position.x, wanderer.position.y, Wanderer.WIDTH, Wanderer.HEIGHT);
        int startX, startY, endX, endY;
        if (wanderer.velocity.x > 0) {
            startX = endX = (int) (wanderer.position.x + Wanderer.WIDTH + wanderer.velocity.x);
        } else {
            startX = endX = (int) (wanderer.position.x + wanderer.velocity.x);
        }
        startY = (int) (wanderer.position.y);
        endY = (int) (wanderer.position.y + Wanderer.HEIGHT);
        getTiles(startX, startY, endX, endY, tiles);
        koalaRect.x += wanderer.velocity.x;
        for (Rectangle tile : tiles) {
            if (koalaRect.overlaps(tile)) {
                wanderer.velocity.x = 0;
                break;
            }
        }
        koalaRect.x = wanderer.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 (wanderer.velocity.y > 0) {
            startY = endY = (int) (wanderer.position.y + Wanderer.HEIGHT + wanderer.velocity.y);
        } else {
            startY = endY = (int) (wanderer.position.y + wanderer.velocity.y);
        }
        startX = (int) (wanderer.position.x);
        endX = (int) (wanderer.position.x + Wanderer.WIDTH);
        getTiles(startX, startY, endX, endY, tiles);
        koalaRect.y += wanderer.velocity.y;
        for (Rectangle tile : tiles) {
            if (koalaRect.overlaps(tile)) {
                // we actually reset the koala y-position here
                // so it is just below/above the tile we collided with
                // this removes bouncing :)
                if (wanderer.velocity.y > 0) {
                    wanderer.position.y = tile.y - Wanderer.HEIGHT;
                    // we hit a block jumping upwards, let's destroy it!
                    //TiledMapTileLayer layer = (TiledMapTileLayer)map.getLayers().get(1);
                    //layer.setCell((int)tile.x, (int)tile.y, null);
                } else {
                    wanderer.position.y = tile.y + tile.height;
                    // if we hit the ground, mark us as grounded so we can jump
                    wanderer.grounded = true;
                }
                wanderer.velocity.y = 0;
                break;
            }
        }
        rectPool.free(koalaRect);

        // unscale the velocity by the inverse delta time and set
        // the latest position
        wanderer.position.add(wanderer.velocity);
        wanderer.velocity.scl(1 / deltaTime);

        // Apply damping to the velocity on the x-axis so we don't
        // walk infinitely once a key was pressed
        wanderer.velocity.x *= Wanderer.DAMPING;
        wanderer.velocity.y *= Wanderer.DAMPING;

    }

    private void getTiles(int startX, int startY, int endX, int endY, Array<Rectangle> tiles) {
        TiledMapTileLayer layer = (TiledMapTileLayer) map[0].getLayers().get(1);
        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);
                }
            }
        }
    }

    private void renderKoala(float deltaTime) {
        // based on the koala state, get the animation frame
        TextureRegion frame = null;
        /*
        switch (koala.state) {
        case Standing:
            frame = stand.getKeyFrame(koala.stateTime);
            break;
        case Walking:
            frame = walk.getKeyFrame(koala.stateTime);
            break;
        case Jumping:
            frame = jump.getKeyFrame(koala.stateTime);
            break;
        }
        */
        switch (wanderer.facing) {
        case North:
            frame = walkNorth.getKeyFrame(wanderer.stateTime);
            break;
        case East:
            frame = walkEast.getKeyFrame(wanderer.stateTime);
            break;
        case South:
            frame = walkSouth.getKeyFrame(wanderer.stateTime);
            break;
        case West:
            frame = walkWest.getKeyFrame(wanderer.stateTime);
            break;
        }

        // draw the wanderer, depending on the current velocity
        // on the x-axis, draw the wanderer facing either right
        // or left
        Batch batch = renderer.getSpriteBatch();
        batch.begin();
        if (wanderer.facesRight) {
            batch.draw(frame, wanderer.position.x, wanderer.position.y, Wanderer.WIDTH, Wanderer.HEIGHT);
        } else {
            batch.draw(frame, wanderer.position.x + Wanderer.WIDTH, wanderer.position.y, -Wanderer.WIDTH,
                    Wanderer.HEIGHT);
        }
        batch.end();
    }

}