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 making a sidescroller using java and Lwjgl. But I'm having some trouble getting the screen to actually ... well... sidescroll. The world is randomly generated and drawn in blocks. Like so:

block[x][y] = new Block(BlockType.STONE, x * BLOCK_SIZE, y * BLOCK_SIZE);

At the moment I have it so that the player's sprite just moves around independently. But when I try to move it using the glTranslatef method, nothing happens. 41 blocks by 41 blocks are seen on the screen and I have the total world at 60 blocks by 60 blocks. If you could help me actually get this to work that would be GREAT! :D
If anything is unclear just ask and I'll be sure to update you with whatever is necessary.

Thank you for your time!

EDIT: Here's the code for the map generation, sorry it's so long I'm not sure where to condense it:

for(int x = 0; x < worldW; x++) {
        for(int y = 0; y < worldH; y++) {
            /* Null pointer on THIS line */ block[x][y] = new Block(BlockType.AIR, (x * BLOCK_SIZE) - cam.getX(), (y * BLOCK_SIZE) - cam.getY()); 
        }
    }

    for(int y = 0; y < worldW; y++) {
        for(int x = 0; x < worldH; x++) {       

            //Random dirt (world) generation//
            if(y > worldH / 6) {
                if(rand.nextInt(100) > 10) {
                    try {
                        if(block[x - 1][y - 1].getType() == BlockType.DIRT) {
                            block[x][y] = new Block(BlockType.DIRT, (x * BLOCK_SIZE) - cam.getX(), (y * BLOCK_SIZE) - cam.getY());
                        }
                    } catch(Exception e) { }
                }

                if(rand.nextInt(100) > 10) {
                    try {
                        if(block[x + 1][y - 1].getType() == BlockType.DIRT) {
                            block[x][y] = new Block(BlockType.DIRT, (x * BLOCK_SIZE) - cam.getX(), (y * BLOCK_SIZE) - cam.getY());
                        }
                    } catch(Exception e) { }
                }

                try {
                    if(block[x][y - 1].getType() == BlockType.DIRT) {
                        block[x][y] = new Block(BlockType.DIRT, (x * BLOCK_SIZE) - cam.getX(), (y * BLOCK_SIZE) - cam.getY());
                    }
                } catch(Exception e) { }
                if(rand.nextInt(100) < 10) {
                    block[x][y] = new Block(BlockType.DIRT, (x * BLOCK_SIZE) - cam.getX(), (y * BLOCK_SIZE) - cam.getY());
                }
            }

            //Random stone generation//
            if(y > worldH / 4) {
                if(rand.nextInt(100) > 20) {
                    try {
                        if(block[x - 1][y - 1].getType() == BlockType.STONE) {
                            block[x][y] = new Block(BlockType.STONE, (x * BLOCK_SIZE) - cam.getX(), (y * BLOCK_SIZE) - cam.getY());
                        }
                    } catch(Exception e) { }
                }

                if(rand.nextInt(100) > 20) {
                    try {
                        if(block[x + 1][y - 1].getType() == BlockType.STONE) {
                            block[x][y] = new Block(BlockType.STONE, (x * BLOCK_SIZE) - cam.getX(), (y * BLOCK_SIZE) - cam.getY());
                        }
                    } catch(Exception e) { }
                }

                try {
                    if(block[x][y - 1].getType() == BlockType.STONE) {
                        block[x][y] = new Block(BlockType.STONE, (x * BLOCK_SIZE) - cam.getX(), (y * BLOCK_SIZE) - cam.getY());
                    }
                } catch(Exception e) { }

                if(rand.nextInt(100) < 5) {
                    block[x][y] = new Block(BlockType.STONE, (x * BLOCK_SIZE) - cam.getX(), (y * BLOCK_SIZE) - cam.getY());
                }
            }
        }                       
    }

    //Placing grass blocks//
    for(int y = 0; y < block.length; y++) {
        for(int x = 0; x < block[0].length; x++) {
            if(block[x][y].getType() == BlockType.DIRT && block[x][y - 1].getType() == BlockType.AIR) {
                block[x][y] = new Block(BlockType.GRASS, (x * BLOCK_SIZE) - cam.getX(), (y * BLOCK_SIZE) - cam.getY());
            }
        }
    }

EDIT 2:

