I'm trying to draw simple text with libGDX on the screen. The thing that I want to consider is the size of the text. I would like to draw score of the player on the screen which i would like it to be big. But even i use the freetype fonts, it's not looking smooth. Here is the code:
SpriteBatch batch;
String string;
FreeTypeFontGenerator generator;
FreeTypeFontParameter parameter;
BitmapFont font;
#Override
public void create () {
batch = new SpriteBatch();
generator = new FreeTypeFontGenerator(Gdx.files.internal("arial.ttf"));
parameter = new FreeTypeFontParameter();
parameter.size = 100;
font = generator.generateFont(parameter);
string = "0123456";
}
#Override
public void render () {
Gdx.gl.glClearColor(0, 0, 0, 1);
batch.begin();
font.draw(batch, string, 50, 400);
batch.end();
}
Am i on the right path to draw the score or some HUD screen to the viewport? Is there a nicer way or is there a way to do this with the fonts easily? (For starting to learn from scratch?)
EDIT: Here is how it looks like
Try setting the minFilter and magFilter of FreeTypeFontGeneratorParameter to Linear, like this:
#Override
public void create () {
batch = new SpriteBatch();
generator = new FreeTypeFontGenerator(Gdx.files.internal("arial.ttf"));
parameter = new FreeTypeFontParameter();
parameter.size = 100;
parameter.minFilter = Texture.TextureFilter.Linear;
parameter.magFilter = Texture.TextureFilter.Linear;
font = generator.generateFont(parameter);
string = "0123456";
}
Related
Trying to place two buttons in a table row.
Right-most button appears slightly offscreen.
Adding to table with .add(btn).right() but seems not to have any effect.
Documentation says something about removing the Align.left and vise-versa but I'm not sure what they're saying.
Working from mobile.
Took pic, uploaded to ImageBucket but can't see whole thing so took two more (top + bottom of screen) just in case.
Top of screen:
https://i1161.photobucket.com/albums/q501/StudioGilliam/Screenshot_20190430-224041_TextBasedRPG.jpg
As you can see, the labels display fine.
Bottom of screen:
https://i1161.photobucket.com/albums/q501/StudioGilliam/Screenshot_20190430-224024_TextBasedRPG.jpg
The offending code:
public class TextBasedRPG implements ApplicationListener
{
private Stage stage;
private TextButton btnNext;
private TextButton btnItems;
private Label lblPlayer1;
private Label lblEnemy1;
private Label lblInfo;
#Override
public void create()
{
stage = new Stage(new ScreenViewport());
Gdx.input.setInputProcessor(stage);
// UI STUFF
// Labels
Label.LabelStyle styleL = new Label.LabelStyle(new BitmapFont(), Color.BLACK);
lblPlayer1 = new Label("Player data", styleL);
lblPlayer1.setFontScale(3.5f);
lblEnemy1 = new Label("Enemy data", styleL);
lblEnemy1.setFontScale(3.5f);
lblEnemy1.setAlignment(Align.right);
lblInfo = new Label("Information", styleL);
lblInfo.setFontScale(4.0f);
// Buttons
TextButton.TextButtonStyle styleTB = new TextButton.TextButtonStyle();
styleTB.font = new BitmapFont();
styleTB.up = new NinePatchDrawable(new NinePatch(new Texture(Gdx.files.internal("ButtonGreyUp.png")), 10, 10, 10, 10));
styleTB.down = new NinePatchDrawable(new NinePatch(new Texture(Gdx.files.internal("ButtonGreyDown.png")), 10, 10, 10, 10));
btnNext = new TextButton("Next Turn", styleTB);
btnNext.setTransform(true);
btnNext.setScale(6.0f);
btnNext.setTouchable(Touchable.enabled);
btnNext.align(Align.right);
btnItems = new TextButton("Play", styleTB);
btnItems.setTransform(true);
btnItems.setScale(6.0f);
btnItems.setTouchable(Touchable.enabled);
// Table
Table table = new Table();
table.setBounds(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
table.setFillParent(true);
table.pad(50);
table.add(lblPlayer1).expandX().left();
table.add(lblEnemy1).expandX().right();
table.row();
table.add(lblInfo).expandY().colspan(2);
table.row();
table.add(btnItems).expandX().left();
table.add(btnNext).expandX().right();
table.debugAll();
stage.addActor(table);
}
#Override
public void render()
{
Gdx.gl.glClearColor(1, 1, 1, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
stage.act();
stage.draw();
}
#Override
public void dispose(){stage.dispose();}
#Override
public void resize(int width, int height){}
#Override
public void pause(){}
#Override
public void resume(){}
I don't recommend using setScale() since it only affects the representation of the actor and causes problems with the actual dimensions within the table.
You should use a fitting width and height for your buttons and use a font with a bigger textsize.
You could use GDX Freetype to generate your fonts with the correct size on startup.
Here is an example approach for the solution:
I use the following approach for my UI elements here as an example for a Label:
This is in my static UIHelper Class:
public static Cell addToTable(Table table, Label label, float width) {
Label.LabelStyle style = new Label.LabelStyle(skin.get("default", Label.LabelStyle.class));
float aspectRatio = style.background.getMinWidth()/style.background.getMinHeight();
float height = width / aspectRatio;
style.font = Assets.font;
style.fontColor = Assets.font.getColor();
label.setStyle(style);
label.setAlignment(Align.center);
return table.add(label).width(width).height(height);
}
Then I can just call:
float width = (float)Gdx.graphics.getWidth()*0.8f; // I want my label to be 80% of the screen width
UIHelper.addToTable(table, levelLabel, width).colspan(3).pad(20);
For my fonts, I do this:
private static BitmapFont generateFont(){
FreeTypeFontGenerator generator = new FreeTypeFontGenerator(Gdx.files.internal("skins/beemelon/passion-one-regular.ttf"));
FreeTypeFontGenerator.FreeTypeFontParameter parameter = new FreeTypeFontGenerator.FreeTypeFontParameter();
parameter.size = (int) (38 * Gdx.graphics.getDensity()); // Change the 38 to a value fit for your game
parameter.color = new Color(255f / 255f, 165f / 255f, 23f / 255f, 1f); // Divide by 255f to get a value between 0 and 1
parameter.borderWidth = parameter.size / 10f;
parameter.borderColor = Color.BLACK;
BitmapFont bitmapFont = generator.generateFont(parameter);
generator.dispose();
return bitmapFont;
}
Hope this helps or pushes you in the right direction.
The way I have been doing it so far is copying the same font, saving under another name and loading it with different parameters. I am trying to develop an app in LibGDX and by saving the font as different files takes more memory than necessary. Isn't there a way of loading 1 font multiple times, each time with different parameters?
Take a look of this example, I am creating a list of BitmapFont object having different size by simply changing attributes of FreeTypeFontGenerator.FreeTypeFontParameter.
public class MainGame extends Game {
SpriteBatch spriteBatch;
BitmapFont font[];
OrthographicCamera camera;
#Override
public void create() {
camera=new OrthographicCamera();
camera.setToOrtho(false,400,640);
spriteBatch = new SpriteBatch();
int size[]=new int[]{5,8,10,13,15,20,30,40,50,60};
font=new BitmapFont[size.length];
FreeTypeFontGenerator generator = new FreeTypeFontGenerator(Gdx.files.internal("BUBBLEGUM.TTF"));
FreeTypeFontGenerator.FreeTypeFontParameter parameter = new FreeTypeFontGenerator.FreeTypeFontParameter();
parameter.color = Color.WHITE;
parameter.magFilter = Texture.TextureFilter.Linear; // used for resizing quality
parameter.minFilter = Texture.TextureFilter.Linear;
for(int i=0;i<size.length;i++){
parameter.size=size[i];
font[i]=generator.generateFont(parameter);
font[i].getRegion().getTexture().setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear);
font[i].setColor(1.0f, 0.0f, 0.0f, 1.0f);
}
generator.dispose(); // Don't forget to dispose
}
#Override
public void render() {
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
Gdx.gl.glClearColor(1,1,0,1);
spriteBatch.setProjectionMatrix(camera.combined);
spriteBatch.begin();
for (int i=0;i<font.length;i++)
font[i].draw(spriteBatch,"LIBGDX FONT",10,100+i*55);
spriteBatch.end();
}
#Override
public void resize(int width, int height) {
camera.setToOrtho(false,width,height);
}
#Override
public void dispose() {
spriteBatch.dispose();
for(BitmapFont bmfont:font)
bmfont.dispose();
}
}
EDIT
https://github.com/libgdx/libgdx/blob/master/tests/gdx-tests/src/com/badlogic/gdx/tests/extensions/FreeTypeFontLoaderTest.java
I have been struggling to get fonts sort of working with libgdx and I finally did it.
But now it's throwing an exception, which I am not able to figure out.
java.lang.NullPointerException: Attempt to read from field 'com.badlogic.gdx.graphics.Color com.badlogic.gdx.graphics.g2d.GlyphLayout$GlyphRun.color' on a null object reference
at com.badlogic.gdx.graphics.g2d.GlyphLayout.setText(GlyphLayout.java:141)
at com.badlogic.gdx.graphics.g2d.BitmapFontCache.addText(BitmapFontCache.java:505)
at com.badlogic.gdx.graphics.g2d.BitmapFontCache.addText(BitmapFontCache.java:487)
at com.badlogic.gdx.graphics.g2d.BitmapFontCache.setText(BitmapFontCache.java:438)
at yt.agar.game.Screens.GameScreen.render(GameScreen.java:213)
at com.badlogic.gdx.Game.render(Game.java:46)
at com.badlogic.gdx.backends.android.AndroidGraphics.onDrawFrame(AndroidGraphics.java:459)
at android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1522)
at android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1239)
GlyphLayout.java:141:
https://github.com/libgdx/libgdx/blob/master/gdx/src/com/badlogic/gdx/graphics/g2d/GlyphLayout.java#L141
I draw the font this way:
BitmapFont font = assetManager.get('arial-96.otf');
font.draw(spriteBatch, "sample text", 10, 10);
I generate the bitmapfont this way, using the AssetManager. I have tried a lot of different fonts, including truetype fonts.
FreetypeFontLoader.FreeTypeFontLoaderParameter font = new FreetypeFontLoader.FreeTypeFontLoaderParameter();
font.fontFileName = "fonts/arial.otf";
font.fontParameters.color = Color.WHITE;
font.fontParameters.borderColor = Color.BLACK;
font.fontParameters.borderWidth = 3;
font.fontParameters.flip = true;
font.fontParameters.characters = FreeTypeFontGenerator.DEFAULT_CHARS;
font.fontParameters.size = 96;
manager.load("arial-96.otf", BitmapFont.class, font);
I can't see that I am doing something wrong.
I tried in this way and it work fine for me :
public class TestGame extends Game {
private AssetManager assetManager;
private SpriteBatch spriteBatch;
#Override
public void create() {
assetManager=new AssetManager();
spriteBatch=new SpriteBatch();
FileHandleResolver resolver = new InternalFileHandleResolver();
assetManager.setLoader(FreeTypeFontGenerator.class, new FreeTypeFontGeneratorLoader(resolver));
assetManager.setLoader(BitmapFont.class, ".otf", new FreetypeFontLoader(resolver));
FreetypeFontLoader.FreeTypeFontLoaderParameter size03Params = new FreetypeFontLoader.FreeTypeFontLoaderParameter();
size03Params.fontFileName = "CHARLEMAGNESTD-BOLD.otf";
size03Params.fontParameters.size = 96;
assetManager.load("CHARLEMAGNESTD-BOLD.otf", BitmapFont.class, size03Params);
assetManager.finishLoading();
}
#Override
public void render() {
spriteBatch.begin();
if(assetManager.update()){
BitmapFont font=assetManager.get("CHARLEMAGNESTD-BOLD.otf");
font.draw(spriteBatch,"HEOOOW",100,100);
}
spriteBatch.end();
}
#Override
public void dispose() {
spriteBatch.dispose();
assetManager.dispose();
}
}
I've been following along with a LibGDX tutorial on Youtube and have come across an issue rendering a TiledMap to my screen. At the moment, I can render some labels/images using my HUD java class
public class HUD {
public Stage stage; //the background
private Viewport viewport; //so the HUD stays fixed and the world can move
private int score;
private int timer;
private int bactoCount;
private Texture foodTexture, antioBioBottle;
//these are widgets
Label antioBioTxt;
Image antiBioImg;
Label countDown;
Label countTxt;
Image foodImg;
Label foodTxt;
Label bactoCountLabel;
Label bactoTxt;
//these images need to be buttons...
public HUD (SpriteBatch sb) {
foodTexture = new Texture("Bacto food.png");
antioBioBottle = new Texture("Antibioticbottle.png");
bactoCount = 0;
timer = 0;
viewport = new FitViewport(BactoBuds.V_WIDTH, BactoBuds.V_HEIGHT, new OrthographicCamera());
stage = new Stage(viewport, sb);
//stage = new Stage();
//use a Table to organise widgets on the stage
Table table = new Table();
table.top();
table.setFillParent(true); //the table is the size of our stage
antioBioTxt = new Label("Antibiotic", new Label.LabelStyle(new BitmapFont(), Color.WHITE));
antiBioImg = new Image(antioBioBottle);
// %03d means its 3 digits long
//bitmap font sets the font to bit style
//string.format for changing from a string to a int
countDown = new Label(String.format("%03d", timer), new Label.LabelStyle(new BitmapFont(), Color.WHITE));
countTxt = new Label("Time to flood:", new Label.LabelStyle(new BitmapFont(), Color.WHITE));
foodImg = new Image(foodTexture);
foodTxt = new Label("Food", new Label.LabelStyle(new BitmapFont(), Color.WHITE));
bactoCountLabel = new Label(String.format("%06d", bactoCount), new Label.LabelStyle(new BitmapFont(), Color.WHITE));
bactoTxt = new Label("Bacteria:", new Label.LabelStyle(new BitmapFont(), Color.WHITE));
//if multiple labels use expandX then they all share an equal portion of the screen
table.add(antioBioTxt).expandX().padTop(10);
table.add(foodTxt).expandX().padTop(10);
table.add(bactoTxt).expandX().padTop(10);
table.add(countTxt).expandX().padTop(10);
table.row();
table.add(antiBioImg).expandX();
table.add(foodImg).expandX();
table.add(bactoCountLabel).expandX().align(Align.center);
table.add(countDown).expandX().align(Align.center);
stage.addActor(table);
}
}
These render nicely on the screen. However, when I try to render up a background TMX map image, it renders in the wrong location. I've been messing with the code for a few days now, trying to change the position of the map position. At the first instance I was only able to see a tiny corner of the map and now I've gotten the whole thing to render, but it only takes up ~1/4 of the screen. Now I am at a loss as to how to proceed.
public class playScreen implements Screen{
private BactoBuds game;
private OrthographicCamera gamecamera;
private Viewport gameView;
private HUD HUD;
private TmxMapLoader mapLoader; //loads map to screen
private TiledMap map; //reference to map
private OrthogonalTiledMapRenderer renderer;
public playScreen (BactoBuds game) {
this.game = game;
gamecamera = new OrthographicCamera();
gameView = new FitViewport(BactoBuds.V_WIDTH, BactoBuds.V_HEIGHT, gamecamera);
HUD = new HUD(game.batch);
mapLoader = new TmxMapLoader(); //make a new map loader, set map to maploader, then pass it to the renderer
map = mapLoader.load("grassy.tmx");
renderer = new OrthogonalTiledMapRenderer(map);
gamecamera.setToOrtho(false);
gamecamera.position.set(gameView.getWorldWidth() / 2, gameView.getWorldHeight() / 2, 0); //this changes map position
renderer.setView(gamecamera);
}
#Override
public void show() {
}
#Override
public void render(float delta) {
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
renderer.render();
game.batch.setProjectionMatrix(HUD.stage.getCamera().combined);
HUD.stage.draw();
}
Please forgive the dodgy coding, I'm quite new and I'm still learning about good practices. I think it has something to do with the camera positioning, but swapping out the values doesn't appear to change anything.
public class BactoBuds extends Game {
public static final int V_WIDTH = 800;
public static final int V_HEIGHT = 480;
public static final String Title = "BactoBuds";
public SpriteBatch batch; //public to let other screens have access to images
private Texture img;
private Game game;
private Screen screen;
private OrthographicCamera camera;
public BactoBuds () {
game = this;
}
#Override
public void create () {
batch = new SpriteBatch();
img = new Texture("badlogic.jpg");
// change this to menuScreen later
setScreen(new playScreen(this));
}
public void dispose () {
batch.dispose();
img.dispose();
}
#Override
public void render () {
super.render();
}
public void resume (){
}
public void pause () {
}
}
Thanks for the help!
You need to call camera.update() within render method.
Have you tried moving your camera? If only 1/4 of the map is visible your camera might be centered at 0,0 while your map uses that as the bottom left origin of the texture.
Try camera.position.set(BactoBuds.V_WIDTH / 2, BactoBuds.V_HEIGHT / 2, 0);
My game start freezing after some time (take too much ram), I want to try draw 3( later more) string using loop method. My code is this:
public class Simple implements ApplicationListener {
private OrthographicCamera camera;
private SpriteBatch batch;
private BitmapFont font;
private GlyphLayout layout;
String a1 = "aa";
String a2 = "bb";
String a3 = "cc";
int a = 0;
#Override
public void create() {
camera = new OrthographicCamera();
camera.setToOrtho(false, 800, 480);
batch = new SpriteBatch();
}
#Override
public void render() {
Gdx.gl.glClearColor(0, 0, 0.2f, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
camera.update();
batch.setProjectionMatrix(camera.combined);
batch.begin();
for (int i = 1; i < 4; i++) {
layout = new GlyphLayout();
font = new BitmapFont();
layout.setText(font, "a" + i);
font.draw(batch, layout, 200 + (15 * i), 200);
}
batch.end();
}
}
To visualize what EpicPandaForce mentioned in the comments:
public class Simple implements ApplicationListener {
private OrthographicCamera camera;
private SpriteBatch batch;
private BitmapFont font;
private GlyphLayout layout;
String a1 = "aa";
String a2 = "bb";
String a3 = "cc";
int a = 0;
#Override
public void create() {
camera = new OrthographicCamera();
camera.setToOrtho(false, 800, 480);
batch = new SpriteBatch();
//Initialize the fields in create()
layout = new GlyphLayout();
font = new BitmapFont();
}
#Override
public void render() {
Gdx.gl.glClearColor(0, 0, 0.2f, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
camera.update();
batch.setProjectionMatrix(camera.combined);
batch.begin();
for (int i = 1; i < 4; i++) {
//Use them like you do.
layout.setText(font, "a" + i);
font.draw(batch, layout, 200 + (15 * i), 200);
}
batch.end();
}
}
I'm not sure if this is going to work. You are not specifying a bitmapfont anywhere so when you draw it using layout you probably get a nullPointerException. In the create method you probably want to initialize font with font = new BitmapFont(Gdx.files.internal("Path to bitmapfont"));.
Using new is a expensive operation. The update() method is being called every frame and you are creating new objects each time it is being called. On top of that BitmapFont() is not a small object. And each time you create a new object for font and layout the previous object it holded needs to be collected by the garbage collector. A basic rule is to never use the new keyword in the update() method but rather change it and/or use it like I did just now. To visualize this in a very simple way:
Object o; // <-- a simple container
new Object(); // <-- a object stored in memory in all it's glory
Object o = new Object(); // <-- container o is now pointing to the memory address of new Object()
Object o = new Object(); // container 0 is now pointing to a different object in memory
//But the old one is still chilling at it's own address and needs to be collected
The problem isn't necessarily that you're creating a new font every render call (though you certainly shouldn't be doing that for performance reasons,) but more that you're not releasing the font from memory via dispose.
Normally garbage collection will clean up after you, but in some cases you need to clean up after yourself. Libgdx utilizes some unmanaged code for performance reasons and so needs you to manually release it. The doc makes this clear, and expounds upon why.
The texture for a BitmapFont loaded from a file is managed. dispose()
must be called to free the texture when no longer needed. A BitmapFont
loaded using a TextureRegion is managed if the region's texture is
managed. Disposing the BitmapFont disposes the region's texture, which
may not be desirable if the texture is still being used elsewhere.
So call dispose when you're done with the font, and initialize your font in your constructor. Otherwise your program will use more and more RAM and performance will be terrible.