Camera does not follow player

2019-08-06 10:07发布

问题:

I use libgdx have one player which moves in x direction from left to right. Now I want the camera to follow it (like in Flappy Bird for example).

What happen is that the player go out off screen when it reaches the right border of screen and the camera don't follow him.

I have tried following options but none of them worked:

  • camera.position.set(player.getX(), camera.position.y, 0);
  • camera.position.set(player.getX(), 0, 0);
  • Vector3 vector3= camera.unproject(new Vector3(player.getX(), 0f, 0f)); player.setX(vector3.x);

I know that this question already exists on SO but none answer works in this case. Maybe I miss something important that i don't know.


The code:

Game.java class

  public class Game extends com.badlogic.gdx.Game implements   ApplicationListener {
  public static Vector2 VIEWPORT = new Vector2(320, 480);
  public static int WIDTH;
  public static int HEIGHT;


@Override
public void create() {
    WIDTH = Gdx.graphics.getWidth();
    HEIGHT = Gdx.graphics.getHeight();
    // VIEWPORT = new Vector2(WIDTH/2, HEIGHT/2);
    VIEWPORT = new Vector2(WIDTH, HEIGHT);
    setScreen(new GameScreen(this));
 }

@Override
public void resize(int width, int height) {
    // TODO Auto-generated method stub
    super.resize(width, height);
}

@Override
public void resume() {
}

@Override
public void pause() {
}

}

GameScreen.java class

import android.util.Log;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.Preferences;
import com.badlogic.gdx.Screen;
import com.badlogic.gdx.audio.Sound;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.Stage;
import com.badlogic.gdx.scenes.scene2d.ui.Image;
import com.badlogic.gdx.scenes.scene2d.ui.Skin;
import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener;
import com.badlogic.gdx.utils.viewport.FitViewport;
import java.util.Collections;

public class GameScreen implements Screen {

private OrthographicCamera camera;

private Player  player;
private PlayerInputHandler inputHandler1, inputHandler2;
private Sound sound;

FitViewport viewp;

public static int WIDTH;
public static int HEIGHT;


int width_spacing = 0;
int height_spacing = 0;


Stage stage;


Skin skin;


public GameScreen(Game game) {
   stage = new Stage(new FitViewport(Game.WIDTH, Game.HEIGHT));
    camera = (OrthographicCamera)  stage.getCamera();

     Gdx.input.setInputProcessor(stage);
}


@Override
public void show() {
    resetGame();
}

public void resetGame() {


    WIDTH = Gdx.graphics.getWidth();
    HEIGHT = Gdx.graphics.getHeight();
    width_spacing = Game.WIDTH / 24;
    height_spacing = Game.HEIGHT / 14;
    stage.clear();
      skin = new Skin(Gdx.files.internal("data2/uiskin.json"));

    prepareInputHandlers();
    prepare_stage();
}



public void addPlayer() {
    Texture texture = new Texture("player.png");
    player = new Player(texture);
    player.setPosition(Game.WIDTH / 2, Game.HEIGHT * 2 / 3);

    stage.addActor(player);
}


@Override
public void resize(int width, int height) {

    stage.getViewport().update(width, height, true);
}

@Override
public void render(float delta) {
    Gdx.gl.glClearColor(1, 1, 1, 1);
    Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);


    if (delta > 1 / 60f) {
        player.setX(player.getX() + (4 * delta));


               camera.position.set(player.getX(), camera.position.y, 0);



    }

    update();


    stage.act(delta);
    stage.draw();
}

private void update() {

    camera.update();


}

private void prepareInputHandlers() {

    inputHandler2 = new PlayerInputHandler(player, Input.Keys.LEFT, Input.Keys.RIGHT, Input.Keys.UP, Input.Keys.DOWN);
}


@Override
public void dispose() {


    sound.dispose();

    player.getTexture().dispose();
}




public void prepare_stage() {
     addPlayer();

    player.setWidth(64);
    player.setHeight(64);




}
@Override
public void resume() {
    // TODO Auto-generated method stub

}

@Override
public void hide() {
    // TODO Auto-generated method stub

}

@Override
public void pause() {
    // TODO Auto-generated method stub

}
 }

Player.java class

 import com.badlogic.gdx.graphics.Texture;

 public class Player extends com.badlogic.gdx.scenes.scene2d.ui.Image{

private Texture texture;


public Player(Texture texture) {
    super(texture);

  }
     public Texture getTexture() {
    return texture;
}
   @Override
   public void act(float delta) {
    super.act(delta);
   }


  }

回答1:

try to use stage's camera instead of creating your own. Change your GameScreen constructor like this:

    public GameScreen(Game game) 
    {
        stage = new Stage(new FitViewport(Game.WIDTH, Game.HEIGHT));
        camera = (OrthographicCamera) stage.getCamera();

        Gdx.input.setInputProcessor(stage);
    }

then in the render method set the camera position just like

    camera.position.set(player.getX(), camera.position.y, 0);

before camera.update() call


There is also something strange in your code - why you have camera.position.set() and setting player x in this condition:

    if (delta > 1 / 60f) //??
    {
        player.setX(player.getX() + (4 * delta));
        camera.position.set(player.getX(), camera.position.y, 0);
    }

I'm pretty sure you don't need this - but even if you need the

    camera.position.set(player.getX(), camera.position.y, 0);

should be out of if statement because what is happening now is that even if you are changing your player position (using keybord through PlayerInputHandler object) you **don't update camera position. Try to remove if statement or at least do something like

    public void render(float delta) 
    {
        Gdx.gl.glClearColor(1, 1, 1, 1);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);

        if (delta > 1 / 60f) 
        {
            player.setX(player.getX() + (100 * delta));
        }

        camera.position.set(player.getX(), camera.position.y, 0);
        update();

        stage.act(delta);
        stage.draw();
    }

last thing is that if your stage is empty (excluding player) when camera will start to follow player - you will see as player not moving at all :) Add someting more to stage