Hello all, I am very new to game programming. I am currently using the
Slick2D Library to assist me in making a game. I am trying to create a scrolling level like you would have in Zelda where the player reaches the edge of the screen and goes onto the next. I am using a Tile Map to load the level and have defined tiles within the map editor where the collision is to take place (walls, trees). Anyway, when I compile the code and run, the map loads and I can move the sprite around. Currently I cannot get the map to “scroll” in any direction. In addition each direction gives me different results. When heading North, or West I crash (array index out of bounds)
When I head south, I get “blocked” (collision point) from reaching the edge. Sorry for the long post. Any help in figuring out why the scrolling does not work is greatly appreciated. Here is the code.
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package GameWorld;
/**
*
* @author Matt
*/
import org.newdawn.slick.*;
import org.newdawn.slick.tiled.TiledMap;
import org.newdawn.slick.state.*;
import org.newdawn.slick.gui.TextField;
public class GamePlayState extends BasicGameState{
private int stateID = 0;
private TiledMap level1;
private Animation sprite,up,down,left,right;
private float x = 34f, y = 34f;
//is the current tile of the tile map "blocked"
private boolean[][] blocked;
//
private boolean[][] collidable;
private static final int SIZE = 32;
private static final int TILE_SIZE = 32;
private static final float SPEED = 0.003f;
private TextField text1;
/** 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 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 player's x position in tiles */
private float playerX =20;
/** The player's y position in tiles */
private float playerY = 20;
private enum STATES{START_GAME_STATE,PAUSE_GAME_STATE,GAME_OVER_STATE};
private STATES currentState = null;
public GamePlayState(int stateID)
{
this.stateID = stateID;
}
@Override
public int getID() {
return stateID;
}
@Override
public void init(GameContainer container, StateBasedGame sb) throws SlickException
{
//assigning instance variable of object TileMap to the level1 Map Location
level1 = new TiledMap("C:/Users/Matt/Downloads/desert.tmx");
/*storing the image files for movement in an array so that different images can be loaded when player has new weapons.
and more importantly to help animate the sprite
*/
Image [] movementUp = {new Image("C:/Users/Matt/Downloads/last-guardian-sprites/last-guardian-sprites/amg1_bk1.gif")
,new Image("C:/Users/Matt/Downloads/last-guardian-sprites/last-guardian-sprites/amg1_bk2.gif")};
Image [] movementDown = {new Image("C:/Users/Matt/Downloads/last-guardian-sprites/last-guardian-sprites/amg1_fr1.gif")
,new Image("C:/Users/Matt/Downloads/last-guardian-sprites/last-guardian-sprites/amg1_fr2.gif")};
Image [] movementLeft = { new Image("C:/Users/Matt/Downloads/last-guardian-sprites/last-guardian-sprites/amg1_lf1.gif")
,new Image("C:/Users/Matt/Downloads/last-guardian-sprites/last-guardian-sprites/amg1_lf2.gif")};
Image [] movementRight ={ new Image("C:/Users/Matt/Downloads/last-guardian-sprites/last-guardian-sprites/amg1_rt1.gif")
,new Image("C:/Users/Matt/Downloads/last-guardian-sprites/last-guardian-sprites/amg1_rt2.gif")};
//determine how often the images are to be redrawn
int [] duration = {300,300};
//animate the sprite as the user presses the key
up = new Animation(movementUp,duration,false);
down = new Animation(movementDown,duration,false);
left = new Animation(movementLeft,duration,false);
right = new Animation(movementRight,duration,false);
//set default orientation of the sprite
sprite = right;
sprite.setAutoUpdate(false);
//add collision detection to the walls that have the blocked Map property
blocked = new boolean[level1.getWidth()][level1.getHeight()];
collidable = new boolean[level1.getWidth()][level1.getHeight()];
for (int a=0;a<level1.getWidth();a++) {
for (int b=0;b<level1.getHeight();b++) {
int tileID = level1.getTileId(a, b, 0);
String value = level1.getTileProperty(tileID, "blocked", "false");
if ("true".equals(value)) {
blocked[a][b] = 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;
}
@Override
public void update(GameContainer container, StateBasedGame sb, int delta) throws SlickException
{
//update the sprite movement as the keys are pressed
Input input = container.getInput();
float fdelta = delta*0.1f;
if (input.isKeyDown(Input.KEY_UP))
{
sprite = up;
if (!(isBlocked(x, y - fdelta) || isBlocked(x+SIZE-1, y - fdelta)))
{
sprite.update(delta);
// The lower the delta the slowest the sprite will animate.
y -= delta * 0.1f;
}
}
else if (input.isKeyDown(Input.KEY_DOWN))
{
sprite = down;
if (!(isBlocked(x, y + SIZE + fdelta) || isBlocked(x+SIZE-1, y + SIZE + fdelta)))
{
sprite.update(delta);
y += fdelta;
}
}
else if (input.isKeyDown(Input.KEY_LEFT))
{
sprite = left;
if(!(isBlocked(x-fdelta,y) || isBlocked(x-fdelta,y+SIZE-1)))
{
sprite.update(delta);
x -= fdelta;
}
}
else if (input.isKeyDown(Input.KEY_RIGHT))
{
sprite = right;
if (!(isBlocked(x + SIZE + fdelta, y) || isBlocked(x + SIZE + fdelta, y+SIZE-1)))
{
sprite.update(delta);
x += fdelta;
}
}
}
@Override
public void render(GameContainer container, StateBasedGame sb, Graphics g) throws SlickException
{
// draw the appropriate section of the tilemap based on the centre (hence the -(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
level1.render(playerTileOffsetX - (SIZE / 2), playerTileOffsetY - (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();
// TextField field = new TextField();
//render the map onto the screen
// level1.render(0,0);
sprite.draw((int)x,(int)y);
// fontTest.drawString(20.0f, 20.0f, "Slick displaying True Type Fonts", Color.green)
}
private boolean isBlocked(float aBlock, float bBlock)
{
int a = (int)aBlock/SIZE;
int b = (int)bBlock/SIZE;
return blocked[a][b];
}
/* private boolean isCollectable(float x,float y)
{
int xBlock = (int)x / SIZE;
int yBlock = (int)y / SIZE;
return collidable[xBlock][yBlock];
} */
}