LibGdx How to Scroll using OrthographicCamera?

12,438

Solution 1

Its not clear how your drawing? I'm not sure if your doing this approach correctly.. Can you provide details of your background and ship? Can you provide details on you background image, is it a huge image that your scrolling around or is it a repeated image you want to repeat as you scroll?

--EDIT--

ok i think i have an idea what might be up. I would normally apply the camera to the current context.

Place the following in your resize

    public void resize(int width, int height) {
    cam = new OrthographicCamera(width, height);
    cam.translate(width / 2, height / 2, 0);
}

Place the following in the start of your render()

cam.position.set(posX,posY,0);
cam.update();
cam.apply(Gdx.gl10);
Gdx.gl.glClearColor(0,0,0,1);
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT); // #14

This will make you have a clear screen with the origin set at the bottom left of the window. You should then draw your background first

spriteBatch.setProjectionMatrix(cam.combined);
spriteBatch.begin();
spriteBatch.draw(background,0,0,sizeX,sizeY);
spriteBatch.end()

see how that looks as you move your camera position posX and posY. Then add your ship to the mix

-- MORE EDITS ---

you can then calculate the posX and posY as

posX = defaultOffsetX+shipX

and so on..

Anyhow hope this helps I'm still only learning myself so this might not be the best method.. but it seems to work.

Solution 2

I can't tell if this is your only mistake, but this is ONE mistake. If this is what you say you were doing:

spriteBatch.begin();
drawBackground();
drawShip();
spriteBatch.setProjectionMatrix(camera.combined); 
spriteBatch.end();

You wont see anything. When setProjectionMatrix is called inside a begin()/end() block. the current batch is flushed to the gpu. So, you are actually not drawing anything with the camera matrix. You should do this instead:

    spriteBatch.setProjectionMatrix(camera.combined); 
    spriteBatch.begin();
    drawBackground();
    drawShip();
    spriteBatch.end();

EDIT:

If you don't call that line, spriteBatch uses its own default camera (which wont notice your camera.update() modifications, so that's not what you want).

You should now pay more attention to the coordinates you are using. I'm not quite sure you really need the ppu conversion thing. To begin with, define everything in imaginary world coordinates, note that you'll see some stretching in your world.

public void drawShip(){
    spriteBatch.draw(shipTexture,ship.getPosition().x,ship.getPosition().y, 10, 10);
}//your ship is 10 units wide and tall!

public void drawBackground(){
    spriteBatch.draw(background, -10,0, 500, 100);     
} //your background is 500 units wide, and 100 units tall

//camera setup
camera = new OrthographicCamera(50, 50);
//your camera will print to screen 50 units of your world

If you get to see a stretched world, try to understand how it's working (if you can't see anything, there is something wrong somewhere).

EDIT 2

