libgdx using percentage for images - java

I'm making a game sort of like flappy bird, but it works on landscape mode, to make it fair so that people with bigger screens don't have an advantage I change my images to screen % for example the bird will be 10% of screen height, so it will be the same in all screens, the question is, is this a good idea or is there any other way?

You don't need to use percentages. If you are using libgdx, you can (and should) use a predefined viewport size, so the screen resolution is handled by the library and not you.
You can achieve this using a camera, setting a fixed height, and calculating the width:
HEIGHT = 10;
WIDTH = (Gdx.graphics.getWidth()/Gdx.graphics.getHeight())*HEIGHT;
camera = new OrthographicCamera();
camera.setToOrtho(false, WIDTH, HEIGHT);
this way, your height will be 10 units. And the width will be caculated by the screen x-y ratio.
the bird will be 10% of screen height
Then your bird will be 1 unit size (height/10).
If you want both sides to be fixed (so noone sees more in the width). Its even easier, but your images won't keep their ratio, they will be stretched in both axis.
HEIGHT = 10;
WIDTH = 15;
camera = new OrthographicCamera();
camera.setToOrtho(false, WIDTH, HEIGHT);

Related

Libgdx - Tiledmap rendered tiles disappearing from screen

I'm creating a side-scrolling platformer and I'm using my own Tiled map. I'm rendering it using the OrthogonalTiledMapRenderer, but after adding background images I noticed that they disappear from the screen too soon. On the first picture you can see the background giant trees still being rendered, and in the TiledMap the first background tile horizontally ends exactly where the ladder starts, and then the same picture is added (so it's basically one image pasted multiple times on the level - second picture).
However, even before reaching the first image's ending point, it disappears, which looks like this:
Anybody can help with that? Here is the code for the rendering:
OrthogonalTiledMapRenderer mapRenderer = new OrthogonalTiledMapRenderer(map, 1 / Constants.PPM);
OrthographicCamera camera = new OrthographicCamera();
float width = Constants.VIEWPORT_WIDTH * camera.zoom * 2;
float height = Constants.VIEWPORT_HEIGHT * camera.zoom * 2;
mapRenderer.setView(camera.combined, cameraX, cameraY, width, height);
Gdx.gl.glClearColor(0x64 / 255.0f, 0x95 / 255.0f, 0xed / 255.0f, 0xff / 255.0f);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
mapRenderer.render();
The floats are updated with camera position.
cameraX = camera.position.x - camera.viewportWidth * camera.zoom;
cameraY = camera.position.y - camera.viewportHeight * camera.zoom;
Camera follows the player and is clamped to the borders of the map. Nothing too fancy, I also tried mapRenderer.setView(camera) with the same results.
It looks like this is caused by optimistic culling of tiles on the renderer side, which breaks when tiles are overly large.
One way to fix this would be to not use a single large tile for these backgrounds, but rather to add the background as a tileset using the same tile size as your map. You can still easily place the whole image at once by using click+drag to select all the tiles in this tileset.
Another option may be to place this image as a tile object on an Object Layer instead, but I don't know if libgdx will render those for you by default.
Creating separate tilesets for every background image and splitting them in 32x32 tiles fixed the issue.
You could temporarily boost the zoom of your camera so you always render an area larger than you see.
float zoom = camera.zoom;
camera.zoom += 1f;
//render map
camera.zoom = zoom;

Android - Can't draw same size square on all devices

I have an application running on android on which I have to draw a grid. I would like the cells of the grid to be of the same size on all devices, and I've found this method to do that:
float scale = getResources().getDisplayMetrics().density;
float SIZE = DESIRED_DP_VALUE * scale + 0.5f;
DESIRED_DP_VALUE is a value I set for the cells dimension.
I've tried the app on two smartphones and a tablet: the tablet and one of the smartphones have the cells of the same size, while the other smartphone doesn't.
This is the method I use to draw the grid:
protected void onDraw(Canvas canvas) {
canvas.drawColor(Color.BLACK);
int count=0;
while(count<=row){
float coordinate=count*SIZE;
canvas.drawLine(coordinate,0,coordinate,column*SIZE,whitePaint);
count++;
}
count=0;
while(count<=column){
float coordinate=count*SIZE;
canvas.drawLine(0,coordinate,row*SIZE,coordinate,whitePaint);
count++;
}
}
The grid is draw correctly on each device.
Where could the problem be?
I think you are mixing some concepts.
The size in pixels is that, how many dots are counting per with or height.
Every device has its own screen size measured in inches and the amount of pixels or dots able to draw in width and height.
The relationship between dimension and pixels is the density.
So, what do you want to do?
Draw an square which shows the same physical size on the screen or a square with the same amount of pixels?
If you want to draw based on inches, take it that way.
For drawing an one inch square, for a device with a density of 300 pixels per inch you need 300 pixels.
If the device is 150 pixels per inch, you must draw a 150 pixels square.
So, you need to keep fixed the size in inches, not the desired DP.

