无法在 Libgdx 中显示文本

Posted

技术标签:

【中文标题】无法在 Libgdx 中显示文本【英文标题】:Can't display text in Libgdx 【发布时间】:2018-08-14 13:28:10 【问题描述】:

我正在使用 Libgdx 制作安卓游戏。我对此很陌生,我不知道为什么我在命令 font.draw() 中的文本没有显示。 一切都在工作,直到我为这个游戏添加了一个阶段。我在代码顺序中也有上层 sb.begin();

我经常在谷歌上搜索,我发誓我至少花了 4 个小时在谷歌上搜索,但都没有成功。

如果有人可以帮助我,我会非常感激。

非常感谢您的回复!

        sb.draw(gameoverImg, cam.position.x - gameoverImg.getWidth() / 2, cam.position.y + 95);
        sb.draw(table, cam.position.x - table.getWidth() / 2 + 33, cam.position.y - 180);


        font.getData().setScale(0.25f);
        font.draw(sb, "" + currentHighScore, cam.position.x + 30, FlappyDemo2.HEIGHT / 2 - 200);
        font.draw(sb, "" + score, cam.position.x + 30, FlappyDemo2.HEIGHT / 2 - 159);




        myTextureRegion = new TextureRegion(playBtn2);
        myTexRegionDrawable = new TextureRegionDrawable(myTextureRegion);
        button = new ImageButton(myTexRegionDrawable); //Set the button up
        button.setPosition(253/2, 112);
        stage = new Stage(new ScreenViewport()); //Set up a stage for the ui
        stage.addActor(button); //Add the button to the stage to perform rendering and take input.


        myTextureRegion2 = new TextureRegion(scoreBtn);
        myTexRegionDrawable2 = new TextureRegionDrawable(myTextureRegion2);
        button2 = new ImageButton(myTexRegionDrawable2); //Set the button up
        button2.setPosition(345, 185);
        stage.addActor(button2);

【问题讨论】:

stage.addActor(font); 怎么样? 你的代码一团糟。那是更新方法吗?您是否每帧都初始化一个新阶段?这不是一个好主意,从 100 小时的基本编程课程/书籍/教程开始,然后暂时离开游戏编程。除此之外,要回答您的问题,我们需要知道SpriteBatch 的设置位置和方式,以及您拥有的ViewportCamera 的大小和位置。它可能绘制在屏幕之外或太小。还要确保String 不为空。 谢谢大家,我通过创建标签解决了这个问题,然后我使用了 stage.addActor(label); @OndřejŠerek 我不认为你“真的”解决了它。我回答了你的问题,我建议你关注它。 【参考方案1】:

如果您对编程很认真,请从基础开始。如果这是您的更新方法,那么您将创建一个 new Stage 和 2 个 new ImageButton 并在每帧加载纹理。如果您考虑一下,您会意识到这是错误的做法。使用 new 关键字是“昂贵的”,因为它创建了一个新对象。在我们快速的计算机上,这无关紧要,但最终您会产生延迟。此外,如果您每帧都创建一个新阶段,那么您将无法真正使用它,因为……旧的每次都会被丢弃。您可以在更新循环之外执行此操作。

如果这不是您的更新方法,则将您绘制的线移动到更新方法。还要确保更新方法每帧清除屏幕。这就是图形通常的工作方式,每一帧屏幕都会被清除,一切都会重新绘制。

我强烈建议您离开游戏编程并从基本的 Java 教程开始。这将使您的生活更轻松,因为此时您正在溺水,如果您不逐步采取这一措施,将会有一段时间。我确实想为您指明正确的方向,希望以下代码能让您大开眼界。编程最重要的部分是使代码工作整洁并结构化。超过 10 行的方法可以拆分为多个方法,并且可读性更高。

我总是使用 LibGDX 中内置的屏幕功能来开始。

TestScreen.java

/**
 * Extending from screen adapter to gain it's functionality and implement the Gesture Listener to use input.
 */
