How to render specific area?

I’m currently attempting to change my map loading/rendering code so that only the area within x number of blocks in all directions of the sprites’ location are rendered. I know how this should work but I’m not sure how to change the code for it to work in the way that I want it to work.
The way that I’m planning to have it work is that, because the maps are tile-based, it will render all the tiles that you can see on screen and 1 tile in each direction off screen so that when the player is moving it will have enough space and time to render the new tiles so that you don’t start seeing a black background.

Below is the code that I use to load the map. Each pixel on the image corresponds to a tile that will be loaded; when the tiles are being rendered there is a switch statement that, depending on the value at a certain (X,Y) location in the 2D map[][] array, will render a specific tile. This code is based off of another piece of code that I managed to find while googling one day.
I need to somehow change it so that it will only load a certain area of the image based upon four sets of (X, Y) coordinates) instead of loading the entire image pixel by pixel by line by line.

Edit: All code is in the third post

This snippit of code is what I use to render the map. It takes the map[][] array that is loaded from the method above and then goes through every single position in the map[][] array and, depending on the value at that point, renders a specific tile.

Edit: All code is in the third post.

Thanks in advance to anyone who can help me figure out how to solve my problem.

Ack! While your case statement there will work (And you’ll have to do probably do something like it somewhere) it’s not the best way to handle that. This is more about your switch statement than anything. You should pull out that g.draw command and put it into a method that you call:


private void drawSprite(Sprite sprite, int col, int pos, int playerX, int playerY) {
g.drawImage(sprite, column*40 - playerX, row * 40 - playerY, null);
}

Then you can do something a bit better than that switch statement by doing something like:


HashMap<Integer, Sprite> sprites = new HashMap<Integer, Sprite>();
private void init() {
sprites.put(SpriteColorNumber, SpriteResource); // For each one.
}

// ... Lots of stuff

//Render Map
        for(int row = 0; row < mapHeight; row++)
        {
            for(int column = 0; column < mapWidth; column++)
            {
drawSprite(sprites.get(currentMap[column][row]), row, col, playerX, playerY);
}
}

Of course, translating the pixel values into indexes into a bounded array or something would result in better efficiency… But ah, getting off track there, hah.

Whew! That said for your problem about painting the only a sub-section of the map, you first need to decide how you’re going to do it? Are you centering the displayed section on the player? And if so, when he gets to an edge of your map will the map stop following him?

If it doesn’t stop then it’s really simple:


int startX = (playerX - halfWidth) / tileX - 1;
int startY = (playerY - halfHeight) / tileY - 1;
int endX = (playerX + halfWidth) / tileX + 1;
int endY = (playerY + halfHeight) / tileY + 1;

for(int i = startX; i < endX; i++) {
for(int j = startY; j < endY; j++) {
// Render code!
}
}

For the other way (With the camera stopping at the edges) I’ve got a code snippet somewhere (It’s a class that holds the screen bounds and stuff like that) but I’ll have to dig it out.

Thanks for the reply. I’ve attempted to add something similar to what you wrote into the code (I’ve pasted the part I’m talking about below) but I can’t seem to figure out the variables due to how I’ve written my code. I probably should have posted all of the code to give anyone a better understanding of how it works, Anyways…

Do the playerY & playerX variables represent the current area in the map[][] array where the player is?
Do the halfHeight & haldWidth variables represent the amount of tiles from where the player is standing on to the edge of the screen?
What do tileX and tile Y represent?

[quote]int startX = (playerX - halfWidth) / tileX - 1;
int startY = (playerY - halfHeight) / tileY - 1;
int endX = (playerX + halfWidth) / tileX + 1;
int endY = (playerY + halfHeight) / tileY + 1;

for(int i = startX; i < endX; i++) {
for(int j = startY; j < endY; j++) {
// Render code!
}
}
[/quote]
I’ll post the movement code along with the rest of the rendering code so that you can see how I’m doing everything.

