如何在libgdx中绘制平滑文本?

如何在libgdx中绘制平滑文本?,libgdx,Libgdx,我试着在我的android游戏中在libgdx上绘制简单的文本,但它看起来很清晰。如何使文本在不同分辨率下看起来平滑?我的代码: private BitmapFont font; font = new BitmapFont(); font.scale((ppuX*0.02f)); font.draw(spb, "Score:", width/2-ppuX*2f, height-0.5f*ppuY); 位图字体是纹理,如果要在将较小的纹理调整为较大尺寸时使其看起来更平滑,则需要确保使用正确

我试着在我的android游戏中在libgdx上绘制简单的文本,但它看起来很清晰。如何使文本在不同分辨率下看起来平滑?我的代码:

private BitmapFont font;

font = new BitmapFont();

font.scale((ppuX*0.02f));

font.draw(spb, "Score:", width/2-ppuX*2f, height-0.5f*ppuY);

位图字体是纹理,如果要在将较小的纹理调整为较大尺寸时使其看起来更平滑,则需要确保使用正确的纹理过滤器


一种解决方案是使用libgdx的FreeType扩展,如前所述。这允许您从.ttf字体动态生成位图字体。通常,一旦知道目标分辨率,您会在启动时执行此操作

下面是一个例子:

int viewportHeight;
BitmapFont titleFont;
BitmapFont textFont;

private void createFonts() {
    FileHandle fontFile = Gdx.files.internal("data/Roboto-Bold.ttf");
    FreeTypeFontGenerator generator = new FreeTypeFontGenerator(fontFile);
    FreeTypeFontParameter parameter = new FreeTypeFontParameter();
    parameter.size = 12;
    textFont = generator.generateFont(parameter);
    parameter.size = 24;
    titleFont = generator.generateFont(parameter);
    generator.dispose();
}
这将获取位图字体中使用的纹理,并将其过滤更改为双线性,从而在向上和向下缩放图像时获得更高的图像质量,但代价是GPU渲染速度稍慢(差异通常不明显)。

  • 使用libgdx网站提供的hiero创建一个.fnt文件
  • 将字体大小设置为150;它将创建一个.fnt文件和一个.png文件
  • 将这两个文件复制到您的资产文件夹中
  • 现在声明字体:

    BitmapFont font;
    
  • 现在在创建方法中:

    font = new BitmapFont(Gdx.files.internal("data/100.fnt"), false); // 100 is the font name you can give your font any name
    
  • 在渲染中:

    font.setscale(.2f);
    
    font.draw(batch, "whatever you want to write", x,y);
    

您应该快速查看自定义字体着色器和/或距离字段字体。它们易于理解,同样也易于实施:

距离字段字体保持平滑,即使您将其放大:


一般来说,你不会看到清晰的文字,因为你是按照特定的分辨率设计游戏的,当你移动到不同的设备时,Libgdx会缩放所有内容以匹配新的分辨率。即使使用线性过滤,文本缩放也不好,因为圆角很容易变形。在一个完美的世界中,您将根据可用像素数在运行时动态创建内容,而不会使用单一的自动缩放

这就是我正在使用的方法:为小屏幕(480 x 320)构建所有内容,当您以更大的分辨率打开它时,我将以更大的大小加载位图字体,并将其应用到Libgdx稍后将自动执行的大小,并将其反转

