Previous Tutorial
Next Tutorial
Posted on: 07-11-2012

Gravity Platformer Tutorial #6 : Scrolling the screen

Before we start the tutorial, I'll provide a zip file with the source code and the data files of the tutorials before this one. The zip also includes the new level file that we use in this tutorial: download

One of the next things that is essential to platforming games is the way that the screen scrolls. Now in our game, the puzzles will involve gravity and that means that if we would create a level that would be too large for the screen, the objects (or the player for that matter) could "fall" off the screen.

This isn't necessarily a bad thing for some puzzles, but for most of them it would limit them to the size of the screen. And for the puzzles that are larger than the screen, we would want to see what happens outside our screen by walking towards it. That means we need some kind of scrolling the screen.

There are multiple approaches to this, but for this game we are going to use a method to keep our player centered in the middle of the screen.

There are a few issues with this however, what if the player reaches a wall and the boundary is not thick enough? We could just render nothing there, but that would be ugly.

So to circumvent that, we are going to have 2 cases:

  • Our player is too close to a boundary, we have to somehow stop the screen from scrolling beyond the map boundaries
  • Our player is in a spot between all 4 boundaries and we can happily keep our player at the center of our screen

  1. So lets start off by creating a bigger map, you can either try increasing the map yourself (which I recommend) or you can skip the next step and download the level file here: download

  2. To increase the size of our map, we simply open the Tiled editor. Then we go to "Map" -> "Resize Map".

    I went with 50 tiles wide and 25 high, but you can increase it to any size you would like. The most important thing is to not forget to fill all the new empty tiles with the "air" tile block, or we won't be able to walk there.

  3. The next thing we need to do is have our render method in our Character class take 2 parameters, offset_x and offset_y.

    1. public void render(float offset_x, float offset_y){
    2.  
    3. //draw a moving animation if we have one and we moved within the last 150 miliseconds
    4. if(movingAnimations != null && moving){
    5. movingAnimations.get(facing).draw(x-2-offset_x,y-2-offset_y);
    6. }else{
    7. sprites.get(facing).draw(x-2-offset_x, y-2-offset_y);
    8. }
    9. }

    The idea behind the offset is, if we move our player more to the right, we will calculate how much every object has to offset from their actual position to render them correctly on the screen.

  4. Which is what we will do now, but first our level has to know what character the player is.

    So we add a Player attribute to the Level class and also include it in the constructor.

    1. public Level(String level, Player player) throws SlickException{
    2. map = new TiledMap("data/levels/" + level + ".tmx","data/img");
    3. characters = new ArrayList<Character>();
    4.  
    5. this.player = player;
    6. addCharacter(player);
    7.  
    8. loadTileMap();
    9. }

    We must not forget to add the player as a Character as well, else he won't be drawn.

    This also means that we will have to update the init() method of LevelState.

    1. public void init(GameContainer container, StateBasedGame sbg) throws SlickException {
    2.  
    3. //at the start of the game we don't have a player yet
    4. player = new Player(128,415);
    5.  
    6. //once we initialize our level, we want to load the right level
    7. level = new Level(startinglevel, player);
    8.  
    9. //and we create a controller, for now we use the MouseAndKeyBoardPlayerController
    10. playerController = new MouseAndKeyBoardPlayerController(player);
    11.  
    12. physics = new Physics();
    13. }
  5. And now the calculation of the actual offset, we have one for the X and one for the Y:

    1. public int getXOffset(){
    2. int offset_x = 0;
    3.  
    4. //the first thing we are going to need is the half-width of the screen, to calculate if the player is in the middle of our screen
    5. int half_width = (int) (Game.WINDOW_WIDTH/Game.SCALE/2);
    6.  
    7. //next up is the maximum offset, this is the most right side of the map, minus half of the screen offcourse
    8. int maxX = (int) (map.getWidth()*32)-half_width;
    9.  
    10. //now we have 3 cases here
    11. if(player.getX() < half_width){
    12. //the player is between the most left side of the map, which is zero and half a screen size which is 0+half_screen
    13. offset_x = 0;
    14. }else if(player.getX() > maxX){
    15. //the player is between the maximum point of scrolling and the maximum width of the map
    16. //the reason why we substract half the screen again is because we need to set our offset to the topleft position of our screen
    17. offset_x = maxX-half_width;
    18. }else{
    19. //the player is in between the 2 spots, so we set the offset to the player, minus the half-width of the screen
    20. offset_x = (int) (player.getX()-half_width);
    21. }
    22.  
    23. return offset_x;
    24. }

    The comments should lead you through the code, as for the 3 cases we can have:

  6. And here is the one for the Y:

    1. public int getYOffset(){
    2. int offset_y = 0;
    3.  
    4. int half_heigth = (int) (Game.WINDOW_HEIGTH/Game.SCALE/2);
    5.  
    6. int maxY = (int) (map.getHeight()*32)-half_heigth;
    7.  
    8. if(player.getY() < half_heigth){
    9. offset_y = 0;
    10. }else if(player.getY() > maxY){
    11. offset_y = maxY-half_heigth;
    12. }else{
    13. offset_y = (int) (player.getY()-half_heigth);
    14. }
    15.  
    16. return offset_y;
    17. }
  7. And now all we have to do is letting our render method use these offsets

    1. public void render(){
    2.  
    3. int offset_x = getXOffset();
    4. int offset_y = getYOffset();
    5.  
    6. //render the map first
    7. map.render(-(offset_x%32), -(offset_y%32), offset_x/32, offset_y/32, 33, 19);
    8.  
    9. //and then render the characters on top of the map
    10. for(Character c : characters){
    11. c.render(offset_x,offset_y);
    12. }
    13.  
    14. }

    The way that the render method of map works is that it can offset tiles, but not pixels. So we can fix that problem by starting to render a bit outside the screen.

    Remember that integers round down, then we can find out what is left by using the modulo or "%" operator, this will result in the left over (e.g. 35%32 = 3).

  8. And there we go, we can actually move around a larger map without our character moving off our screen :)

    Closing Notes

    As the last tutorial was a bit long, I decided to keep things short and simple in this one, in the next one we will add a nice background and make use of parallax scrolling.
Categories: Game Development, Java, Tutorial

Comments

Grump said: (08-11-2012)
Seriously, this stuff is fantastic.

Thanks so much for your effort!
Beyond Louie's said: (10-11-2012)
N i i i i i i i c e!



What is the name of the website? (to counter the spam)