This is the render/logic code.

package Screens;

import Core.GameCanvas;
import Core.ResourceHandler;
import Entity.CollisionDetection;
import Entity.Player;
import java.awt.Graphics2D;

public class ScreenGame extends Screen
{
    private int[][] currentMap;
    private GameCanvas canvas;
    private ResourceHandler resource;
    private Player player;
    private CollisionDetection collision;
    private int playerXLocation, playerYLocation, playerDirection;
    private boolean playerIsWalking;
    private int mapWidth, mapHeight;
    private int spriteCounter = 0, spriteCounterTwo = 0;
    
    public ScreenGame(GameCanvas canvas)
    {
        this.canvas = canvas;
        resource = new ResourceHandler();
        player = new Player();
        resource.loadImages();
        collision = new CollisionDetection();
    }
    
    public void logicUpdate()
    {
        setCurrentMap();
        collision.logicUpdate();
        player.logicUpdate();
        playerXLocation = player.getXLocation();
        playerYLocation = player.getYLocation();
        playerIsWalking = player.getIsWalking();
        playerDirection = player.getDirection();
        mapWidth = currentMap.length;
        mapHeight = currentMap[0].length;
        spriteCounterTwo++;
        
        //This while statement checks 4 different points around the player's sprite, if any of them return false then the player's position is changed until they all return true.
        while(collision.checkPointCollision(playerXLocation - 12, playerYLocation + 22) == false /*LowerLeftPoint*/ || collision.checkPointCollision(playerXLocation + 12, playerYLocation + 22) == false /*Lower Right Point*/ || collision.checkPointCollision(playerXLocation - 12, playerYLocation) == false /*Middle Left Point*/ || collision.checkPointCollision(playerXLocation + 12, playerYLocation) == false /*Middle Right Point*/)
        {
            switch(playerDirection)
            {
                case 0:
                {
                    player.setXLocation(1);
                    playerXLocation++;
                    break;
                }
                
                case 1:
                {
                    player.setYLocation(1);
                    playerYLocation++;
                    break;
                }
                    
                case 2:
                {
                    player.setXLocation(-1);
                    playerXLocation--;
                    break;
                }
                    
                case 3:
                {
                    player.setYLocation(-1);
                    playerYLocation--;
                    break;
                }
            }
        }
    }
    
    /////////////////////////////////////////////////////////////////
    /////////////////////////////////////////////////////////////////
    
