I am currently experiencing issues when drawing and scaling sprites.
I am loading my assets from a texture-atlas, which I packed no problem with the LibGDX texture packer gui tool. My texture atlas image currently looks like this.
These images are supposed to be buttons, but as you can see, the image is very small, so when the sprites are loaded, they load a sprite of say, 34x16 pixels. When I render these buttons, on a canvas of 1920x1080, they are much too small. I use sprite.scale(int scale) to scale the sprites, but when I scale them, they appear blurry. What I would like to happen, is when they are scaled, each pixel is scaled proportionally, keeping the pixelated effect on the button, rather than a blurry resized image from a really small texture. I currently render the sprites using sprite.render(SpriteBatch batch). Is this the proper way of rendering a sprite, after they are loaded using atlas.createSprite(String name)? I am new to using sprites, and loading textures from a texture-atlas, so i am wondering if this is the correct way of doing things.
Also, when I initialize my game, I load numerous different Sprite objects from a TextureAtlas. Each sprite holds a texture that will represent a game object, however it is my understanding that you render a sprite using sprite.render(SpriteBatch batch), so therefore I could only use a sprite, loaded from the TextureAtlas for one game object, because I would also have to set the scale, and position of the sprite, as it represents the game object. I am used to loading a Texture, then rendering this texture using batch.render(), at a given position, but I don't see how this is possible if I am using a sprite. Even if I use batch.render(Sprite, x, y), I am unable to scale the sprite properly, because as I mentioned before, I would like to scale the sprite while maintaining a pixelated effect, and even so, using the Sprite.scale() method, this would scale the Sprite object as a whole, making it impossible to use the Sprite's texture multiple times for numerous game objects.
Any suggestions would be greatly appreciated.
The code I am currently using to render/load the sprites is as follows:
Loading from TextureAtlas:
public static TextureAtlas atlas = new TextureAtlas(Gdx.files.internal("data/texture/pack/output/pack.pack"));
public static Sprite sprite = atlas.createSprite("buttonUp");
sprite.setScale(10);
Rendering Sprite: GdxGame.WIDTH/HEIGHT are 1920x1080. Though the Desktop window is scaled down from that size. Thus, everything is rendered as if the screen were 1920x1080.
batch = new SpriteBatch();
camera = new OrthographicCamera(GdxGame.WIDTH, GdxGame.HEIGHT);
camera.position.set(GdxGame.WIDTH/2, GdxGame.HEIGHT/2, 0);
camera.setToOrtho(false, GdxGame.WIDTH, GdxGame.HEIGHT);
public void render(float delta){
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
batch.setProjectionMatrix(camera.combined);
batch.begin();
camera.update();
sprite.draw(batch);
batch.end();
}
After further investigation, I have discovered that I can use Sprite.set(Sprite sprite) to make Sprite x a copy of Sprite y, and therefore render each sprite multiple times. However, this does not solve the issue of scaling the sprite. I must emphasize further that when rendering a scaled sprite, the scaling is not done by pixel, meaning that it is blurry. But, when rendering a TextureRegion, like: batch.draw(TextureRegion, x, y, width, height) if the width and height are greater than that of the original texture, it will scale each pixel, rather than blur the whole thing to try and make it look better. The following is an image of the blurriness I am talking about:
Notice how this sprite is scaled to be blurry, even though the original image is small, and pixelated.
What TextureFilter settings are you using in your code or in the texturepacker? Try the "Nearest" filter. If you have set it to "Linear" or alike, it will always take 4 texture pixels (texels) and interpolate them to get the color of the pixel to be drawn.
That might help against the blur, but I am not sure if it will produce exactly that 8-bit look you are aiming for...
Related
So I am having a little hard time understanding how ortographic cameras work in libgdx.
what I want is to have a camera that will only render things within a square while having another camera set the bounds for my whole screen.
So here, I was able to do what I wanted on the whole screen for the game pad. But, the thing you see on the top right is the background map of the game and i want to render the parts only fall within the red square you see here. How do I achieve that?
Are cameras supposed to do that or do I need to figure out a way to do it manually? I am really confused as to how cameras and projection matrices work.
Here on this screen, The red square and the green pad on the left are being drawn using the projection matrix of my screen camera. The map(top right) is drawn using my map cam.
Map cam is a view port of 400x400 but as you can see , the tiles are rectangular and that isnt the aspect ration i want. If someone can briefly explain how cameras work , I'd greatly appreciate it.
The reason I am not posting my code here is because I feel like I need to understand how camera mechanics work to even code it properly so I want to address that issue first.
Following #Tenfour04's advice worked perfectly. In case anyone wonders what I wanted to achieve. Here's a picture.
A camera alone cannot crop off part of the screen. For that you need to use glViewport. There is already a Viewport class in Libgdx that can do that for you. You will need two orthographic cameras (one for the map and one for the GUI), but the viewport can create its own.
private Viewport viewport;
//in create:
viewport = new FitViewport(400, 400);
//in resize:
viewport.update(width, height);
//in render:
viewport.getCamera().position.set(/*...move your map camera as needed*/);
viewport.apply(); //viewport cropped to your red square
batch.setProjectionMatrix(viewport.getCamera().combined);
batch.begin();
//draw map
batch.end();
//return to full screen viewport
Gdx.gl.glViewport(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
batch.setProjectionMatrix(yourGUICamera.combined);
batch.begin();
//draw gui
batch.end();
What happens, is the camera will fit itself to the size of the screen. In order to change this, you would want to use a FrameBuffer. The frame buffer will constrain the camera into the desired size, then can be drawn as a texture.
Create the frame buffer with the dimensions being in pixels.
//Initialize the buffer
FrameBuffer fbo = new FrameBuffer(Format.RGB565, width, helght, false);
Render the world within the buffer.
fbo.begin();
//Draw the world here
fbo.end();
Draw the buffer to the screen with a batch.
batch.begin();
batch.draw(fbo.getColorBufferTexture(), x, y);
batch.end();
I am currently working on a game in which i need pixel perfect collision with objects. The only obstacle i had gotten to however, is with actually getting a mask of the object. I thought about rendering a sprite of an object (which is properly scaled and transformed) to FrameBuffer, which then i'd convert to a pixmap, but i had no luck doing it (tried many methods, including this)
So, my question is: Is there a way of rendering a single sprite to a pixmap in LibGDX?
Sounds like putting the horse behind the cart. A Sprite is a region of a Texture, which in turn is an image loaded from file aka Pixmap. If you just want to load the image from file then you can do: new Pixmap(Gdx.files.internal("yourfile.png"));. You can also scale and transform your coordinates without rendering to a FBO first.
That said; getting the Pixmap of a FrameBuffer is as "simple" as taking a screenshot while the FBO is bound, because it is exactly that.
fbo.begin();
Gdx.gl.glClear(...);
... //render to the FBO
Pixmap pixmap = ScreenUtils.getFrameBufferPixmap(0, 0, fbo.getWidth(), fbo.getHeight());
fbo.end();
Note that this will look like it is up-side-down.
But you are probably only interested in the pixel data, so you might as well skip the Pixmap step in that case and use the ScreenUtils.getFrameBufferPixels method.
However, that said; using the pixel data for collision detection is most likely not the best solution for whatever it is you are trying to achieve. Instead I'd advise to look into other options, for example have a look at this tool which can be used to convert your images into a collision shape.
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.
I am making libgdx game, and i want to have smooth circle character. Now i have 128 x 128 circle texture, which looks proppertly in paintnet but have ragged edges in game . I draw this texture by:
width=height=Gdx.graphics.getWidth()/4;
game.batch.draw(game.assets.good_guy,x,y,width,height);
I have tried to use photoshop, paintnet, gimp and inkscape but the texture was ragged all the time.
This is how it looks like in game:
And this is how looks texture:
try to keep the aspect ratio, if your texture is 128x128 and you as another ratio scales can show sawtooth, read about texture filtrer http://www.badlogicgames.com/wordpress/?p=1403 or use, svg or OpenVG Is there a way to incorporate vector graphics into LibGDX development?
I am using the animation class to make a simple animation, with only 2 frames.
With animation, i can get the index, or texture region at the current time.
if (!animation.isAnimationFinished(time))
time += Gdx.graphics.getDeltaTime();
else
time = 0;
But the problem is, that I can't load any texture, its width and height must be a power of 2, so i got a big 1024x1024 texture, that has the 2 images.
With sprite.setTexture() i can only put a Texture, but animation.getframe returns a texture region.
Is there a way to change the sprite texture with an animation?
Also
sprite.setTexture(animation.getKeyFrame(time).getTexture());
Does not work.
This works
sprite = new Sprite(animation.getKeyFrame(time));
But I don't think is the best idea... I think is slow can can make bugs.
You usually use TextureRegion for sprites. The method that you are looking for is TextureRegion#setRegion (Sprite extends TextureRegion).
Like this:
sprite.setRegion(animation.getKeyFrame(time));