Ok, so here's the code that I use for rendering a block itself, not the logic for where to place it, just the block:

public void render() {
    texture.bind();

    glLoadIdentity();
    glTranslatef(x, y, 0);
    glBegin(GL_QUADS);
        glTexCoord2f(0, 0); //Top left texture corner
            glVertex2f(0, 0);
        glTexCoord2f(1, 0); //Top right texture corner
            glVertex2f(BLOCK_SIZE, 0);
        glTexCoord2f(1, 1); //Bottom right texture corner
            glVertex2f(BLOCK_SIZE, BLOCK_SIZE);
        glTexCoord2f(0, 1); //Bottom left texture corner
            glVertex2f(0, BLOCK_SIZE);
    glEnd();
    glLoadIdentity();
}
share|improve this question
    
Are you controlling the player via the keyboard? Do you have a "Map" or "Level" class where you collocate your instantiated tiles? –  Savlon Apr 9 '13 at 6:21
    
Yes, the player is controlled using the arrow keys. Yes, I have a level class where all of the logic for the world generation (and some of the rendering) is done. –  Connor W Apr 9 '13 at 13:07
    
Well in that world generation class do you have a render or draw method? If so create a camera class with x, y, velocityX and velocityY variables, minus those x and y variables from the draw image in your render world method. Set the velx and vely whenever you press a key down to -1 or whichever way you want to go. In your camera class in a tick or logic method add the velocity to the position and kablamo! –  Savlon Apr 9 '13 at 20:25
    
There's a side scroller. In the camera logic method you can also put restrictions on how far it will move and the speed at which it moves at. If you want a bit of code let me know and ill post some... Good luck –  Savlon Apr 9 '13 at 20:26
    
If you could post some code that would be great actually! Thanks for the response by the way! –  Connor W Apr 9 '13 at 23:25
show 1 more comment

closed as too localized by msell, Byte56, Anko, bummzack, Trevor Powell Apr 12 '13 at 13:37

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.If this question can be reworded to fit the rules in the help center, please edit the question.

1 Answer

up vote 7 down vote accepted

Instead of me just giving you the classes and you not knowing what is happening in them, I will provide you with an explanation and run down of what is happening and then you can give it a go yourself.

I believe it's better to teach someone how to fish rather than catching the fish for them :)

Ok so lets get into it!

A camera is basically just an x and y offset. When we say "Move" the camera, we don't move the camera at all. We actually move everything else relative to the camera's position.

Please Note: There are a lot of different ways to implement a camera in a game and this is just one take of it. It is a very simplified version.

First thing to do is create a "Camera" class.

What are some things we need to do with this object?

  • We need to place the camera in a designated position (x and y position)
  • We want to move the camera around (x and y velocity)
  • There are other things we could do with this class. However, these 2 needs will suffice for this example (eg. follow object, zoom out, zoom in etc)

As the above points give us an idea of the variables needed for this class lets add them to the camera class with their getters and setters.

Creating the Camera class

Camera Variables

int x;
int y;
int xVelocity;
int yVelocity;

Camera Constructor

public Camera(int x, int y) {
    this.x = x;
    this.y = y;
    this.xVelocity = 0;
    this.yVelocity = 0;
}

now that our camera class has variables we will need to add an update method which we will call from our map class later on.

This method will be called update() and will be adding the camera velocity to the position.

Camera update method

public void update() {

    x += xVelocity;
    y += yVelocity;

}

Woo! that is our very very simplified camera class!

Implementing our camera in the "Map" class

lets instantiate a Camera in the map class

public Camera camera = new Camera(0, 0);

We just created the camera and placed it's x and y position at coordinates 0, 0

enter image description here

Now that we have instantiated our camera we would like to move the tiles or map in relation to the camera's x and y position. One way of doing this is like so:

lets presume you have a render method in your Map class that cycles through each of your tiles in your Tile[][] 2D array and renders each tile in it's designated position * tile size.

public void render(Graphics g) {
    for (int y = 0; y < mapHeight(); y++) {
        for (int x = 0; x < mapWidth(); x++) {

            Tile tile = getTile(x, y); // Custom method that gets the tile at xy coordinate

            tile.render(x * tile.getWidth(), y * tile.getHeight(), g); // renders tile at designated position
        }
    }
}

Now lets add the code to adjust for our camera's x and y position