    @Override
    public void render(Graphics2D g) 
    {
        //Updates Logic in other Methods
        logicUpdate();
        
        //Render Map
        for(int row = 0; row < mapHeight; row++)
        {
            for(int column = 0; column < mapWidth; column++)
            {
                switch(currentMap[column][row]) //Note: To increase the player's walking speed just times both the playerXPosition and playerYPosition by a speed multiplyer
                {
                    case -1237980: //Grass
                    {
                        g.drawImage(resource.getSprite(2, 0, 0), column*40 - playerXLocation, row * 40 - playerYLocation, null);
                        break;
                    }

                    case -3584: //Grass Flower 1
                    {
                        g.drawImage(resource.getSprite(2, 0, 1), column*40 - playerXLocation, row * 40 - playerYLocation, null);
                        break;
                    }

                    case -16735512: //Grass Flower 2
                    {
                        g.drawImage(resource.getSprite(2, 0, 2), column*40 - playerXLocation, row * 40 - playerYLocation, null);
                        break;
                    }

                    case -14503604: //Stone Path
                    {
                        g.drawImage(resource.getSprite(2, 0, 3), column*40 - playerXLocation, row * 40 - playerYLocation, null);
                        break;
                    }
                        
                    case -14503860: //Stone Path
                    {
                        g.drawImage(resource.getSprite(2, 0, 4), column*40 - playerXLocation, row * 40 - playerYLocation, null);
                        break;
                    }
                        
                    case -14504116: //Stone Path
                    {
                        g.drawImage(resource.getSprite(2, 0, 5), column*40 - playerXLocation, row * 40 - playerYLocation, null);
                        break;
                    }
                        
                    case -14504372: //Stone Path
                    {
                        g.drawImage(resource.getSprite(2, 0, 6), column*40 - playerXLocation, row * 40 - playerYLocation, null);
                        break;
                    }
                        
                    case -14504628: //Stone Path
                    {
                        g.drawImage(resource.getSprite(2, 0, 7), column*40 - playerXLocation, row * 40 - playerYLocation, null);
                        break;
                    }
                        
                    case -14504884: //Stone Path
                    {
                        g.drawImage(resource.getSprite(2, 0, 8), column*40 - playerXLocation, row * 40 - playerYLocation, null);
                        break;
                    }
                        
                    case -14505140: //Stone Path
                    {
                        g.drawImage(resource.getSprite(2, 0, 9), column*40 - playerXLocation, row * 40 - playerYLocation, null);
                        break;
                    }
                        
                    case -14505396: //Stone Path
                    {
                        g.drawImage(resource.getSprite(2, 0, 10), column*40 - playerXLocation, row * 40 - playerYLocation, null);
                        break;
                    }
                        
                    case -14505652: //Stone Path
                    {
                        g.drawImage(resource.getSprite(2, 0, 11), column*40 - playerXLocation, row * 40 - playerYLocation, null);
                        break;
                    }
                }
            }
        }
        
        
        //Render Player
        //Whenever you get diagonal movement animations on the player sprite create more direction numbers for the diagonal movement and then add the stuff to render the diagonal animations below
        if (!playerIsWalking)
        {
            spriteCounter = 0;
            spriteCounterTwo = 0;
        }
        else if(playerIsWalking && spriteCounter == 0)
        {
            spriteCounter = 1;
        }
        
        if (spriteCounter == 0 && !playerIsWalking)
        {
            g.drawImage(resource.getSprite(0, playerDirection, spriteCounter), 628, 499, null);
        }
        else if (spriteCounter == 1 && playerIsWalking && spriteCounterTwo >= 15)
        {
             g.drawImage(resource.getSprite(0, playerDirection, spriteCounter), 628, 499, null);
             spriteCounter++;
             spriteCounterTwo = 0;
        }
        else if (spriteCounter == 1 && playerIsWalking && spriteCounterTwo < 15)
        {
             g.drawImage(resource.getSprite(0, playerDirection, spriteCounter), 628, 499, null);
        }
        else if (spriteCounter == 2 && playerIsWalking && spriteCounterTwo >= 15)
        {
            g.drawImage(resource.getSprite(0, playerDirection, spriteCounter), 628, 499, null);
            spriteCounter--;
            spriteCounterTwo = 0;
        }
        else if (spriteCounter == 2 && playerIsWalking && spriteCounterTwo < 15)
        {
            g.drawImage(resource.getSprite(0, playerDirection, spriteCounter), 628, 499, null);
        }
    }
    
    //Set methods
    public void setCurrentMap()
    {
        currentMap = resource.getMap();
    }
}

Movement

package Entity;

import Core.KeyboardListener;
import java.awt.event.KeyEvent;

public class Player extends Entity
{
    private int xLocation = 0, yLocation = 0, direction = 0;
    private boolean isWalking = false;
    
    public Player()
    {
    }
    
