Package org.newdawn.slick.examples.scroller

Source Code of org.newdawn.slick.examples.scroller.Scroller

package org.newdawn.slick.examples.scroller;

import org.newdawn.slick.Animation;
import org.newdawn.slick.AppGameContainer;
import org.newdawn.slick.BasicGame;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Input;
import org.newdawn.slick.SlickException;
import org.newdawn.slick.SpriteSheet;
import org.newdawn.slick.tiled.TiledMap;
import org.newdawn.slick.util.Log;

/**
* An example to show scrolling around a tilemap smoothly. This seems to have caused confusion
* a couple of times so here's "a" way to do it.
*
* @author kevin
*/
public class Scroller extends BasicGame {
  /** The size of the tank sprite - used for finding the centre */
  private static final int TANK_SIZE = 32;
  /** The size of the tiles - used to determine the amount to draw */
  private static final int TILE_SIZE = 32;
  /** The speed the tank moves at */
  private static final float TANK_MOVE_SPEED = 0.003f;
  /** The speed the tank rotates at */
  private static final float TANK_ROTATE_SPEED = 0.2f;
 
  /** The player's x position in tiles */
  private float playerX = 15;
  /** The player's y position in tiles */
  private float playerY = 16;
 
  /** The width of the display in tiles */
  private int widthInTiles;
  /** The height of the display in tiles */
  private int heightInTiles;
 
  /** The offset from the centre of the screen to the top edge in tiles */
  private int topOffsetInTiles;
  /** The offset from the centre of the screen to the left edge in tiles */
  private int leftOffsetInTiles;
 
  /** The map that we're going to drive around */
  private TiledMap map;
 
  /** The animation representing the player's tank */
  private Animation player;
 
  /** The angle the player is facing */
  private float ang;
  /** The x component of the movement vector */
  private float dirX;
  /** The y component of themovement vector */
  private float dirY;
 
  /** The collision map indicating which tiles block movement - generated based on tile properties */
  private boolean[][] blocked;
 
  /**
   * Scroller example
   */
  public Scroller() {
    super("Scroller");
  }
 
  /**
   * @see org.newdawn.slick.BasicGame#init(org.newdawn.slick.GameContainer)
   */
  public void init(GameContainer container) throws SlickException {
    // load the sprites and tiles, note that underneath the texture
    // will be shared between the sprite sheet and tilemap
    SpriteSheet sheet = new SpriteSheet("testdata/scroller/sprites.png",32,32);
    // load the tilemap created the TileD tool
    map = new TiledMap("testdata/scroller/map.tmx");
   
    // build a collision map based on tile properties in the TileD map
    blocked = new boolean[map.getWidth()][map.getHeight()];
    for (int x=0;x<map.getWidth();x++) {
      for (int y=0;y<map.getHeight();y++) {
        int tileID = map.getTileId(x, y, 0);
        String value = map.getTileProperty(tileID, "blocked", "false");
        if ("true".equals(value)) {
          blocked[x][y] = true;
        }
      }
    }
   
    // caculate some layout values for rendering the tilemap. How many tiles
    // do we need to render to fill the screen in each dimension and how far is
    // it from the centre of the screen
    widthInTiles = container.getWidth() / TILE_SIZE;
    heightInTiles = container.getHeight() / TILE_SIZE;
    topOffsetInTiles = heightInTiles / 2;
    leftOffsetInTiles = widthInTiles / 2;
   
    // create the player sprite based on a set of sprites from the sheet loaded
    // above (tank tracks moving)
    player = new Animation();
    for (int frame=0;frame<7;frame++) {
      player.addFrame(sheet.getSprite(frame,1), 150);
    }
    player.setAutoUpdate(false);

    // update the vector of movement based on the initial angle
    updateMovementVector();
   
    Log.info("Window Dimensions in Tiles: "+widthInTiles+"x"+heightInTiles);
  }

  /**
   * @see org.newdawn.slick.BasicGame#update(org.newdawn.slick.GameContainer, int)
   */
  public void update(GameContainer container, int delta) throws SlickException {
    // check the controls, left/right adjust the rotation of the tank, up/down
    // move backwards and forwards
    if (container.getInput().isKeyDown(Input.KEY_LEFT)) {
      ang -= delta * TANK_ROTATE_SPEED;
      updateMovementVector();
    }
    if (container.getInput().isKeyDown(Input.KEY_RIGHT)) {
      ang += delta * TANK_ROTATE_SPEED;
      updateMovementVector();
    }
    if (container.getInput().isKeyDown(Input.KEY_UP)) {
      if (tryMove(dirX * delta * TANK_MOVE_SPEED, dirY * delta * TANK_MOVE_SPEED)) {
        // if we managed to move update the animation
        player.update(delta);
      }
    }
    if (container.getInput().isKeyDown(Input.KEY_DOWN)) {
      if (tryMove(-dirX * delta * TANK_MOVE_SPEED, -dirY * delta * TANK_MOVE_SPEED)) {
        // if we managed to move update the animation
        player.update(delta);
      }
    }
  }