NOTE This render method will render the WHOLE map. This can create lag if your map is really large, to overcome this issue I suggest only rendering the tiles inside the screen bounds.

public void render(Graphics g) {
    for (int y = 0; y < mapHeight(); y++) {
        for (int x = 0; x < mapWidth(); x++) {

            Tile tile = getTile(x, y); // Custom method that gets the tile at xy coordinate

            tile.render((x * tile.getWidth()) - camera.getX(), (y * tile.getHeight()) - camera.getY(), g); // renders tile at designated position
        }
    }
}

Now before our camera is ready to be moved we need to implement the "update()" method which is located in the camera class.

public void mapUpdate() {

    camera.update();

}

Note: If you were to apply an x or y velocity to the camera right now you would soon figure out that it just keeps going and wont stop at the map boundaries. I am NOT going to show you how to prevent the camera's x and y position from moving outside of the map bounds as i believe you would be able to implement this feature yourself. You can either place it in the "Map" class update method or the "Camera" class update method, whichever seems more logical to you do that.

"Moving" the camera

We are now able to adjust the camera's x and y position which will adjust our maps position on screen due to the way we are rendering each tile with the camera offset.

NOTE Make sure you have map.update(); in a main update method.

Lets presume you have implemented a keyListener and have instantiated a Map map variable. A basic way to move the camera with keys is as follows:

@Override
public void keyPressed(KeyEvent e) {
    int keyCode = e.getKeyCode();

    switch (keyCode) {
    case KeyEvent.VK_A:
    case KeyEvent.VK_LEFT:
        map.camera.setxVelocity(-1);
        break;
    case KeyEvent.VK_W:
    case KeyEvent.VK_UP:
        map.camera.setyVelocity(-1);
        break;
    case KeyEvent.VK_S:
    case KeyEvent.VK_DOWN:
        map.camera.setyVelocity(1);
        break;
    case KeyEvent.VK_D:
    case KeyEvent.VK_RIGHT:
        map.camera.setxVelocity(1);
        break;
    }

}

@Override
public void keyReleased(KeyEvent e) {
    int keyCode = e.getKeyCode();

    switch (keyCode) {
    case KeyEvent.VK_A:
    case KeyEvent.VK_LEFT:
        map.camera.setxVelocity(0);
        break;
    case KeyEvent.VK_W:
    case KeyEvent.VK_UP:
        map.camera.setyVelocity(0);
        break;
    case KeyEvent.VK_S:
    case KeyEvent.VK_DOWN:
        map.camera.setyVelocity(0);
        break;
    case KeyEvent.VK_D:
    case KeyEvent.VK_RIGHT:
        map.camera.setxVelocity(0);
        break;
    }

}

Now if you run the program and use the arrow keys you will see your map moving around.

Below is a picture of what is happening with the map x and y coordinates and the camera x and y coordinates.

If you were to press the Right arrow key, the process below would happen. The camera would add to it's x position and the map would minus the camera's x position.

enter image description here

This implementation of a camera is very basic and has been simplified for ease of learning.

I hope you learnt something from this. It is basic and it is simplified. There are many ways to implement a camera and this is just one of them. It isn't the most effective nor is it the most efficient. It is merely an implementation for teaching purposes.

Good luck with everything!

EDIT: Download source code here

http://code.google.com/p/camerates/downloads/list

share|improve this answer
1  
Wow! Thanks savlon! This looks great, and thank you for not just giving me the code, this was much more helpful. I'll update the post later when I get a chance to implement the code. Thanks for your time! –  Connor W Apr 10 '13 at 13:37
    
You are welcome :) let me know how you go –  Savlon Apr 10 '13 at 20:00
    
Another question actually, I have quite a bit of code for the world generation, so sould I just add - camera.getWidth() to everyplace that I have x * Tile.tileSize? –  Connor W Apr 11 '13 at 0:51
    
Ideally you would want an easier way to implement a camera. However, for this example I believe it would be fine for you to add - camera.position to every area you have specified in your above comment –  Savlon Apr 11 '13 at 1:55
    
Hmm, well, I added the cam.getX() to all of those instances, but now I get a null pointer exception. I've posted the generation code above, sorry it's a bit long though. –  Connor W Apr 11 '13 at 2:33
show 4 more comments

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