    public void logicUpdate()
    {
        if(KeyboardListener.isKeyPressed(KeyEvent.VK_W) || KeyboardListener.isKeyPressed(KeyEvent.VK_UP))
        {
            //Up
            yLocation--;
            isWalking = true;
            direction = 1;
        }
        else if(KeyboardListener.isKeyPressed(KeyEvent.VK_S) || KeyboardListener.isKeyPressed(KeyEvent.VK_DOWN))
        {
            //Down
            yLocation++;
            isWalking = true;
            direction = 3;
        }
        else if(KeyboardListener.isKeyPressed(KeyEvent.VK_A) || KeyboardListener.isKeyPressed(KeyEvent.VK_LEFT))
        {
            //Left
            xLocation--;
            isWalking = true;
            direction = 0;
        }
        else if(KeyboardListener.isKeyPressed(KeyEvent.VK_D) || KeyboardListener.isKeyPressed(KeyEvent.VK_RIGHT))
        {
            //Right
            xLocation++;
            isWalking = true;
            direction = 2;
        }
        else
        {
            isWalking = false;
        }
    }
    
    //Set Methods
    public void setXLocation(int x)
    {
        xLocation += x;
    }
    
    public void setYLocation(int x)
    {
        yLocation += x;
    }
    //Get Methods
    public int getXLocation()
    {
        return xLocation;
    }
    
    public int getYLocation()
    {
        return yLocation;
    }
    
    public boolean getIsWalking()
    {
        return isWalking;
    }
    
    public int getDirection()
    {
        return direction;
    }
}

To get where the player’s position on the map[][] array is, I use this:


int tempInt = 15;
        int tempIntTwo = 12;
        
        if(playerXLocation> 0)
        {
            tempInt = 16;
        }
        
        if(playerYLocation> 0)
        {
            tempIntTwo = 13;
        }
        
        int xPositionOnMap = ((playerXLocation/ 40)) + tempInt;
        int yPositionOnMap = ((playerYLocation/ 40)) + tempIntTwo;

As for the improvements to the switch statement, that’ll help a lot! I’m first going to look into hashmaps first before I attempt to use them.

Ah, next time use the pastebin (Link below the text area) for a large chunk of code. :3

Alright, I was making some assumptions based on the code you had posted, here they are:

  1. The player’s location is represented by a screen pixel location (In this case, the center of their sprite).
  2. You know the dimensions of your screen.

The first assumption leads to playerX being the player’s X pixel location and that playerY is the player’s Y pixel location. (I was hand typing things I try to keep the length of my variable names short, those two values are playerXLocation and playerYLocation respectively. Assuming that it’s pixel data).
The second assumption allows us to find the displayed bounds of the screen by tiles. Let’s say that the player’s location is (400,500) and that the display is (480,320), and that tiles are 40 pixels wide/high. Looking at we can substitute and get
int startX = (playerX - halfWidth) / tileX - 1;
startX = (400 - 240) / 40 - 1;
startX = (160) / 40 - 1;
startX = 4 - 1;
startX = 3.
This means that to only call paint for tiles on the screen, we’d start drawing at 3 and end at some endX (Which we’d find in the same way).

Anyway, your paint loop would compute those four values and use them as a bounds for painting. Ah, I can post some code (My aborted platformer project) which has some code for doing the bound finding and paint loop.

Hmm… I can’t see if it’s working or not but I’ve altered the map rendering code. I tried using a very large map (400x400 pixels in size which is a lot of tiles) and you could easily see that the game was slower and lagging just as it did before I edited the rendering code. I’m going to try and mess around with the code to see if I can check if it’s working somehow.

Edit:
Derp, it looks like I forgot to add the startY, startX, endX, endY to the for loop that renders the map… Back to testing!

Edit 2:
I’m getting a lot of ArrayIndexOutOfBounds errors. Attempting to figure out a fix for them now…

Edit 3:
After testing out your code a little bit I managed to create a variant of it that works somewhat the same although I still get ArrayIndexOutOfBounds errors. I’m working on fixing them now.

Edit 4:
Managed to get it working properly. All that’s left now is to figure out how to optimize map loading so that it doesn’t spend a few minutes loading a 1000x1000 pixel image and then error out because it’s using 100% CPU. Everything except for the map loading is working amazingly compared to how it was before, thanks a ton! ;D