LibGdx - Scaling Sprites, Camera and Viewports

Hell All & thanks for reading,
I recently started working on an 2D Android/Desktop project and have become stuck trying to display my sprites in the way i want.
I have a background Sprite that is 144(w) by 160(h) that I want to be able to position other sprites onto the screen relative to points on the background sprite.
I think I understand that if I create a camera/viewport that is 144 x 160 I would be able to position my sprites on the background sprite using the co-ordinates based on the 144 x 160 of the background sprite. This will work across the different screen resolutions found on mobile devices but will stretch the background sprite despite experimenting with the different viewport types (FillViewport, FitViewport etc..).
What I want to achieve is to have my background sprite to maintain it ratio across different screen resolutions and to be able to place other sprites over the background sprite. The placing of sprite need to work across different resolutions.
Apologies if my explanation is confusing or makes no sense. I would add some image to help explain but I reputation to add any to the post. However I think the TLTR question is "What is the correct way to display sprites on multiple screen resolutions while keeping a correct ratios and scaling to the screen size and position of sprite in a way that works across multiple resolutions?"
Thank, All Questions Welcome
A FitViewport would do what you described (maintain aspect ratio), but you will have black bars on some devices. Based on the code you posted on the libgdx forum, I see that you forgot to update the viewport in the resize method, so it is not behaving as designed.
However, for a static camera game like what you described, I think the best solution would be to plan your game around a certain area that is always visible on any device, for example, the box from (0,0) to (144,160). Then use an ExtendViewport with width and height of 144 and 160. After you update the viewport in resize, you can move the camera to be centered on the rectangle like this:
private static final float GAME_WIDTH = 144;
private static final float GAME_HEIGHT = 160;
public void create(){
//...
viewport = new ExtendViewport(GAME_WIDTH, GAME_HEIGHT);
//...
}
public void resize(int width, int height){
viewport.update(width, height, false); //centering by putting true here would put (0,0) at bottom left of screen, but then the game rectangle would be off center
//manually center the center of your game box
Camera camera = viewport.getCamera();
camera.position.x = GAME_WIDTH /2;
camera.position.y = GAME_HEIGHT/2;
camera.update();
}
Now your 144x160 box is centered on the screen as it would be with FitViewport, but you are not locked into having black bars, because you can draw extra background outside the 144x160 area using whatever method you like.
In your case 144:160 is a wider portrait aspect ratio than any screen out there, so you wouldn't need to worry about ever filling in area to the sides of your game rectangle. The narrowest aspect ratio of any phone or tablet seems to be 9:16, so you can do the math to see how much extra background above and below the game rectangle should be drawn to avoid black showing through on any device.
In this case it works out to 48 units above and below the rectangle that you would want to fill in:
144 pixels wide at 9:16 would be 256 tall.
(256 - 160) / 2 = 48
EDIT: I see from your post on the libgdx forum that you want the game area stuck at the top of the screen and the remainder of the area to be used for game controls. In that case, I would change the resize method like this, since you want to have the game area's top edge aligned with the top edge of the screen. You can also calculate where the bottom of the controls area will be on the Y axis. (The top will be at Y=0.)
public void resize(int width, int height){
viewport.update(width, height, false);
//align game box's top edge to top of screen
Camera camera = viewport.getCamera();
camera.position.x = GAME_WIDTH /2;
camera.position.y = GAME_HEIGHT - viewport.getWorldHeight()/2;
camera.update();
controlsBottomY = GAME_HEIGHT - viewport.getWorldHeight();
}
I'm not sure how you plan to do your controls, but they would need to fit in the box (0, controlsBottomY) to (GAME_WIDTH, 0). Keep in mind that there are some phones with aspect ratios as small as 3:4 (although rare now). So with your 0.9 aspect ratio, on a 3:4 phone only the bottom 17% of the screen would be available for controls. Which might be fine if it's just a couple of buttons, but would probably be problematic if you have a virtual joystick.

