当前位置: 首页 > 知识库问答 >
问题:

libgdx中多个摄影机和视口的问题

湛财
2023-03-14

所以我在做一个简单的游戏,但我想我可能会把事情复杂化。我有一个相机的游戏屏幕和视口跟随玩家的位置,当它到达侧面的点时,相机停止跟随玩家并停留在一个点。

这本身工作得很好,但是后来我想在游戏中添加暂停菜单和其他一些功能,创建一个带有自己的相机和视口以及舞台和形状渲染器的hud类。

当我在游戏屏幕内创建这个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,而不是制作一个新的正交摄影机,我使用的摄影机也有hudCamara,玩家的动作非常完美,但现在hud的薄薄部分根本不移动。。

共有1个答案

杨征
2023-03-14

看起来您只将projectionMatrix设置为仅HUD摄像头,如中所示

sp.setProjectionMatrix(hudCam.combined);

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

另一件需要记住的事情是,当你在游戏中使用多个视口摄影机时,大多数情况下都是1个视口与1个摄影机匹配,并像你的情况一样使用另一组。在draw调用中,您还需要调用Viewport类的apply()apply(true),告诉系统您将基于哪个视口进行绘制,从而它将遵循视口的附加摄影机设置的屏幕坐标。

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

// 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();

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

  1. 将投影矩阵设置为SpriteBatchshaperender
 类似资料:
  • 我正在尝试围绕我的模型旋转我的透视相机。模型位于中心(0,0,0)点。这是我的旋转相机方法: 我试着去中心,旋转5度,然后回到同样的距离。然而,旋转似乎不起作用,我不知道为什么,任何帮助都非常感谢。

  • 我正在尝试制作一个在实时相机上画画的应用程序。在这种情况下,我用xib创建了一个名为的类,其中所有与绘画相关的功能都在运行。 我正在添加到视图。视图添加正确。但是当我触摸设备屏幕时,应用程序无法绘制任何东西,日志显示以下错误 我添加子视图的代码是 请帮助我,如何在现场摄像机上画画!!! 提前谢谢。 编辑:在绘制视图中,我创建了图像视图,初始化如下 =[[UIImageView alloc]init

  • 我目前有一个游戏,有一个地图是480x3200,一个人从顶部掉下来。镜头跟在人的后面,随着人的下落有平台。平台需要是可触摸的,所以我可以在游戏中旋转和移动它们,所以我把它变成了一个图像,而它原本只是一个精灵。 编辑:

  • 使用摄影机 安装PSP™专用的摄影机(选购品)后,可拍摄静止图像或影像。 若要使用此机能,需先准备另售的周边机器。有关周边机器的详情,请参阅各区域的官方网站。 您使用的PSP™ 必要的周边机器 PSP-1000/2000/3000系列 摄影机(PSP™主机专用) Memory Stick™ PSP-N1000系列 摄影机(PSP™主机专用) 转接线转换器 部分区域可能并未贩卖摄影机。 拍摄图像或影

  • 嗨,我在libgdx切换屏幕时遇到了问题。我正在建造一个小行星游戏克隆。因此,首先呈现我的Main MenuScreen类(使用Fitviewport),然后我调用setScreen()到GameScreen(GameScreen不使用Fitviewport),除了第二个屏幕呈现为使用Fitviewport。如果我调整第二个屏幕的大小,那么整个窗口用于渲染。为什么会发生这种情况?这里有一些图片..

  • 针对不同应用的三维场景需要使用不同的投影方式,比如机械、工业设计领域常常采用正投影(平行投影), 大型游戏场景往往采用透视投影(中心投影)。为了完成三维场景不同的投影方式,three.js封装WebGL API和相关算法,提供了正投影相机OrthographicCamera和透视投影相机PerspectiveCamera。 正投影和透视投影简单解释 下面对正投影相机和透视投影相机的投影算法进行简单