I took a look at your code. First remove ppu's, as it obscures your code. You were setting your cam position to the ship.postion, while drawing at ship.position * ppu. Also your background was way too big (that's why you see it pixelated). You should see something reasonable with this. (someday you'll have to initialize your camera in another way to deal with stretching, but forget it until you understand how all works).

this.cam = new OrthographicCamera(CAMERA_WIDTH,CAMERA_HEIGHT);

public void drawShip(){ 
    spriteBatch.draw(shipTexture, ship.getPosition().x ,ship.getPosition().y, 10, 10);
}

public void drawBackground(){
    spriteBatch.draw(background, -CAMERA_WIDTH/2, -CAMERA_HEIGHT/2, 100, 100); //let bg begin where camera starts. (0,0)
}


public void render(float delta){ 
    ship.Move(delta);
    moverCamara(ship.getPosition().x, ship.getPosition().y);
    spriteBatch.setProjectionMatrix(cam.combined);
    spriteBatch.begin();
        drawBackground();
        drawShip();
    spriteBatch.end();
}
Share:
12,438
MBRebaque
Author by

MBRebaque

Updated on June 05, 2022

Comments

  • MBRebaque
    MBRebaque almost 2 years

    enter image description here

    I have been looking for 10 hours (literally) and I'm done, I need to ask. Thing is I'm learning How use LibGdx to program Java games. I'm doing a Horizontal Space Ship Game. So, my worst problem here is that I do not know how do scroll (I think draw will explain better). I want to draw a huge background (Space) and make my OrthographicCamera move right like with my SpaceShip, so it will create a Scroll effect with the Space Background. No enemies and nothing but the ship on the screen.

    I'm trying this:

     public void moveCamera(float x,float y){
        cam.position.set(x, y, 0);
     }
    

    Then I use that method in my WorldRender render() method:

    public void render(float delta){ 
        ship.Move(delta);
        moveCamera(ship.getPosition().x,ship.getPosition().y);
        cam.update();
        System.out.println(""+cam.position);
        spriteBatch.begin();
            drawBackground();
            drawShip();
        spriteBatch.end();
    }
    

    I actually move the camera position (I can see that thanks to the println), but It isn't moving in the game, so SpaceShip just disappears by the edge of the window.

    I also tried this before spriteBatch.end()

    spriteBatch.setProjectionMatrix(camera.combined);
    

    but when I do that windows only shows a black screen, no ship, no nothing. As I said, I'm desperate, I see lot of examples (scroll with mouse, paralexscrolling etc) but all are to advanced or just nothing to do with my code.

    This is how I draw stuff. Background and ship are textures inside WorldRender. I draw background image very wide, so my intention is do some scrolling over as I said. That's the code

    private void loadTextures(){
        shipTexture=new Texture(Gdx.files.internal("nave.png"));
        background=new Texture(Gdx.files.internal("fondo.jpg"));
    }
    
    public void drawShip(){
        spriteBatch.draw(shipTexture,ship.getPosition().x*ppuX,ship.getPosition().y*ppuY, ship.WIDTH*ppuX,ship.HEIGHT*ppuY);
    }
    
    public void drawBackground(){
        spriteBatch.draw(background, -10*ppuX,0*ppuY, Gdx.graphics.getWidth()*10,Gdx.graphics.getHeight());     
    }
    

    Here you can download the code if someone want to help in hardcore mode

    My code (not working)

    I FINALLY SOLVED IT!

    That's the code I used in a class name WorldRenderer, which have methods that are called within GameScreen for render, resize etc

     public WorldRenderer(World world) {
        // TODO Auto-generated constructor stub
        
        this.world=world;
        this.ship=world.getShip();
        this.cam = new OrthographicCamera(CAMERA_WIDTH,CAMERA_HEIGHT);
        
        this.cam.setToOrtho(false,CAMERA_WIDTH,CAMERA_HEIGHT);
        this.cam.position.set(ship.getPosition().x,CAMERA_HEIGHT/2,0);
        this.cam.update();//actualizamos la camara
        spriteBatch=new SpriteBatch();
        loadTextures();
    }
    
    private void loadTextures(){
        shipTexture=new Texture(Gdx.files.internal("nave.png"));
        background=new Texture(Gdx.files.internal("fondo.jpg"));
    }
    
      public void drawShip(){
              spriteBatch.draw(shipTexture,ship.getPosition().x,ship.getPosition().y,10,10);
    }
    
    public void drawBackground(){
        spriteBatch.draw(background, 0,0, 500,50);
    } 
    
     public void render(float delta){ 
        ship.Move(delta);
        moveCamera(ship.getPosition().x);
        spriteBatch.setProjectionMatrix(cam.combined); 
        spriteBatch.begin();
            drawBackground();
            drawShip();
        spriteBatch.end();
    }
    
     public void moveCemara(float x){
        cam.position.set(x+20,cam.position.y, 0);
        cam.update();
    }
    

    Inside the Ship I have this method which I call within render in WorldRenderer to move It

    public void Move(float delta){
        if(Gdx.input.isKeyPressed(Keys.LEFT)) this.position.x -=velocity *delta;
        if(Gdx.input.isKeyPressed(Keys.RIGHT)) this.position.x +=velocity *delta;
        if(Gdx.input.isKeyPressed(Keys.UP)) this.position.y +=velocity *delta;
        if(Gdx.input.isKeyPressed(Keys.DOWN)) this.position.y -=velocity *delta;
    }
    

    Also I want to thanks very much to the people who helped me. I'm marking first answer as the good one, but, mix both was what gave me the real solution.

    I leave here some tutorials I followed which are pretty good for noobs

    That's a good everything-from-scratching-tutorial LiGdxForNoobs

    A simple platform game platformGame

    A very simple game bucketGame