下面是一个让事情更清楚的例子:

    public static float SCALE;
    public static final int VIRTUAL_WIDTH = 320;
    public static final int VIRTUAL_HEIGHT = 480;


    public void loadFont(){

     // how much bigger is the real device screen, compared to the defined viewport
     Screen.SCALE = 1.0f * Gdx.graphics.getWidth() / Screen.VIRTUAL_WIDTH ;

     // prevents unwanted downscale on devices with resolution SMALLER than 320x480
     if (Screen.SCALE<1)
        Screen.SCALE = 1;

     FreeTypeFontGenerator generator = new FreeTypeFontGenerator(Gdx.files.internal("data/Roboto-Regular.ttf"));

     // 12 is the size i want to give for the font on all devices
     // bigger font textures = better results
     labelFont = generator.generateFont((int) (12 * SCALE));

     // aplly the inverse scale of what Libgdx will do at runtime
     labelFont.setScale((float) (1.0 / SCALE));
     // the resulting font scale is: 1.0 / SCALE * SCALE = 1

     //Apply Linear filtering; best choice to keep everything looking sharp
     labelFont.getRegion().getTexture().setFilter(TextureFilter.Linear, TextureFilter.Linear);
}
公共静态浮标;
公共静态最终int虚拟_宽度=320;
公共静态最终int虚拟_高度=480;
公共void loadFont(){
//与定义的视口相比,真实设备屏幕要大多少
Screen.SCALE=1.0f*Gdx.graphics.getWidth()/Screen.VIRTUAL\u WIDTH;
//防止分辨率小于320x480的设备出现不必要的缩小

如果(Screen.SCALE在更新后有很多东西被弃用,这就是我的工作:

public void regenerateFonts(OrthographicCamera cam, Game game) {
    int size = 18;

    if (cam != null && game != null) {
        // camera and game are provided, recalculate sizes
        float ratioX = cam.viewportWidth / game.getW();
        float ratioY = cam.viewportHeight / game.getH();
        System.out.println("Ratio: [" + ratioX + ":" + ratioY + "]");

        size *= ratioY;
    }

    // font parameters for this size
    FreeTypeFontParameter params = new FreeTypeFontParameter();
    params.flip = true; // if your cam is flipped
    params.characters = LETTERS; // your String containing all letters you need
    params.size = size;
    params.magFilter = TextureFilter.Linear; // used for resizing quality
    params.minFilter = TextureFilter.Linear; // also

    // Lato Light generator
    FreeTypeFontGenerator generator = new FreeTypeFontGenerator(Gdx.files.internal("fonts/Lato-Light.ttf"));

    // make the font
    fontLatoLight = generator.generateFont(params);
    generator.dispose(); // dispose to avoid memory leaks
}
当您要在屏幕上渲染时:

// text rendering
fontLatoLight.setColor(Color.WHITE); // set color here (has other overloads too)
fontLatoLight.draw(batch, "Hello World!", xCoord, yCoord);

??这只是解释了如何使用当前版本中不推荐使用的.scale()方法。

我使用Libgdx平滑文本的解决方案

我使用BitmapFont,并使用Hiero工具生成3种不同大小的相同字体 示例Arial 16、Arial 32、Arial 64

我将它们放在我的资产文件中,并根据屏幕大小仅使用(加载)其中一个

if(Gdx.graphics.getWidth() < (480*3)/2)
        {
            textGametFont = BitmapFont(Gdx.files.internal(nameFont+16+".fnt"),
                    Gdx.files.internal(nameFont+16+".png"), false);
        }else
        {
            if(Gdx.graphics.getWidth() < (3*920)/2)
            {

                textGametFont = new BitmapFont(Gdx.files.internal(nameFont+32+".fnt"),
                        Gdx.files.internal(nameFont+32+".png"), false);
            }else
            {
                textGametFont = new BitmapFont(Gdx.files.internal(nameFont+64+".fnt"),
                        Gdx.files.internal(nameFont+64+".png"), false);
            }
        }
缩放图像

要处理设备所有类型分辨率的字体大小,我使用这两个函数

public static float xTrans(float x)
{
    return x*Gdx.graphics.width/(YourModel.SCREEN_WIDTH);
}

public static float yTrans(float y)
{
    return y*Gdx.graphics.height/YourModel.SCREEN_Height;
}
我使用的模型屏幕分辨率是

屏幕宽度=480

屏幕高度=320

将比例设置为字体

textGametFont.setScale((xtrans(yourScale)+ ytrans(yourScale))/2f);
最后画出你的文字

textGametFont.draw(batch, "WINNER !!", xTrans(250), yTrans(236));

希望这是清楚和有用的!!!

场景2D中,如果您想对所有标签应用抗锯齿,请在第一个屏幕的构造器上显示:

skin.getFont("default-font").getRegion().getTexture().setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear);
这是我游戏中的第一个屏幕:

...
public class MainMenuScreen implements Screen {    
    public MainMenuScreen() {
        ...
        skin.getFont("default-font").getRegion().getTexture().setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear);
    }
}
字体名称位于ui.json文件中,请检查BitmapFont和Label$LabelStyle部分:


查看博客文章。不要缩放,但要为每种字体创建合适的字体。ppu也不好。每一个使用像素转换的教程都会出错。以你决定的对象大小绘制,并告诉相机你的游戏世界要绘制多少。请添加一些解释。他已经对字体纹理应用了线性纹理过滤。似乎我s在某些设备上很有意义——在我的例子中是Nexus7(1代)这个解决方案对我很有帮助。如何使字体纹理生成mipmap?现在,字母是黑色块。这不是绝对正确的。你可以在着色器中为字体着色。你可能想说你一次只能使用一种颜色。但即使这样,也可以通过更复杂的着色器或附加纹理来克服。如何n我是用皮肤做的吗?@AlexKapustian,你有什么解决办法吗……事实上,问题是如何在Scene2d.ui中已有的小部件中使用这个距离域字体功能。这不是最直接的解决办法,因为它需要花一些精力来研究指南,但它是值得的!文本显示得很漂亮!谢谢!这是一个很好的解决方案这种方法使字体明显优于线性筛选。而且似乎比实现距离字段容易得多。请注意,在调整字体大小时,它看起来仍然有点糟糕。如果您有更好的字体大小筛选(或其他)配置,请发表评论
generateFont(int)
现在已被弃用。我们应该使用什么方法来生成字体?@user824294只需编辑答案,只需被作者或某个版主接受即可,但您可以看到,这需要付出一些努力来完成所有工作,但所有工作都值得一试。谢谢您。请注意,“hiero”必须从源代码执行,没有可用的预构建jar。Hiero说明如下:
textGametFont.draw(batch, "WINNER !!", xTrans(250), yTrans(236));
skin.getFont("default-font").getRegion().getTexture().setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear);
...
public class MainMenuScreen implements Screen {    
    public MainMenuScreen() {
        ...
        skin.getFont("default-font").getRegion().getTexture().setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear);
    }
}
"com.badlogic.gdx.graphics.g2d.BitmapFont": {
    "default-font": {
      "file": "default.fnt"
    }
  },
"com.badlogic.gdx.scenes.scene2d.ui.Label$LabelStyle": {
    "default": {
      "font": "default-font",
      "fontColor": "white",
    }
  },