Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I'm toying with creating a tile-based 2D java game engine. I can render the "local" area without issues(I.E. deciding which local tiles to render). The problem came when I introduced floating point locations. I want my "camera" location to be a double. My thought was "I'll multiply the double by the tilesize, round it, and get a pixel approximation". That doesn't work, for one reason or another. The code below is the most functional code I've been able to construct. It works almost entirely correctly except around the 0,0 area it skips tiles(?) and it looks hackish and the code's overall hideous. Is there some easier method I'm missing here, is there an example I can examine?

private HashMap<Integer, HashMap<Integer, Tile>> tiles = new HashMap<>(); // Tiles stored here
public double cameraX = 0, cameraY = 0; // Camera location(centered on screen)
private final int TILE_SIZE = 100; // Size of tiles
private final int TILE_BUFFER = 5; // Buffer of tiles to be rendered/loaded around screen
private int screenTileWidth = 0, screenTileHeight = 0; // Tiles that fit onto the screen

@Override
public void render(Graphics g) {
    // Calculate tile width/height of screen
    int screenWidth = this.screenTileWidth + (TILE_BUFFER * 2), screenHeight = this.screenTileHeight
            + (TILE_BUFFER * 2);

            // Supposedly the offsets from the camera's location to be applied to the rest of the tile locations
    int locOffsetX = (int) Math.round((cameraX % 1) * TILE_SIZE);
    int locOffsetY = (int) Math.round((cameraY % 1) * TILE_SIZE);

            // Big mess of "eww" hackish stuff to fix negatives messing with things
    if (cameraX >= 0 && locOffsetX >= 0) {
        locOffsetX *= -1;
    }
    if (cameraX < 0 && locOffsetX < 0) {
        locOffsetX *= -1;
    }
    if (cameraY >= 0 && locOffsetY >= 0) {
        locOffsetY *= -1;
    }
    if (cameraY < 0 && locOffsetY < 0) {
        locOffsetY *= -1;
    }

            // Base offsets to center tile
    int offsetX = ((GameEngine.g.getWidth() / 2) - (screenTileWidth / 2)
            * TILE_SIZE)
            + locOffsetX;
    int offsetY = ((GameEngine.g.getHeight() / 2) - (screenTileHeight / 2)
            * TILE_SIZE)
            + locOffsetY;

    // Loop through loaded tiles(x/y tile coord)
    for (int x = (int) (Math.floor(cameraX) - (screenWidth / 2)); x < Math
            .floor(cameraX) + (screenWidth / 2); x++) {
        for (int y = (int) (Math.floor(cameraY) - (screenHeight / 2)); y < Math
                .floor(cameraY) + (screenHeight / 2); y++) {
                            // The screen-relative tile coord
            int sx = (int) (x - Math.floor(cameraX));
            int sy = (int) (y - Math.floor(cameraY));

                            // Tile pixel location
            int locX = sx * TILE_SIZE + offsetX;
            int locY = sy * TILE_SIZE + offsetY;

            // Draw box/location info
            g.setColor(Color.RED);
            g.drawRect(locX, locY, TILE_SIZE, TILE_SIZE);
            g.drawString(x + ", " + y, locX + 10, locY + 20);
        }
    }
}
share|improve this question

closed as off-topic by MrCranky, Anko, concept3d, Sean Middleditch, Josh Petrie Feb 8 at 20:06

  • This question does not appear to be about game development within the scope defined in the help center.
If this question can be reworded to fit the rules in the help center, please edit the question.

4  
This question appears to be off-topic because it is about debugging your code for you. –  MrCranky Feb 6 at 8:34
    
@MrCranky I apologize I worded it badly, I was asking for input on better methods of what I was doing. I know well the code I have is broken and probably a bad way of going about things. I wasn't asking for it to be debugged, rather how a problem like it would usually be handled. –  D-Technodude Feb 6 at 12:17
    
@D-T You can always edit to reword. Currently, the question is focused entirely on code. We're a game development site, not a programming site. Could you instead describe the problem you're trying to solve, what you're trying to do and why you think it's not working? It's a lot easier to help (and more useful to future readers) that way. –  Anko Feb 6 at 13:56
2  
@Anko I put it on gamedev because it's related to game development and I figured the developers here would have more experience with implementing such a system. I see your point though and I'll consider it more carefully in the future, thank you. –  D-Technodude Feb 6 at 15:37
    
@MrCranky "would a professional game developer give me a better/different/more specific answer to this question than other programmers?" I think yes because of the fact that, even though it is a programming question, a professional game developer may give a better answer due to the fact that this is the type of issue that a game developer may face or possibly has faced in the past. –  Aidan Mueller Feb 7 at 5:11
add comment

2 Answers

up vote 0 down vote accepted

I believe you are taking up a lot of space with the offset stuff. You could make your code a lot simpler by using translation. Translation is the act of moving the origin of rendering to a different location (the default location of the origin is usually at the top left of the screen). Translation is not specific to Java, but in Java it is usually accomplished by calling the translate method on your Graphics object. The graphics object accepts two integers as parameters. After calling translate, all objects will be drawn relative to the X and Y that you passed into the translate method (note that you may want to first get the AffineTransform from the Graphics object so that you can restore it back to the way it was when you are done rendering).

You way me wondering how this helps. The answer is that the translate method accepts negative numbers as well as positive numbers. What this means, is that you can pass the negated camera X and Y coordinates as parameters. Then when you draw a tile, it will appear as though the camera has moved. With this knowledge, our new render code will look something like the following:

public void render(Graphics g)
{
    AffineTransform at = g.getTransform();
    g.translate(-cameraX, -cameraY);
    for(int x = left; x < right; x++) // left and right represent the horizontal bounds for the tiles that will be drawn.
    {
        for(int y = top; y < bottom; y++) // top and bottom are the same as left and right, except these are the vertical bounds.
        {
            drawTile(g, x, y);
        }
    }
    g.setTransform(at);
}

I never defined the left, right, top, and bottom variables, so you will obviously have to adapt this code to fit your program, but this should help you solve your problem.

share|improve this answer
    
I'm unable to test currently but I'm pretty sure that solves all my problems. My subsequent question would be, if I'm rendering say, 50 tiles, at +10,000 * a tilesize of 100 then translate to that location, is there going to be a lag problem related to that offset/translation being 100,000 pixels? –  D-Technodude Feb 6 at 12:22
    
@D-Technodude As far as I know, the positions passed into the draw functions is always multiplied by the current transformation matrix regardless of whether or not it has been translated or not. I suggest reading this linear algebra tutorial if you want to understand what is actually going on. But the short answer is: No, there would be no difference if you have a large translation. The only thing you should have to worry about, is making sure that you are only rendering visible tiles. –  Aidan Mueller Feb 6 at 18:07
add comment

Double are not always as precise as we may think.

Did you consider using fixed point arithmetic? The would be faster and in your use case it should fix the issue.

For making your code easier to maintain, perhaps you could rethink your coordinate model to have 0,0 in a corner instead of the middle of your tiles map. This way you would have only positive coordinates and you could remove you code which is dealing with sign issues.

Last thing: you may put the expressions you use in your for loops exit conditions in variables so they won't have to be computed for each iteration (this will also make the code easier to read and to debug).

share|improve this answer
add comment

Not the answer you're looking for? Browse other questions tagged or ask your own question.