Why does the sample author hardcode width and height for orthographic camera?(LibGdx Zombie Bird tutorial)

I am trying to follow along with the guide on here and learn LibGdx.
http://www.kilobolt.com/day-4-gameworld-and-gamerenderer-and-the-orthographic-camera.html
Here's the author's code for setting the width and height of the orthographic camera(camera used to project the 3d stuff all evenly into 2d?
private OrthographicCamera cam;
and later in a constructor
cam = new OrthographicCamera();
cam.setToOrtho(true, 136, 204);
Is there a reason why he choose to hardcode the width and height and not retrieve the height and width of the screen the game is being run on via Gdx.graphics.getWidth/getHeight?
(-from Changing the Coordinate System in LibGDX (Java))
You didn't understand how camera behaves. It doesn't matter if screen is 320x480 or 1080*1920 for camera. Camera uses own coordinate system. For example we have 1920*1080 screen. We DON'T wanna use pixels because it's bad practice. What we really want is to have own coordinate system of our world. If you have world 16*9 m then you can calculate that 1 m = 120 pixels. But your friend can have 800*450 screen and for him 1 m = 50 pixels. That's why we hardcode camera's width and height. But there is another problem here, the ratio. We considered that our ratio is 16/9 but some devices can have 4/3 ratio. Supporting a lot of ratios is very complex theme so i don't wanna mention it here.
Screenshots on different ratios of my game
If you want i can share with you my code. But note it isn't perfect and it's not complete game. And as you can see from screenshots i didn't hardcode height, only width. So i have empty space up and down.
If anyone is still struggling with this, I suggest reading into part 5, where the author explains how
"we are going to assume that the width of the game is always 136. The height will be dynamically determined! We will calculate our device's screen resolution and determine how tall the game should be."

Drawing subset of a gradient in libgdx

I know this question has been accessed before (like here), but I was wondering how to do the following. In my game, I have a scrolling background. There is for example a blue sky that is light blue at the bottom and gets darker the higher you go. This is not really possible with the suggested solution:
shapeRenderer.filledRect(x, y, width, height,
lightBlue, lightBlue, darkBlue, darkBlue);
since you can only give the colors that really will be shown. I would like to have a gradientPaint with at the top darkblue and the bottom lightblue that stretches out over for example 500 pixels. This, while I only draw only 200 pixels of it. With this, the color would still get darker when the background scrolls. Does anybody know how to do this with libgdx?
What you want is to see a smaller (say 200 pixel) window onto a larger (say 500 pixel) gradient. To do that you just need to compute the colors of four corners colors based on the location of your window in the overall gradient, and then draw just that. (So don't think about drawing the entire background, but about figuring out how to draw just the part that you need.)
Since you're just moving smoothly between the two colors (between 0 and 500), you're doing a "linear interpolation" (that is a straight-line estimation) between the colors based on where the Window is. Libgdx supports this via the lerp() methods on Color.
Assuming the window is travelling along the Y axis, something like this should give what you want:
Color baseColor = lightBlue;
Color topColor = darkBlue;
int skyHeight = 500;
int windowHeight = 200;
int windowLocation = ...; // something betweeen 0 and skyHeight - windowHeight;
Color windowBottomColor = baseColor.copy().lerp(topColor, windowLocation / skyHeight);
Color windowTopColor = baseColor.copy().lerp(topColor, (windowLocation + windowHeight) / skyHeight);
Now windowBottomColor and windowTopColor should be suitable for calling filledRect:
shapeRenderer.filledRect(x, y, width, height,
windowBottomColor, windowBottomColor, windowTopColor, windowTopColor);
Note that the "copy()" calls create a new Color object for each invocation, so you might want to optimize that to avoid the allocation.
Disclaimer: I haven't tried this code, so it probably has some stupid bugs in it, but hopefully it gives you the right idea.

Categories