libgdx中多个摄像头和视口的问题

时间:2017-07-18 00:25:47

标签: java android camera libgdx

所以我正在做一个简单的游戏,但我想我可能会让事情复杂化。我有一个用于GameScreen的摄像头和一个跟随玩家位置的viewPort,当它到达两侧的点时,摄像头停止跟随玩家并保持在一个点。

这本身工作正常,但后来我想在游戏中添加暂停菜单和其他一些功能,创建一个带有自己的相机和视口的hud类,以及一个舞台和一个shapeRenderer。

问题出现在我在gameScreen中创建这个hud的实例时,我在玩的时候看的相机看起来像是hudCam,它不跟随播放器,基本上不让我看到播放器时它到达屏幕的边缘。

这是我的GameScreen类:

public class GameScreen implements Screen {

    WowInvasion game;
    ScrollingBackground background;
    private OrthographicCamera gameCam;
    private Viewport gameViewPort;

    /*
    Basically I wanna keep the same sprites running while in the menu, playing and till dead

    therefore, I'll have a switch statement with cases on where the games at, inside the functions needed. That way I'll keep
    the game has a background for the menu and there's no need for running a second screen.
     */
    public static final int MAIN_MENU = 0;
    public static final int GAME = 1;
    private static int state = 1; //current state. starts with MAIN_MENU //DEBUGGING GAME SCREEN

    //STAGES
    private GameStage gameStage; //game ui
    private menuStage mainMenu; //Main menu of the game
    private Hud hud;

    //Resources
    private TextureAtlas atlas; //for the textures most
    private Skin skin; //for the styles and fonts

    //Sprites
    private Player player;

    //Shapes
    private float progressPower; //for the power to build up
    private final float POWER_CHARGED = 1000; //limit to get power
    private final float DECREASING_POWER = 20; //limit to get power

    public GameScreen(WowInvasion game){
        this.game = game;
        gameCam = new OrthographicCamera();
        gameCam.setToOrtho(false, WowInvasion.WIDTH, WowInvasion.HEIGHT);
        gameViewPort = new StretchViewport(WowInvasion.WIDTH, WowInvasion.HEIGHT, gameCam);
        progressPower = 0f;
        game.wowAssetManager.loadTexturesGameScreen(); // tells our asset manger that we want to load the images set in loadImages method
        game.wowAssetManager.loadSkins(); //load the needed skins
        game.wowAssetManager.manager.finishLoading(); // tells the asset manager to load the images and wait until finsihed loading.
        skin = game.wowAssetManager.manager.get("ui/menuSkin.json");
    }

    @Override
    public void show() {
        game.batch.setProjectionMatrix(gameCam.combined);
        background = new ScrollingBackground();
        atlas = game.wowAssetManager.manager.get(WowAssetManager.GAME_ATLAS); //declaring atlas
        mainMenu = new menuStage(gameViewPort, game.batch, skin, game); //pass it so that we only use one batch and one same viewport
        gameStage = new GameStage(gameViewPort, game.batch, skin, game);
        hud = new Hud(game.batch, skin);
        player = new Player(atlas.findRegion("player"), (int) gameCam.viewportWidth / 2, (int) gameCam.viewportHeight / 2);

        switch(state){
            case MAIN_MENU:
                Gdx.input.setInputProcessor(mainMenu);
                break;
            case GAME:
                background.setFixedSpeed(false); //does not work in here
        }
    }

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

        if(state ==  GAME) {
            background.setFixedSpeed(false);
            player.update(delta, gameCam.viewportWidth, gameCam.viewportHeight); //updating player for movement
           //really cheap way to charge power with velocity
            if(progressPower != POWER_CHARGED) {
                progressPower += Math.abs(player.getVelocity().x) + Math.abs(player.getVelocity().y);
                progressPower -= DECREASING_POWER;
            }
            else
                progressPower = POWER_CHARGED / 4;
        }


        mainMenu.act(Math.min(Gdx.graphics.getDeltaTime(), 1 / 30f)); //updating while making sure delta won't be more than 1/30f.
        gameStage.act(Math.min(Gdx.graphics.getDeltaTime(), 1 / 30f));
        game.batch.begin();
        background.updateAndRender(delta, game.batch); //updating scrolling background
        player.draw(game.batch);
        game.batch.end();
        mainMenu.draw(); //draw the menu stage
        gameStage.draw(); //draw the ui stage for the game
        hud.getStage().draw();
        hud.renderRotateMeter();

