Libgdx background image not fitting - java

I am developing a game which has 480x800 VIRTUAL screen sizes. Also I render my map using TiledMapRenderer. My problem is fitting background and HUD elements into the screen which has different ratio than 480/800 (Mostly taller devices). Some devices show blank area at the bottom of screen.
//my viewport (WIDTH = 480, HEIGHT = 800)
viewport = new ScalingViewport(Scaling.fillX,MyGdxGame.WIDTH,MyGdxGame.HEIGHT,camera);
#Override
public void resize(int width, int height) {
viewport.update(width, height, true);
camera.position.set(camera.viewportWidth / 2, camera.viewportHeight / 2, 0);
barriers.getRenderer().setProjectionMatrix(viewport.getCamera().combined);
shapeRenderer.setProjectionMatrix(viewport.getCamera().combined);
}
My screen should fit the X, but background image should fit X and Y without changing the aspect ratio. In this case ScalingViewport does not solve my problem, and if I change the viewport, I have to code everything from beginning.
#Override
public void render(float delta) {
update(delta);
SpriteBatch sb = game.batch;
Gdx.gl.glClearColor(46f/255,46f/255,46f/255,1f);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
sb.setProjectionMatrix(camera.combined);
sb.begin();
//this has to change in somehow
sb.draw(AssetManager.backgroundMenu,0,0,MyGdxGame.WIDTH,MyGdxGame.HEIGHT);
sb.end();
}
Should I use multiple viewport? Or is there any way to fit my background into the screen? By the way I do not want to change my camera if there is a way.

Yes, you should use second viewport for your HUD elements.
I would recommend using ExtendViewport
ExtendViewport viewport = new ExtendViewport(MyGdxGame.WIDTH,MyGdxGame.HEIGHT);
It fills all screen (without black bars) and keeps aspect ratio for all resolutions.

Related

libGDX camera zoom is different on different devices:

I'm making a game on both desktop and android and the same code results in two different screens (cam.zoom is the same in both):
The desired result is the left screen and the code used to render is like so: (the image is 8000x4000 and is a place holder for my map)
public class MainMenuScreen implements Screen {
private final Application application;
private SpriteBatch batch;
private ShapeRenderer sr;
private OrthographicCamera cam;
private Viewport viewport;
private Button startGame;
private Texture background = new Texture(Gdx.files.internal("background.jpg"));
public MainMenuScreen(final Application application) {
this.application = application;
cam = new OrthographicCamera(WIDTH, HEIGHT);
viewport = new FitViewport(WIDTH, HEIGHT, cam);
batch = this.application.batch;
sr = this.application.sr;
startGame = new Button(-50, -25, 100, 50);
startGame.setColour(new Color(0.01f, 0.35f, 0.47f, 1));
startGame.setText("Start game", this.application.font);
startGame.setHasBorder(true);
startGame.setBorderThickness(3);
startGame.setBorderColour(new Color(0.02f, 0.62f, 0.79f, 1));
startGame.setTextColour(new Color(0.02f, 0.62f, 0.79f, 1));
}
public void update() {
Vector2 mousePos = Extras.getMousePos(viewport);
if (startGame.isClickedOn(mousePos)) {
}
}
#Override
public void render(float delta) {
ScreenUtils.clear(0, 0, 0, 1);
batch.setProjectionMatrix(cam.combined);
sr.setProjectionMatrix(cam.combined);
update();
batch.begin();
batch.draw(background, -background.getWidth() / 2, -background.getHeight() / 2);
batch.end();
startGame.render(this.sr, this.batch);
}
How do I make sure all different devices have the same zoom in the camera?
A possible solution I don't know how to implement yet could be setting cam.zoom to a value dependent on the screen size somehow but there has to be a better way for this using libGDX itself.
First, are you trying to make the button size's same on all device's screen resolution? or you want to make camera zooming have same value?
Ok, How the variable WIDTH and HEIGHT was declared?if you have declared both with one spesific size. Its will be not same if you're trying in another resolutions.
EXAMPLE:
//Constant Spesific Value of WIDTH and HEIGHT Size.
public static final int WIDTH = 1280, HEIGHT = 720;
///////////////////////////////////////////////////
//Non-Constant Value of WIDTH and HEIGHT Size.
public static int WIDTH, HEIGHT;
...
//Define Both In Main.class
public MainGameScreen(){
WIDTH = Gdx.graphics.getWidth();
HEIGHT = Gdx.graphics.getHeight();
}
However, LibGDX's screen resolution can be calculated. Some object size in your game must be spesific, when calculating the size between both WIDTH and HEIGHT you need to know, how the size will be same in all device with one spesific calculation.
EXAMPLE:
/* Button (256x72) in Screen Resolution (1280x720)
Button (160x48) in Screen Resolution (800x480) */
startGame = new Button(0,0, WIDTH/5, HEIGHT/10);
//Button (400x100) in All Screen (Constant Value)
startGame = new Button(0,0, 400, 100);
So, i suggest you to make a calculation to sizing some objects in your game. Because its will be different if you trying to make value in constant.
Ok, the next is, OrthographicCamera Which you want to make same value of zoom right? the cam.zoom is a floating value. Its not a constant value, but it was a variable value that can be changed in all time.
You can trying this code, if you want to zoom camera directly on game
if(Gdx.input.isTouched()){
//Zoom Out
cam.zoom += Gdx.graphics.getDeltaTime();
//Zoom In
cam.zoom -= Gdx.graphics.getDeltaTime();
}
Or if you talking about static-zoom, in a spesific value (not directly changed)
cam.zoom = 1f; //for 1 value of Zoom Out
I hope you understand what i means and im sorry if my answers can't be helpful for you, cause im still learning too, all about LibGDX.
#Alf Equilfe was the one who helped me get to it with his answer and here is the actual solution:
Set WIDTH, HEIGHT to a constant value independent of device size (make it so that any device can handle the size, in my case i chose 1024, 512) and make the aspect ratio the scale so it looks same on all devices.

LibGDX How do I update Actor positions after resizing window?

I'm trying to stick toolbar buttons to the top-right of my screen, but whenever I resize the window, the buttons stay in the same absolute position (relative to the bottom-left).
Before resize:
After resize:
This is the method that generates the UI button (Which is currently only called in the Screen's constructor):
private void generateUiToolbar(){
// Toolbar Table
Table table = new Table();
table.setFillParent(true);
table.top();
table.right();
// Menu button
table.row();
Texture myTexture = new Texture(Gdx.files.internal("ui/stamp.png"));
TextureRegion myTextureRegion = new TextureRegion(myTexture);
TextureRegionDrawable myTexRegionDrawable = new TextureRegionDrawable(myTextureRegion);
ImageButton menuButton = new ImageButton(myTexRegionDrawable);
menuButton.addListener( new ClickListener() {
#Override
public void clicked(InputEvent event, float x, float y) {
stage.clear();
generateUiMenu();
}
});
table.add(menuButton).size(60,60).padTop(10).padRight(10);
stage.addActor(table);
}
This is the resize() method:
public void resize(int width, int height) {
stage.getViewport().update(width, height, true);
stage.getCamera().viewportWidth = width;
stage.getCamera().viewportHeight = height;
stage.getCamera().position.set(stage.getCamera().viewportWidth / 2, stage.getCamera().viewportHeight / 2, 0);
stage.getCamera().update();
}
The variable stage is initiated in the constructor with stage = new Stage();
For some reason stage.getViewport().update(width, height, true); doesn't do anything. When I print stage.getWidth() after resizing, it will return the same number. What's a good way to update the location of the button or Actors in general? Simply clearing the stage and generating the UI again won't work for me, because sometimes when you resize, there are different actors currently displayed. If I missed any information, please let me know.
EDIT 1:
Added table.setFillParent(true); as mentioned in an answer, but that didn't fix it either.
EDIT 2:
After reading the answers and comments, I deleted the stage.getCamera() manipulation, but I'm still not getting the correct result. This is what happens when I resize with just the line of code stage.getViewport().update(width, height, true);:
I think you misunderstand the usage of Viewport.
In your resize method you do:
stage.getViewport().update(width, height, true);
stage.getCamera().viewportWidth = width;
stage.getCamera().viewportHeight = height;
stage.getCamera().position.set(stage.getCamera().viewportWidth / 2, stage.getCamera().viewportHeight / 2, 0);
stage.getCamera().update();
But stage.getViewport().update(width, height, true); already does what you do in the next four lines.
viewport.update(width, height) set the new width and height to the camera and updates the camera. So:
viewport.update(width, height)
is equal to
camera.viewportWidth = width;
camera.viewportHeight = height;
camera.update();
The only difference is that the viewport looks to the aspect ratio depending on which Viewport you use.
And the third parameter: stage.getViewport().update(width, height, true); is a boolean value which says should the camera be centered. So if the third parameter is true the viewport will do:
camera.position.set(camera.viewportWidth / 2, camera.viewportHeight / 2, 0);
In your resize method you override the work of the viewport because with viewport.update(width, height, true) you already have done all of the resize and you don't need the four other lines.
In the resize method this is enough:
public void resize(int width, int height) {
stage.getViewport().update(width, height, true);
}
You can read this for a better understanding of Viewport: How Camera works in Libgdx and together with Viewport
The Viewport object is a camera frustum manager. When you start modifying the camera's parameters (other than position), you are undoing what you did by calling viewport.update().
If you want the table to automatically fill the screen so stuff in the top right corner stays there after a resize, don't set a width and height on the table. Instead, call table.setFillParent(true) so it will automatically update its size to match the viewport size.

How Camera works in Libgdx and together with Viewport

If you work with LibGdx it goes not long until you come to Camera and viewport. If you work the first time with camera and Viewport you get some questions about how it works and how to use it. So:
How can I use a Camera in LibGdx? What's viewport width and height?
What is a Viewport, how can I use it and how it works together with the Camera?
How can I use a Camera in LibGdx? What's viewport width and height?
Firstly it's important that you know the Camera works with World units not with Pixels. World units are not a regular Unit. You self can define how much one World Unit is. Later more.
First, we create an OrthographicCamera a SpriteBatch and a Texture:
private OrthographicCamera camera;
private SpriteBatch batch;
private Texture img;
#Override
public void create () {
//We create a OrthographicCamera through which we see 50x50 World Units
camera = new OrthographicCamera(50,50);
batch = new SpriteBatch();
img = new Texture("badlogic.jpg");
}
We create a OrthographicCamera and in the Constructor we define how many World Units we see if we look through this camera into our world. In our example 50 x 50 World Units these are the viewport width and height.
So we have created a Camera with a viewport width and height of 50.
In the render() method we render our image:
#Override
public void render () {
//Clear the screen (1)
Gdx.gl.glClearColor(1, 1, 1, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
//Set ProjectionMatrix of SpriteBatch (2)
batch.setProjectionMatrix(camera.combined);
batch.begin();
//Draw image on position 0, 0 with width 25 and height 25 (3)
batch.draw(img, 0, 0, 25, 25);
batch.end();
}
(1) Clear the Screen, if we don't do that every Texture will draw over the other and if we draw a Animation we will see the old Frames.
(2) The batch is our Drawer he draws our Images, Animations etc. Default he draws a World which has so many World Units like the Screen has Pixels so in this case 1 World Unit = 1 Pixel. But now we will see 50 x 50 World Units doesn't matter how big the screen is. To say the Batch that he should draw what we see through our camera we must call: batch.setProjectionMatrix(camera.combined);
(3) Now we draw our img on Position 0,0 But 0, 0 doesn't mean on Pixel position 0,0 it means the Image will be drawn on World position 0,0 also width and height are not in Pixels they are in World units so the img will be drawn on Position 0,0 25x25 World Units big. So on a 50x50 viewport, the image fills one-quarter of the whole screen.
The Image fill one-quarter of the whole screen exactly as expected. But why it is on the right top and not on the bottom left?
The Problem is that the center of the Camera point on the position 0,0
So our Image is drawn on position 0,0 he fills the top right corner.
We must set the position of the camera so 0,0 is in the bottom left corner:
camera = new OrthographicCamera(50,50);
camera.position.set(camera.viewportWidth / 2, camera.viewportHeight / 2, 0);
In the render() method we must add camera.update() because every time we change the position or the scale or what else of the camera we must update the camera.
Now the Image is in the bottom left.
Where are the Pixels?
We always speak about World units but where are the Pixels? The pixels are still there. If we have a Screen size of 200 x 200 pixels the batch will always draw 200 x 200 pixels. With the method batch.setProjectionMatrix(camera.combined); we only say the batch how much World Units are one Pixel.
If we have a Screen with 200 x 200 pixels and we create a Camera with a viewport of 50 x 50 world units the SpriteBatch know 1 WorldUnit = 4 Pixels.
Now we draw a Image which is 25 x 25 World Units big the SpriteBatch knows he must draw the image 25 * 4 = 100 pixel big.
So the pixels still there but it's easier to think in World Units.
If it's not clear enough here is a little bit more detailed description: Libgdx's World Units
Box2d
It's also very important to think in World Units if you use Box2d because Box2d works with Meters. So if you create a Body with a Force off 5 on the x axis, the Body is 5 m/s fast.
And now it's very cool to work with World Units because you can say 1 World Unit = 1 Meter so you can create a object with a width of 10 and you know after one second the Body will be in the Center of the Object. If you work with Pixels you will have a Problem if you have a different Screensize.
What is a Viewport, how can I use it and how it works together with the Camera?
Now we have the big Problem about different Screen sizes.
Suddenly we have a Screen size of 350 x 200 pixels, now the Image will be stretched and don't look so nice as before.
For this Problem we use Viewports a few Viewports are StretchViewport, FitViewport and ExtendViewport. All viewports you can find here: https://github.com/libgdx/libgdx/wiki/Viewports.
Firstly what is a Viewport.
Imagine the camera is a speaker who speaks English. Different Screen Sizes are other People who speak German, French, Chinese etc. and the Viewport is the translator. The Translator doesn't change the sense of that what the English Speaker says but he adapts it so the others can understand it. Same are camera and Viewport. Viewport doesn't say or change what you can see on your screen if you run the program. He only handles that you always see the same on different Screen sizes. A Camera can life without Viewport. A Viewport not without Camera.
Add a viewport Object:
private Viewport viewport;
and the resize() method:
#Override
public void resize (int width, int height) {
viewport.update(width, height);
}
StretchViewport
Create a StretchViewport:
camera = new OrthographicCamera(50, 50);
camera.position.set(camera.viewportWidth / 2, camera.viewportHeight / 2, 0);
viewport = new StretchViewport(camera.viewportWidth, camera.viewportHeight, camera);
In the StretchViewport Constructor, we define the viewport width and height and the Camera.
Now we get the same result as before if we have different Screensizes the Images will be stretched.
FitViewport
Maybe we won't stretch our Images we will matter about the ratio of x and y.
The ratio of x and y means: is an Object 2 width and 1 height he will always twice as wide as high for example 200x100, 30x15 but not 20x15.
Create a FitViewport:
camera = new OrthographicCamera(50, 50);
camera.position.set(camera.viewportWidth / 2, camera.viewportHeight / 2, 0);
viewport = new FitViewport(camera.viewportWidth, camera.viewportHeight, camera);
Now the Image will always be a square. To see the Bars on the Side lets draw the Image as big as our viewport:
batch.draw(img, 0, 0, 50, 50);
The Image has a Ratio of 1 because of 50(width)/50(height) = 1 so the Image will always have the same width and height. The Bars on the side are outside of our Viewport and will be drawn in the color you define here: Gdx.gl.glClearColor(1, 1, 1, 1);
ExtendViewport
Maybe we won't Bars on the Side then we can take a ExtendViewport. The ExtendViewport keeps the world aspect ratio without bars by extending the world in one direction. Means on a screen where the aspect ratio between width and height are bigger you will see more of the world.
On a screen 400x200 aspect ration = (400/200 = 2) you will see more than on a screen of 300x200 (300/200 = 1.5);
To show this create a ExtendViewport and draw the Image bigger than the viewport and a second small Image:
camera = new OrthographicCamera(50, 50);
camera.position.set(camera.viewportWidth / 2, camera.viewportHeight / 2, 0);
viewport = new ExtendViewport(camera.viewportWidth, camera.viewportHeight, camera);
// in render() method
batch.begin();
batch.draw(img, 0, 0, 100, 50);
batch.draw(img, -20, 0, 20, 20);
batch.end();
If we now start our Program with a Screen size of 200x200 we see:
And if we resize the Screen on x axis To make the screen wider:
Now we can see more off the first Image and additinal the Second image but the ratio will always be the same. The Image is only stretched because we draw it 100x50 not because of resizing.
I hope this will clear some Questions about Camera and Viewport if you will learn more, read and look some tutorials and read the LibGdx wiki: https://github.com/libgdx/libgdx/wiki

libgdx ios landscape not fullscreen

I have trouble with my app. On iPhone (tested on 5c, 5s, 6) i have two black stripes on both sides (on android all looks well).
How i can dispose of them?
This is my code for drawing
#Override
public void create () {
mWidth = Gdx.graphics.getWidth();
mHeight = Gdx.graphics.getHeight();
mScale = Math.max(mWidth, mHeight) / 20f;
backgroundTexture = new Texture(Gdx.files.internal("backBlue.png"));
ShaderProgram.pedantic = false;
backgroundShader = new ShaderProgram(VERT, FRAG);
if (!backgroundShader.isCompiled()) {
System.err.println(backgroundShader.getLog());
System.exit(0);
}
if (backgroundShader.getLog().length()!=0)
System.out.println(backgroundShader.getLog());
backgroundBatch = new SpriteBatch(5, backgroundShader);
}
#Override
public void render () {
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
backgroundBatch.begin();
backgroundBatch.draw(backgroundTexture, 0, 0, mWidth, mHeight);
backgroundBatch.end();
...
}
#Override
public void resize (int width, int height) {
mWidth = width;
mHeight = height;
mScale = Math.max(width, height) / 20f;
backgroundShader.begin();
backgroundShader.setUniformf("resolution", width, height);
backgroundShader.end();
}
This is probably happening because the viewport you are using, which is usually set in the constructor or the create method.
What is a viewport?
Basically, a viewport is an object that is created to define the policy of how the game will be drawn on different screens. E.g., say your camera is set to be 480 x 800 (pixels). What happens if your game is running on a screen that has a different ratio, for instance, the iPhone 5 that has a screen of 1,136 × 640 pixels? Should the game be stretched? Should the image be cropped? Or should libgdx add black bars on either side to fit the camera size you are using? This decision is made by the viewport your camera is using.
This is it in a nutshell. It is highly recommended to read more on this on the wiki.
Additionally, a good tutorial on this subject can be found here.

LibGDX Circle rendering

Hi I'm just starting to learn about LibGDX and I was wondering how to draw an actual circle.
I'm using a orthographic camera object and shape renderer but whenever I draw a circle it's more of an ellipse
#Override //Circle paint function
public void paint(OrthographicCamera camera) {
renderer.setProjectionMatrix(camera.combined);
renderer.begin(ShapeType.Filled);
renderer.setColor(Color.CYAN);
renderer.scale(1f, 1f, 1f);
renderer.circle(getX(), getY(), getSize());
renderer.end();
}
//How I initialize the camera
camera = new OrthographicCamera(500, 500);
How it ends up looking:
I mean I don't know about you, but I don't think that'
Your orthographic camera ratio should be the same as the viewport ratio, otherwise perspective gets skewed as you've observed. If your viewport is 1.3 ratio (it looks like it is), the ratio of your camera should be the same.
Try: camera = new OrthographicCamera(650, 500);

Categories