  /**
   * Check if a specific location of the tank would leave it
   * on a blocked tile
   *
   * @param x The x coordinate of the tank's location
   * @param y The y coordinate of the tank's location
   * @return True if the location is blocked
   */
  private boolean blocked(float x, float y) {
    return blocked[(int) x][(int) y];
  }
 
  /**
   * Try to move in the direction specified. If it's blocked, try sliding. If that
   * doesn't work just don't bother
   *
   * @param x The amount on the X axis to move
   * @param y The amount on the Y axis to move
   * @return True if we managed to move
   */
  private boolean tryMove(float x, float y) {
    float newx = playerX + x;
    float newy = playerY + y;
   
    // first we try the real move, if that doesn't work
    // we try moving on just one of the axis (X and then Y)
    // this allows us to slide against edges
    if (blocked(newx,newy)) {
      if (blocked(newx, playerY)) {
        if (blocked(playerX, newy)) {
          // can't move at all!
          return false;
        } else {
          playerY = newy;
          return true;
        }
      } else {
        playerX = newx;
        return true;
      }
    } else {
      playerX = newx;
      playerY = newy;
      return true;
    }
  }
 
  /**
   * Update the direction that will be moved in based on the
   * current angle of rotation
   */
  private void updateMovementVector() {
    dirX = (float) Math.sin(Math.toRadians(ang));
    dirY = (float) -Math.cos(Math.toRadians(ang));
  }
 
  /**
   * @see org.newdawn.slick.Game#render(org.newdawn.slick.GameContainer, org.newdawn.slick.Graphics)
   */
  public void render(GameContainer container, Graphics g) throws SlickException {
    // draw the appropriate section of the tilemap based on the centre (hence the -(TANK_SIZE/2)) of
    // the player
    int playerTileX = (int) playerX;
    int playerTileY = (int) playerY;
   
    // caculate the offset of the player from the edge of the tile. As the player moves around this
    // varies and this tells us how far to offset the tile based rendering to give the smooth
    // motion of scrolling
    int playerTileOffsetX = (int) ((playerTileX - playerX) * TILE_SIZE);
    int playerTileOffsetY = (int) ((playerTileY - playerY) * TILE_SIZE);
   
    // render the section of the map that should be visible. Notice the -1 and +3 which renders
    // a little extra map around the edge of the screen to cope with tiles scrolling on and off
    // the screen
    map.render(playerTileOffsetX - (TANK_SIZE / 2), playerTileOffsetY - (TANK_SIZE / 2),
           playerTileX - leftOffsetInTiles - 1,
           playerTileY - topOffsetInTiles - 1,
           widthInTiles + 3, heightInTiles + 3);
   
    // draw entities relative to the player that must appear in the centre of the screen
    g.translate(400 - (int) (playerX * 32), 300 - (int) (playerY * 32));
   
    drawTank(g, playerX, playerY, ang);
    // draw other entities here if there were any
   
    g.resetTransform();
  }

  /**
   * Draw a single tank to the game
   * 
   * @param g The graphics context on which we're drawing
   * @param xpos The x coordinate in tiles the tank is at
   * @param ypos The y coordinate in tiles the tank is at
   * @param rot The rotation of the tank
   */
  public void drawTank(Graphics g, float xpos, float ypos, float rot) {
    // work out the centre of the tank in rendering coordinates and then
    // spit onto the screen
    int cx = (int) (xpos * 32);
    int cy = (int) (ypos * 32);
    g.rotate(cx,cy,rot);
    player.draw(cx-16,cy-16);
    g.rotate(cx,cy,-rot);
  }
 
  /**
   * Entry point to the scroller example
   *
   * @param argv The argument passed on the command line (if any)
   */
  public static void main(String[] argv) {
    try {
      // create a new container for our example game. This container
      // just creates a normal native window for rendering OpenGL accelerated
      // elements to
      AppGameContainer container = new AppGameContainer(new Scroller(), 800, 600, false);
      container.start();
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}
TOP

Related Classes of org.newdawn.slick.examples.scroller.Scroller

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.