So I'm creating a 2D game and currently following a tutorial for adding custom font to the screen.
What I did is shown in the code below. I only copied the part of code relevant to this topic.
public class GameScreen implements Screen, InputProcessor {
private SpriteBatch batch = null;
private OrthographicCamera mCamera = null;
private BitmapFont scoreFont = null;
private int score = 0;
#Override
public void show() {
mCamera = new OrthographicCamera(1920, 1080);
font_texture = new Texture(Gdx.files.internal("font.png"));
font_texture.setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear);
scoreFont = new BitmapFont(Gdx.files.internal("font.fnt"), new TextureRegion(font_texture), false);
batch = new SpriteBatch();
}
#Override
public void render(float delta) {
Gdx.gl.glClearColor(0, 0, 0, 0);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.setProjectionMatrix(mCamera.combined);
batch.begin();
this.scoreFont.draw(batch, "" + score, 100, 220);
batch.end();
}
The problem is, the text is not showing. Could this be outdated method or what?
If you want to draw fonts on your screen then you have many ways to do that:
A. Using .fnt format
1- Hiero you can run it from your Desktop project with Right Click->Run As->Java Application then choose Hiero then create any style you want on the font then save it as .fnt. This tool will save image automaticaly then move these files into your Android project into assets folder then call font with the following simple code:
BitmapFont bFont = new BitmapFont(Gdx.files.internal("fonts/___.fnt"); // initialization
bfont.draw(batch, "" + score, 100, 220); // in render
2- Shobox is a free Adobe Air based app for Windows and Mac OSX with game and ui related tools. Each tool uses a drag and drop - or clipbord interaction for a quick workflow.
3- Glyph Designer is a powerful bitmap font designer, redesigned specifically for OS X Yosemite to take advantage of the latest features. Create beautiful designs using highly configurable effects, definable backgrounds, custom images, editable glyph metrics and more. Make the most of your screen with smart zooming and full screen support. Target hundreds of devices on multiple platforms with support for over 15 frameworks out the box. Streamline localizations with GDCL.
4- Glyphite is a browser-based Bitmap font generator that can create detailed Bitmap fonts in seconds and export them in most major formats.
B. Using .ttf format
1- First you must insert the FreeType lib in your project, then you can use the following simple code:
FreeTypeFontGenerator generator = new FreeTypeFontGenerator(Gdx.files.internal("fonts/___.ttf"));
FreeTypeFontParameter parameter = new FreeTypeFontParameter();
parameter.size = 12;
BitmapFont font12 = generator.generateFont(parameter); // font size 12 pixels
generator.dispose(); // don't forget to dispose to avoid memory leaks!
The scene2d is good lib and easy to handle Actors with cool hierarchy :
//initialization
LabelStyle style = LabelStyle(bFont, Color.BLUE);
Label label = new Label("", style);
stage.addActor(label);
//in render
stage.act();
stage.draw();
label.setText("" + score);
Related
I recently made the decision to switch over to a newer version of the JDK from the one I was using. (Specifically from jdk1.8.0_261 to jdk-14.0.2). This upgrade when pretty smoothly, as most features work the way I expected them and I was able to find how to adjust to anything that was not the same.
However, as shown in the title, I came across an issue with a specific application I am writing that uses Swing. My main monitor is a 4k monitor, and I have set the windows system scaling for that monitor to 200%. While every other Swing application being scaled to match that DPI setting is nice, for this specific application I want to disable that scaling and have pixels be drawn 1:1, especially when this Application is distributed.
Is there a way to disable this automatic scaling with a VM argument? Or is there a way to disable the scaling at runtime before any calls are made to the swing library? (Similar to how any changes to the look and feel must be done before any other calls to the library.)
For reference:
Here is the code I use to create my JFrame and to create the graphics object I draw everything onto, which happens in a timed loop outside of this class and the scope of this question.
public class ScreenManager {
private GraphicsDevice device;
private final JFrame frame;
private static ScreenManager instance;
public ScreenManager() {
instance = this;
GraphicsEnvironment env = GraphicsEnvironment.getLocalGraphicsEnvironment();
this.device = env.getDefaultScreenDevice();
this.frame = new JFrame(game.getGame().gameName());
this.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.frame.setUndecorated(true);
this.frame.setIgnoreRepaint(true);
this.frame.setResizable(false);
this.device.setFullScreenWindow(frame);
this.device.setDisplayMode(device.getDisplayMode());
this.frame.createBufferStrategy(2);
}
public Graphics2D getRenderGraphics() {
Window window = device.getFullScreenWindow();
if (window != null) {
BufferStrategy strategy = window.getBufferStrategy();
Graphics2D g = (Graphics2D) strategy.getDrawGraphics();
g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
return g;
}
return null;
}
public void updateDisplay() {
Window window = device.getFullScreenWindow();
if (window != null) {
BufferStrategy strategy = window.getBufferStrategy();
if (!strategy.contentsLost()) {
strategy.show();
}
}
Toolkit.getDefaultToolkit().sync();
}
// other methods go here
}
Using AffineTransforms would, while welcome advice, not truly help solve this issue, as I need to be able to display at the native resolution of any monitor and already extensively use AffineTransforms on the Graphics object.
EDIT: I have tried System.setProperty("sun.java2d.dpiaware", "false"); as the first line in main with no success. Is the property wrong?
EDIT 2: Addition of more clarity:
My render method looks like this:
private void render(Graphics2D g) {
// Black out the screen to prevent old stuff from showing
g.setColor(Color.BLACK);
g.fillRect(0, 0, ScreenManager.getScreenWidth(), ScreenManager.getScreenHeight());
// Set the transform for zoom to draw the zoomed stuffs
AffineTransform saveState = g.getTransform();
AffineTransform cameraTransform = ScreenManager.getInstance().getCamera().getCurrentTransform();
g.transform(cameraTransform);
// RENDER UPDATEABLE
this.game.getController().renderGame(g);
// REDNER STATIC GUI
g.setTransform(saveState);
// draw mouse cords
Point mouse = this.mouseHandler.getFrameMousePoint();
if (mouse != null) {
Font f = new Font("Consolas", 0, 40);
Point2D scaledPos;
try {
scaledPos = cameraTransform.inverseTransform(mouse, null);
} catch (NoninvertibleTransformException e) {
scaledPos = mouse;
e.printStackTrace();
}
String s1 = mouse.toString();
String s2 = scaledPos.toString();
Rectangle2D r = f.getMaxCharBounds(g.getFontRenderContext());
int yOff = (int) r.getHeight();
Color c = new Color(100, 100, 100, 191);
g.setColor(c);
g.fillRect(mouse.x, mouse.y, (int) (r.getWidth() * (s1.length() > s2.length() ? s1.length() : s2.length())), yOff + yOff + yOff);
g.setColor(Color.WHITE);
g.setFont(f);
g.drawString(s1, mouse.x, mouse.y + yOff);
g.drawString(s2, mouse.x, mouse.y + yOff + yOff);
}
}
And this method is called here:
Graphics2D g = screenManager.getRenderGraphics();
render(g);
g.dispose();
screenManager.updateDisplay(); // SYNCS SCREEN WITH VSync
I have printed out the AffineTransform that is on the graphics object when it is first created, and that prints like this AffineTransform[[2.0, 0.0, 0.0], [0.0, 2.0, 0.0]] which does lead me to conclude that the scaling is done in code. However, the issue is, the things that are rendered with my custom transform ScreenManager.getInstance().getCamera().getCurrentTransform(); are also scaled up by 2, even though I do not contact my transform and set it to mine. (Actually never mind, I realized that I do g.transform on my transform not g.setTransform. I am still including this in the write-up though).
A workaround solution to my rendering problem is to do g.setTransform(AffineTransform.getScaleInstance(1, 1); However, this is more than I want to do and it (after trying it on my code) does not fix the issue with the awt coordinate space. Meaning, The rendering works as desired, but the mouse position does not. When the mouse is in the bottom right corner of my screen, it will give a position that is half of the native resolution of my monitor. This solution does not work for me. Processing time is valuable and the more calculations that must be done to UNDO this feature addition. Here is a link discussing how this would be implemented. I link this to point out the section where it mentions that the developer could do it, but it would take a lot of work on the developers part.
I would still like to know if there is a way to either:
Disable the feature with a command-line VM argument
Disable the feature with a snippet of code
After coming back to this question after a while of working on something else, I have come across the solution I was looking for, mostly by accident.
The solution I was looking for was a Java system property or JVM argument that would disable the DPI awareness of Swing components, meaning that on a system with 200% scaling, the user input space and component rendering would match the native resolution of the screen and not the 200% scaled resolution (eg expecting to read mouse input from and render to a 3840x2160 screen rather than what was happening, where mouse input was capped at 1920x1080).
This solution was discussed in this answer to a similar question. I will restate it here for sake of being complete.
The solution is to pass -Dsun.java2d.uiScale=1 into the VM as a VM argument. This forces the UI scale to be 1, ignoring any system scaling and rendering and gathering mouse input at native resolution. I can also confirm that calling System.setProperty("sun.java2d.uiScale", "1"); before calling any swing class will also produce the result I was looking for.
What is the proper way to extend the background in top down game? I used LibGdx framework. Any idea or tutorial for top down game.My background is in PNG format and screen of 720x1280 portrait.I had a problem in extending the background.I want the camera follow the character and the background will extend. How could I do that? Here is the Screen shot of
https://i.stack.imgur.com/jl03R.png
Here is my code
To display background I used this
//background
Background = new Texture(Gdx.files.internal("floor.png")); //File from assets folder
Background.setWrap(Texture.TextureWrap.Repeat, Texture.TextureWrap.Repeat);
bgsprite = new Sprite(Background);
In render
spriteBatch.draw(Background,0,100,0, srcy, Gdx.graphics.getWidth(),Gdx.graphics.getHeight());
srcy +=3;
The background is scrolling but the camera don't follow the player(cat)
Source code for GameScreen
http://pastebin.com/Dxfx9f65
Thank's and Advance any help or suggestion are much appreciated. :)
Use two identical texture background. Each the size of the screen It can be the same file. It is important that are docked vertically. Move of at the same time. Alternately changing with each other.
Sample code:
declaration:
Texture background1, background2;
SpriteBatch batch;
float yMax, yCoordBg1, yCoordBg2;
final int BACKGROUND_MOVE_SPEED = 100; // pixels per second. Put your value here.
creation:
Background1 = new Texture(Gdx.files.internal("floor.png"));
Background2 = new Texture(Gdx.files.internal("floor.png")); // identical
yMax = 1280;
yCoordBg1 = yMax*(-1); yCoordBg2 = 0;
in method render:
yCoordBg1 += BACKGROUND_MOVE_SPEED * Gdx.graphics.getDeltaTime();
yCoordBg2 = yCoordbg1 + yMax; // We move the background, not the camera
if (yCoordBg1 >= 0) {
yCoordBg1 = yMax*(-1); yCoordBg2 = 0;
}
batch.begin();
batch.draw(background1, 0, yCoordBg1);
batch.draw(background2, 0, yCoordBg2);
batch.end();
The background can be made in the format jpg - will spend less memory.
I am trying to add text for debugging purposes in my program. I call the players debugDraw method like so in the main class:
public void create () {
//Initialize essentials
cam = new OrthographicCamera(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
cam.setToOrtho(false);
rend = new ShapeRenderer();
rend.setAutoShapeType(true);
batch = new SpriteBatch();
// Initialize Entities
player = new Player(new Vector2(100, 100), new Vector2(100,100));
enemy = new Enemy(new Vector2(100, 100), new Vector2(100,10));
}
#Override
public void render () {
//Update player
player.update();
//Update camera then set matrix of batch
cam.update();
batch.setTransformMatrix(cam.combined);
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
// ShapeRenderer begin
rend.begin();
player.render(rend);
enemy.render(rend);
rend.end();
// ShapeRenderer end
// SpriteBatch begin
batch.begin();
player.renderDebugText(batch);
batch.end();
// SpriteBatch end
}
Here is the entity class which is the parent class to player:
public Entity(Vector2 coords, Vector2 dims){
//Assign constructors
position = coords;
dim = dims;
//For debugging purposes of all entities
debugText = new BitmapFont();
debugText.setColor(Color.WHITE);
}
public void renderDebugText(SpriteBatch batch){
debugText.draw(batch, "Vel.x: " + vel.x, 100, 100);
}
However when I run the program, I just get my normal screen with no text at all. I can't seem to figure out why this isn't working. Any help is extremely appreciated.
Nothing immediately looks wrong with the code you posted, so here's a few ideas;
The default BitmapFont is 15pt, if this is drawn at 15px height then it could be very small if you force your game to a high resolution, like Full-HD. My current project is Full-HD and the font I use looks just about right at 45px, so you could try scaling yours by a factor of 3 or 4. E.g. use this after initialising your font;
bitmapFont.getData().setScale(3);
Your Camera should also have the virtual/viewport dimensions, so if you are forcing a particular resolution then you should pass in your virtual dimensions instead.
As #Tenfour04 has suggested, you should try to avoid multiple instances of the same font, so instead of initialising your font in the Entity class, initialise it in your main game and pass it through the Entity constructor. I can't see how this would fix your issue though as this would be purely for performance.
I made a very simple mistake, but from how much code I posted, it is easily missed. On the line where I put
batch.setTransformMatrix(cam.combined);
it should be replaced with
batch.setProjectionMatrix(cam.combined);
Then all errors go away, sorry, I don't know why it took me so long to figure out. Thanks for all the help!
I'm migrating my native Android game to libGDX. That's why I use flipped graphics. Apparently NinePatches can't be flipped. (They are invisible or look strange.)
What would be more efficient:
use one big TextureAtlas containing all graphic files and load it twice (flipped and unflipped) or
use one big TextureAtlas for the flipped graphic files and a second small one for the NinePatch graphics?
Type A:
public static TextureAtlas atlas, atlas2;
public static void load() {
// big atlas (1024 x 1024)
atlas = new TextureAtlas(Gdx.files.internal("game.atlas"), true);
// find many AtlasRegions here
// Same TextureAtlas. Loaded into memory twice?
atlas2 = new TextureAtlas(Gdx.files.internal("game.atlas"), false);
button = ninepatch.createPatch("button");
dialog = ninepatch.createPatch("dialog");
}
Type B:
public static TextureAtlas atlas, ninepatch;
public static void load() {
// big atlas (1024 x 1024)
atlas = new TextureAtlas(Gdx.files.internal("game.atlas"), true);
// find many AtlasRegions here
// small atlas (128 x 64)
ninepatch = new TextureAtlas(Gdx.files.internal("ninepatch.atlas"), false);
button = ninepatch.createPatch("button");
dialog = ninepatch.createPatch("dialog");
}
now I do not have time to test, I expound the idea, but I think it can work, is based on a texture, not texture atlas for simplicity.
short metadata = 2;
Texture yourTextureMetadata = new Texture(Gdx.files.internal(metaDataTexture));
int width = yourTextureMetadata.getWidth() - metadata;
int height = yourTextureMetadata.getHeight() - metadata;
TextureRegion yourTextureClean = new TextureRegion(yourTextureMetadata,
1, 1, width, height);
I assume that metadata has a size of two, now I do not remember, sorry
the idea would take, the largest texture, with metadata and then cut them to have clean on the other side so that you can turn around, I hope to work.
for texturealtas would similar, findRegions and cut metadata and save them without metadata
On the other hand, note that you have static textures, and I think when android change of context, your application to another application, and then back to yours application, you can give errors visualization, your images can black display
I'm working on the android half of a cross-platform android/ios framework that lets you write apps in JS that work on both platforms. I say this because it means I can't use things like 9-patches to get this effect. Full code at https://github.com/mschulkind/cordova-true-native-android
Here are two screenshots of the problem:
-Images redacted because I'm too new to be this useful. I will have to add them when I'm no longer a newbie.-
Here's the code that generates the drawable from https://github.com/mschulkind/cordova-true-native-android/blob/master/src/org/apache/cordova/plugins/truenative/ViewPlugin.java#L146
// Borrowed from:
// http://www.betaful.com/2012/01/programmatic-shapes-in-android/
private class ViewBackground extends ShapeDrawable {
private final Paint mFillPaint, mStrokePaint;
private final int mBorderWidth;
public ViewBackground(
Shape s, int backgroundColor, int borderColor, int borderWidth) {
super(s);
mFillPaint = new Paint(this.getPaint());
mFillPaint.setColor(backgroundColor);
mStrokePaint = new Paint(mFillPaint);
mStrokePaint.setStyle(Paint.Style.STROKE);
mStrokePaint.setStrokeWidth(borderWidth);
mStrokePaint.setColor(borderColor);
mBorderWidth = borderWidth;
}
#Override
protected void onDraw(Shape shape, Canvas canvas, Paint paint) {
shape.resize(canvas.getClipBounds().right, canvas.getClipBounds().bottom);
Matrix matrix = new Matrix();
matrix.setRectToRect(
new RectF(
0, 0,
canvas.getClipBounds().right, canvas.getClipBounds().bottom),
new RectF(
mBorderWidth/2, mBorderWidth/2,
canvas.getClipBounds().right - mBorderWidth/2,
canvas.getClipBounds().bottom - mBorderWidth/2),
Matrix.ScaleToFit.FILL);
canvas.concat(matrix);
shape.draw(canvas, mFillPaint);
if (mBorderWidth > 0) {
shape.draw(canvas, mStrokePaint);
}
}
}
This has happened both when the drawable was set as the background of the EditText directly and when I set it as the background of a parent view around the EditText.
Anyone have an idea of what's going on here or what avenues I should explore?
Looks like you want to draw a rounded rectangle.
To achieve such a style, it is simpler to use a XML drawable.
You simply put a XML file into the drawable/ directory. Here you can describe the desired shape.
Some documentation about XML drawables is here : http://idunnolol.com/android/drawables.html
Look at the tag.