        updateCamera(0, WowInvasion.WIDTH);
        System.out.println(player.getPosition().x);
    }

    public void updateCamera(float startX, float endX){
        Vector3 position = gameCam.position;
        //linear interpolation : a + (b - a) * lerp
        //b = player position
        //a = current camera position
        //lerp = interpolation factor
            position.x = gameCam.position.x + (player.getPosition().x - gameCam.position.x) * .1f;

        //making the camera stay when the player gets to close to the sides
        if(position.x < startX) {
            position.x = startX;
        }

        if(position.x > endX){
            position.x = endX;
        }

        gameCam.position.set(position);
        gameCam.update();
    }

    @Override
    public void resize(int width, int height) {
       gameViewPort.update(width, height);
        //hud.getViewport().update(width, height);
    }

    @Override
    public void pause() {

    }

    @Override
    public void resume() {

    }

    @Override
    public void hide() {
        dispose();
    }

    @Override
    public void dispose() {
        mainMenu.dispose();
        gameStage.dispose();
        game.dispose();
        hud.dispose();
    }

    public static void setState(int state) {
        GameScreen.state = state;
    }

}

这是我的HUD:

public class Hud implements Disposable{

    private Stage stage;
    private Viewport viewport;
    Button buttonPause, buttonResume;
    private OrthographicCamera hudCam;
    private ShapeRenderer sp; //like a batch for shapes

    public Hud(SpriteBatch sb, Skin skin){
        hudCam = new OrthographicCamera();
        hudCam.setToOrtho(false, WowInvasion.WIDTH, WowInvasion.HEIGHT);
        viewport = new StretchViewport(WowInvasion.WIDTH, WowInvasion.HEIGHT, hudCam);
        stage = new Stage(viewport, sb);
        sp = new ShapeRenderer();

        Table table = new Table();
        table.top();
        //this makes the table the size of the stage
        table.setFillParent(true);

        buttonPause = new Button(skin, "pause");
        buttonPause.setTransform(true);
        buttonPause.addListener(new ClickListener(){ //listener to handle event
            @Override
            public void clicked(InputEvent event, float x, float y) {

            }
        });

        buttonResume = new Button(skin, "resume");
        buttonResume.setTransform(true);
        buttonResume.setScale(0.5f);
        buttonResume.addListener(new ClickListener(){
            @Override
            public void clicked(InputEvent event, float x, float y) {
                buttonResume.setVisible(false);

            }
        });

        table.add(buttonPause);
        table.row();
        table.add(buttonResume);

        stage.addActor(table);
    }

    public void renderRotateMeter(){
        sp.setProjectionMatrix(hudCam.combined);
        sp.begin(ShapeRenderer.ShapeType.Filled);
        sp.setColor(Color.YELLOW);
        sp.rect(hudCam.position.x,hudCam.position.y, WowInvasion.WIDTH / 2, 20);
        sp.end();
    }

    public Viewport getViewport() {
        return viewport;
    }

    public Stage getStage() {
        return stage;
    }

    @Override
    public void dispose() {
        stage.dispose();
        sp.dispose();
    }
}

提前感谢!

修改

所以我尝试传递gameCam有一个参数到hud而不是制作一个新的OrthographicCamera我使用的那个也有hudCamara以及很好,与玩家的运动是完美的,除了现在来自Hud的thins不一动不动..

1 个答案:

答案 0 :(得分:2)

看起来你只将classmap设置为只有HUD相机,如

所示
projectionMatrix

尝试在绘制调用之前将其设置为与HUD类之外的其他内容相同。

要记住的另一件事是,当您涉及在游戏中使用多个sp.setProjectionMatrix(hudCam.combined); Viewport时,大部分时间它将与{1} {1 {}匹配1}}和你的情况一样使用另一套。在绘制调用中,您还需要调用Camera类的ViewportCamera来告诉系统您将根据哪个视口绘制,因此它将依赖于屏幕坐标由视口附加相机设置。

因此假设您需要在不同的视口中连续调用2个对象,请执行以下代码。根据libgdx API,方法调用是正确的,但变量名称是虚构的。

apply()

总之,绘制在连续绘制调用中使用多个相机和视口的对象时要记住两件事。

  1. 将投影矩阵设置为apply(true)Viewport
  2. 致电// draw objA adhering to viewportA (thus cameraA) <-- assume it's player cam sb.setProjectionMatrix(cameraA.combined); viewportA.apply(); objA.draw(); // draw objB adhering to viewportB (thus cameraB) <-- assume it's HUD cam sb.setProjectionMatrix(cameraB.combined); viewportB.apply(true); // send in true as for HUD, we always want to center the screen objB.draw(); 课程的SpriteBatchShapeRenderer,让它知道您使用此视口。