I encountered a problem within my (very) simple project. When I draw text, it is displayed in a different position (and appareantly with different size) between Android (Samsung Galaxy S Advance) and Desktop.
In my renderer class I have:
private OrthographicCamera cam;
public final int WIDTH = 320;
public final int HEIGHT = 480;
private ShapeRenderer debugRenderer = new ShapeRenderer();
private SpriteBatch batch = new SpriteBatch();
private BitmapFont font;
And in my constructor:
MyClass(){
this.cam = new OrthographicCamera(WIDTH, HEIGHT);
this.cam.position.set(WIDTH/2, HEIGHT/2, 0);
this.cam.update();
font = new BitmapFont(Gdx.files.internal("data/fonts/font.fnt"));
font.setColor(Color.RED);
}
Finally, the render function:
public void render() {
// For each block y use this code:
// debugRenderer.begin(ShapeType.Filled);
// Rectangle rect = block.getBounds();
// debugRenderer.rect(rect.x, rect.y, rect.width, rect.height);
// debugRenderer.end();
// And then I draw my text:
batch.begin();
font.draw(batch, "Score: " + world.getScore(), 50,50)
batch.end();
}
All block dimensions are in absolute numbers (not relative to any variable like stage.getWidth() or something like that).
The result in Desktop is the following:
While in Android I have:
As you may see, blocks have the same distribution along the screen (in terms of % of screen covered), while text doesn't. It doesn't start in the same place and doesn't have the same height.
Does anybody know what I could be doing wrong?
Just in case it helps, blocks bounds are:
XPos: 45 * i
YPos: 45 * j
SizeX: 32
SizeY: 32
EDIT: Another consideration, the font I'm using is extracted from: https://github.com/libgdx/libgdx/tree/master/demos/superjumper
After this.cam.update(); do you do -
batch.setProjectionMatrix(this.cam.combined);
debugRenderer.setProjectionMatrix(this.cam.combined);
Related
#Override
public void create()
{
batch = new SpriteBatch();
shape = new ShapeRenderer();
velocity = new Vector2(100, 0);
position = new Rectangle(0, 5, 100, 100);
font = new BitmapFont();
font.setColor(Color.BLACK);
font.getData().scale(3f);
camera = new OrthographicCamera();
confCamera();
}
#Override
public void render()
{
if(Gdx.input.isTouched())
position.x = Gdx.input.getX() - position.width/2;
position.y = (Gdx.input.getY() - position.height/2);
shape.begin(ShapeRenderer.ShapeType.Filled);
shape.setColor(Color.BLACK);
shape.rect(position.x, position.y, position.width, position.height);
shape.end();
}
It's a simple code, but I'm not undestanding Y axis, my shape moves like a mirror. If I touch on top, my shape goes to bottom. If I touch on bottom, my shape goes to top. How to fix it?
LibGDX (by default) for rendering uses coordinate system where 0 is at bottom of the screen and the more you go up Y coordinate grows.
Also, when you read input coordinates (touches, moves...) you get screen coordinates, but when you render your graphics you are using "world" coordinates. They are in 2 different coordinate system so to convert from screen to world you have to use camera.unproject() call. Should be like:
Vector3 touchPos = new Vector3(Gdx.input.getX(), Gdx.input.getY(), 0);
camera.unproject(touchPos);
and then use touchPos.x and touchPos.y.
The similar question is asked here so you can find more answers there:
Using unProject correctly in Java Libgdx
I'm having problems setting my orthographic camera to the bottom left part of my screen (0,0)
public GameScreen(Main game) {
this.game = game;
Width = 200;
Height = 300;
view = new ExtendViewport(Width,Height);
camera = new OrthographicCamera(Gdx.graphics.getWidth(),Gdx.graphics.getHeight());
camera.setToOrtho(false,Width/2,Height/2);
camera.position.set(Width,Height,0);
camera.update();
play.Player1();
staple = new Stage();
staple.addActor(play);
staple.addActor(pile);
Gdx.input.setInputProcessor(staple);
}
#Override
public void render(float delta) {
Gdx.gl.glClearColor(0, 1, 1, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
Gdx.graphics.getDeltaTime();
game.getBatch().begin();
game.getBatch().setProjectionMatrix(camera.combined);
game.getBatch().end();
staple.act();
staple.draw();
}
#Override
public void resize(int width, int height) {
view.update(width,height);
view.setScreenPosition(width,height);
}
I've set my viewport as extended viewport using my width and height values I have assigned but I'm struggling to move the camera to the bottom left
part of my screen (0,0) where it can focus on my images on my android device.
Here are a little example how to use camera and viewport:
First we must define how big is our world the camera shows:
private static final int WORLD_WIDTH = 300;
private static final int WORLD_HEIGHT = 250;
Our world is now 300 x 250 units (not Pixel!) big.
It's importent to think in units not in pixels!!
Now we need a OrthographicCamera, a Viewport and a SpriteBatch
OrthographicCamera camera;
Viewport viewport;
SpriteBatch batch;
#Override
public void create () {
camera = new OrthographicCamera(); // we create a OrthographicCamera
viewport = new ExtendViewport(WORLD_WIDTH, WORLD_HEIGHT, camera); // we create a new Viewport with our camera and we will display our world 300 x 250 units
batch = new SpriteBatch(); // we create a new SpriteBatch for draw our textures
}
In our render method we say the batch only to draw what we can see in our Viewport with the method setProjectionMatrix()
#Override
public void render (float delta) {
camera.update(); //update our camera every frame
batch.setProjectionMatrix(camera.combined); //say the batch to only draw what we see in our camera
batch.begin();
batch.draw(texture, 0,0); //draw our texture on point 0,0 bottom left corner
batch.end();
}
And in the resize method:
public void resize(int width, int height){
viewport.update(width, height); //update the viewport to recalculate
}
To understand why you have this issue:
In your code you never set the camera to the viewport: view = new ExtendViewport(Width,Height);
So your viewport never apply to the batch.
To render the correct way without Viewport you must know that the position of OrhographicCamera is in the center.
So when you set a Camera to position 0,0 and size 50,50 you see the world from -25 to 25 in each direction;
To use OrthographicCamera without Viewport:
public void create () {
camera = new OrthographicCamera(WORLD_WIDTH, WORLD_HEIGHT); // we create a OrthographicCamera and we will display our world 300 x 250 units
camera.position.set(camera.viewportWidth / 2, camera.viewportHeight / 2, 0); //we set position of camera, our world point 0,0 is now the bottom left corner in the camera
batch = new SpriteBatch(); // we create a new SpriteBatch for draw our textures
texture = new Texture("badlogic.jpg");
}
public void render () {
camera.update();
batch.setProjectionMatrix(camera.combined);
batch.begin();
batch.draw(texture, 0,0);
batch.end();
}
The important point is in the resize method:
public void resize(int width, int height){
camera.viewportWidth = WORLD_WIDTH;
camera.viewportHeight = WORLD_HEIGHT * height / width;
camera.position.set(camera.viewportWidth / 2, camera.viewportHeight / 2, 0);
}
With this calculation you always see a World of 300 width and 250 * ratio of width, and height.
And exactly this calculation does the viewport for you. Depending on which Vieport (FitViewport, ScreenViewport, ExtendViewport) you use this calculation will be different, try it out.
I hope this helps you to understand how camera, viewport and Spritebatch works together.
Here are useful links to the libgdx wiki which descript the Viewport and Camera:
https://github.com/libgdx/libgdx/wiki/Viewports
https://github.com/libgdx/libgdx/wiki/Orthographic-camera
Use camera.position.set(Width, Height, 1); instead of 0
First you set the Camara width and height equal to the amount of pixels of the window.
camera = new OrthographicCamera(Gdx.graphics.getWidth(),Gdx.graphics.getHeight());
Then you center it at 100, 150. And move it again to 200, 300
camera.setToOrtho(false,Width/2,Height/2);
camera.position.set(Width,Height,0);
You are also using a Viewport but never make use of it.
I would recommend just using a Viewport of choice. A Viewport can take a camera so if you insist using your own camera you can create it but then also pass it to the Viewport when you construct it.
EDIT
Following is a tested minimal example.
public class TestScreen extends ScreenAdapter {
private Viewport viewport;
private ShapeRenderer sr;
public TestScreen() {
// Note that extend viewport extends it's camera so you end up with smaller or larger view of your world depending on the aspect ratio of the physical screen.
viewport = new ExtendViewport(200, 300);
viewport.apply();
System.out.println(viewport.getWorldWidth());
// Just for testing in the resize method.
viewport.getCamera().translate(0, 0, 0);
viewport.getCamera().update();
// ShapeRenderer for testing
sr = new ShapeRenderer();
sr.setAutoShapeType(true);
}
#Override
public void render(float delta) {
Gdx.gl.glClearColor(.04f, .06f, .1f, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
// Draw circle at 0.0 in the world
sr.setProjectionMatrix(viewport.getCamera().combined);
sr.begin(ShapeRenderer.ShapeType.Line);
sr.circle(0, 0, 100);
sr.end();
}
#Override
public void resize(int width, int height) {
// Will center the camera in the world at half it's width and half it's height so left bottom is 0.0 as long as the camera did.
// By using true here you cannot move the camera since you order it to center on the screen and thus the circle we are drawing
// remains in the bottom left.
//viewport.update(width, height, true);
// This will just update the viewport, we moved the camera slightly to the left so the circle appears slight right from the middle.
viewport.update(width, height, false);
// So you want to start your camera centered on something but still want to move it you need to specify that center in the camera
// by either changing it's position or translating it like I did in the constructor. Unfortunately you only get to know the size
// of the world that is being displayed once this resize method did it's job so certain parts might get cut off or your world does
// not fill the screen.
}
}
I am quite new to programming so bear with me here...
I am making a 2d basic game just to practice programming in android studio and can't get my sprite to the correct position on the screen. Also when I draw the sprite it appears stretched and the quality is very poor. Any help is appreciated!
public class MyGdxGame extends ApplicationAdapter {
SpriteBatch batch;
Texture background;
Texture ball;
#Override
public void create () {
batch = new SpriteBatch();
background = new Texture("gamebackground.png");
ball = new Texture("ball2.png");
}
#Override
public void render () {
batch.begin();
batch.draw(background, 0,0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
batch.draw(ball, 0,0, Gdx.graphics.getWidth() / 2, Gdx.graphics.getHeight() / 2);
batch.end();
}
You need to keep the original width/height ratio:
instead of scaling it to half the screen size, define your scaling like that:
float scaleFactor = 2.0f;
batch.draw(ball, 0,0, ball.getWidth()*scaleFactor, ball.getHeight*scaleFactor);
If your image is "blurry", and you want the individual pixels to stay crisp, try loading the texture like that:
ball = new Texture("ball2.png");
ball.setFilter(TextureFilter.Nearest, TextureFilter.Nearest);
This prevents (default) linear interpolation when scaling the texture.
I do a Mario like game with the libgdx library.
All works fine but sometime (especially when the camera goes fast) my TileMap has a little bug during the render.
A picture worth thousand word, so here it is : http://postimg.org/image/4tudtwewn/
I have tried to increment FPS, but there is no change. I have no idea where that is come from.
Here is my code :
public void show() {
TmxMapLoader loader = new TmxMapLoader();
this.plan = loader.load("maps/level-"+this.world+"-"+this.level+".tmx");
this.renderer = new OrthogonalTiledMapRenderer(this.plan);
...
public void render(float delta) {
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
this.renderer.render();// rendu de la carte
Batch batch = this.renderer.getSpriteBatch();
...
This happens when your Camera's position is not perfectly aligned with screen-space coordinates (pixels).
This results in some sprites being rounded to the next pixel while some other (that were connected to those) being rounded to the previous one, resulting in visible ugly glitches.
The easiest fix I could come up with is making sure that the Camera position is always perfectly aligned with screen-space coordinates.
public class TileMapCamera extends OrthographicCamera {
// Map tile size to round to
private int tileSize;
/**
* Create a pixel-perfect camera for a map with the specified tile size
* #param tileSize
*/
public TileMapCamera(int tileSize){
this.tileSize = tileSize;
}
#Override
public void update(){
// Round position to avoid glitches
float prevx = position.x;
float prevy = position.y;
position.x = (int)(position.x * tileSize) / (float)tileSize;
position.y = (int)(position.y * tileSize) / (float)tileSize;
super.update();
position.set(prevx, prevy, 0);
}
}
This works for a tile-based coordinate viewport:
mapViewport = new FitViewport(16, 15, new TileMapCamera(map.getProperties().get("tilewidth", Integer.class)));
If you're working with pixel-based coordinate viewports, you should round the camera position to the nearest integer instead.
I think its about the filtering.
This will help:
TiledMapRenderer Artifact
If the problem you are referring to, is the spacing you can fix when you import the tileset as it says Tenfour04
add or change pixel padding.
I'm creating a simple game for Android using libgdx. I've come to the issue of having different screen sizes for different devices yet haven't found any concreted documentation on how to deal with this problem.
I think I'm supposed to use an OrthographicCamera? An example of code I have so far is:
private OrthographicCamera camera;
public void create() {
batch = new SpriteBatch();
texture = new Texture(Gdx.files.internal("data/cube.png"));
texture.setFilter(TextureFilter.Linear, TextureFilter.Linear);
camera = new OrthographicCamera(1280, 720);
sprite = new Sprite(texture);
sprite.setOrigin(0, 0);
sprite.setPosition(1280/2, 600);
}
public void render() {
Gdx.gl.glClearColor(0.204f, 0.255f, 0.255f, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.setProjectionMatrix(camera.combined);
batch.begin();
sprite.draw(batch);
batch.end();
}
Am I going along the right lines? I don't have any other devices to test on and my emulators are causing me issues.
In case you didn't already do so, you should upgrade your LibGDX version to the latest release which is 1.0.0. In this version the socalled Viewport has been introduced.
You can find some screenshots and code snippets and everything you need to know here.
Basically you will have to decide for a certain strategy (your question sounds like you are interesting in either ScreenViewport or StretchViewport) and then let that manage your camera.
What I use in my libGDX projects is to override the resize method and set the OrthographicCamera to the size of the screen as follows, using the built in method called setToOrtho(boolean yDown) which sets camera centered on the current size which a parameter if you want the y-Axis pointing down or not:
#Override
public void resize(int width, int height){
camera.setToOrtho(false);
}
This, however will not change the size of your textures if you want to rescale your textures as well then I would recommend rather than setting them to an absolute size e.g 15 pixels try setting them to a percentage of the screen size.
Or, another, sometimes more effective method is to work out the correct sizes at a certain size e.g 800 x 480 then work out the percentage increase in width and apply that to your sprites E.g:
#Override
public void resize(int width, int height){
super.resize(width, height);
camera.setToOrtho(false);
//The following is if the sprites are normally correct scaled
//for a screen size of 800 x 480, change to whatever you need
//They should both be floats and class variables
widthChange = width / 800;
heightChange = height / 480;
}
public void render() {
Gdx.gl.glClearColor(0.204f, 0.255f, 0.255f, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.setProjectionMatrix(camera.combined);
batch.begin();
//Rather than using sprite.draw(batch), use:
batch.draw(sprite, sprite.x * widthChange, sprite.y * heightChange, sprite.width * widthChange, sprite.height * heightChange);
batch.end();
}