public class TestScreen extends ScreenAdapter implements GestureDetector.GestureListener 

    // Declare fields, here we reserve memory to put the objects in.
    // There is almost never a reason to make your fields public.
    // Expose them with getters and setters if you need too.
    private SpriteBatch spriteBatch;
    private Viewport viewport;
    private Stage stage;

    private BitmapFont font;

    /**
     * The constructor gets run whenever you use the new keyword.
     * This is a good place to initialize the fields.
     */
    public TestScreen() 
        spriteBatch = new SpriteBatch();

        // There are many viewports, this just sets the viewport to the size of the window width and
        // height. Note that most, if not all other viewports ask for worldWidth and worldHeight not
        // screenWidth and screenHeight.
        // It is also important to note that at this point when the code runs the window is not opened
        // yet so the viewport does not get any width. That is why we need to update it in the resize
        // method below, this will also make sure it does it's job when stretching the window.
        viewport = new ScreenViewport();
        viewport.apply();

        // Never load assets and textures in the game loop. Unless of course you let the player load
        // a image but then just load it once and not every frame.
        // I used a random font in my library with the size of 20 pixels.
        font = new BitmapFont(Gdx.files.internal("fonts/sarpanch_20.fnt"));


        // I put the stage setup in it's own method.
        stage = new Stage();
        setupStage();

        // Input multiplexer allows for multiple input sources. In this case we made this screen
        // a GestureListener and the stage also needs input if you want to press buttons.
        Gdx.input.setInputProcessor(new InputMultiplexer(
            new GestureDetector(this),
            stage
        ));
    

    /**
     * This is already a fairly long method. I could have put the click listener in it's own method
     * so we could reuse it on other actors and the code will be more readable.
     */
    private void setupStage() 
        // Use clear instead of the new keyword whenever you can.
        stage.clear();

        // I advice to use the Skin functionality for actor elements. It works great when you know
        // what you are doing. For now, just a style object.
        Label.LabelStyle style = new Label.LabelStyle(font, Color.RED);

        // final makes sure you won't put a new object in the field. It is needed because I use it
        // in the listener/observer pattern below and that only runs when it observers a specific
        // event. Thus it needs to still be the same object.
        final Label label = new Label("Hello World", style);
        label.setPosition(100, 100);

        // Add awesome effect to label.
        label.addListener(new ClickListener() 
            @Override
            public void enter(InputEvent event, float x, float y, int pointer, Actor fromActor) 
                label.getStyle().fontColor = Color.BLUE;
            

            @Override
            public void exit(InputEvent event, float x, float y, int pointer, Actor fromActor) 
                label.getStyle().fontColor = Color.RED;
            
        );
        // Instead I could have moved this click listener to addHoverColor(Actor actor)... 
        // sure, the above code would remain similar but in here it would read.
        // addHoverColor(label);
        // Which is much more readable.

        // add the Label actor to stage.
        stage.addActor(label);
    

    /**
     * render is the game loop. delta is the time since previous frame.
     * @param delta
     */
    @Override
    public void render(float delta) 
        super.render(delta);

        // Unfortunately LibgDX couples logic and drawing in this method.
        // Always remember to do the logic first and then render
        // Let's make 2 methods for that to keep the code neat and decoupled.
        update(delta);
        draw();

        //I use Stage to draw my GUI, the logic goes in update but the gui is always drawn on top
        drawGui();
    


    private void update(float delta) 
        stage.act();
    

    private void draw() 
        //Clear screen and fill it with color.
        Gdx.gl.glClearColor(.05f, .05f, .05f, 1);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);

        // I want to be able to move the camera around so the sprite batch needs to know it projection
        spriteBatch.setProjectionMatrix(viewport.getCamera().combined);

        spriteBatch.setColor(Color.RED);

        spriteBatch.begin();
        //Use the SpriteBatch to draw the font.
        font.draw(spriteBatch, "Hello World", 100, 100);
        spriteBatch.end();

        //System.out.println(viewport.getCamera().viewportWidth);

    

    private void drawGui() 
        stage.draw();
    

    /**
     * resize is called whenever the window changes size. So also at the start when the window is
     * being set to your or default config size.
     * @param width
     * @param height
     */
    @Override
    public void resize(int width, int height) 
        super.resize(width, height);
        viewport.update(width, height);
    

    // Screen adapter also has pause(), resume() and dispose(). But I leave those for now.


    // Following the mandatory methods from the GestureListener. I just use pan to move the camera around
    @Override
    public boolean touchDown(float x, float y, int pointer, int button) 
        return false;
    

    @Override
    public boolean tap(float x, float y, int count, int button) 
        return false;
    

    @Override
    public boolean longPress(float x, float y) 
        return false;
    

    @Override
    public boolean fling(float velocityX, float velocityY, int button) 
        return false;
    

    @Override
    public boolean pan(float x, float y, float deltaX, float deltaY) 
        viewport.getCamera().translate(-deltaX, deltaY, 0);
        viewport.getCamera().update();
        return false;
    

    @Override
    public boolean panStop(float x, float y, int pointer, int button) 
        return false;
    

    @Override
    public boolean zoom(float initialDistance, float distance) 
        return false;
    

    @Override
    public boolean pinch(Vector2 initialPointer1, Vector2 initialPointer2, Vector2 pointer1, Vector2 pointer2) 
        return false;
    

    @Override
    public void pinchStop() 

    

现在我们只需要在主核心类中做一个小改动。

// Extend from game instead of application listener
public class MyGame extends Game 

    @Override
    public void create () 
        // Now you have access to setScreen.
        setScreen(new TestScreen());
    

我希望这是有道理的。它简短而简单,我相信您可以在我无法阅读您的代码时阅读我的​​代码。所以让我再强调一遍,编写整洁的代码是编程最重要的方面。不仅为我们,也为您自己。显然,拥有扎实的语言基础知识有助于做到这一点。

【讨论】:

以上是关于无法在 Libgdx 中显示文本的主要内容,如果未能解决你的问题,请参考以下文章

LibGDX 按钮在触摸时没有响应

libGDX:如何在按键后逐行读取和显示.txt文件中的文本?

LibGDX 日志记录未显示在 logcat 中

如何在ShapeRenderer LibGDX / Java中显示旋转的多边形

库GDX 。绘制多行文本

开源java游戏框架libgdx专题-08-中文显示与绘制