libGDX texture quality scaling down - libgdx

i am new to libGDX and I just wanted to put a image onto the screen. I have a red ball image which is 800x800 and when i try draw the texture:
batch.draw(ball,50,50,50,50);
The quality of the ball is really bad, but when I don't scale it down, the quality is good.
Here is a image on what I see on the screen:http://prntscr.com/55oars
Any help on how to make the images more crisp and smoother?

From what I know you have two options.
One option is to have a FitViewport and constantly maintain your screen to be the same size which would ultimately preserve the quality of your images. In this case the FitViewport class would help you do this by adding black bars on the screen to take care of the extra space. Example:
private Viewport viewport;
private Camera camera;
public void create() {
camera = new PerspectiveCamera();
viewport = new FitViewport(800, 480, camera);
}
public void resize(int width, int height) {
viewport.update(width, height);
}
Another option is to have a TexturePacker and load images that are proportional for a given screen.
All in all while these approaches may seem a bit tedious they really are a better way to maintain "crisp and smooth" pictures throughout different screen sizes.
It is worth remembering that by resizing the image, you actually reduce the pixel count of the photo. Therefore when you try to resize the image some pixels are "lost" and the original texture cannot be reproduced hence loss of clarity.

Related

Interface gets extra pixel

I made an interface for a game, using extended viewport and when i resize the screen the aspect ratio changes and every element in scene is scales, but when this happens this is what i get :
This is the most annoying issue i dealt with, any advice ? I tried making the tower n times bigger and then just setting bigger world size for the viewport but same thing happens, idk what is this extra pixels on images..
I'm loading image from atlas
new TextureRegion(skin.getAtlas().findRegion("tower0"));
the atlas looks like this:
skin.png
size: 1024,1024
format: RGBA8888
filter: Nearest,Nearest
repeat: none
tower0
rotate: false
xy: 657, 855
size: 43, 45
orig: 43, 45
offset: 0, 0
index: -1
In the third picture, you are drawing your source image just slightly bigger than it's actual size in screen pixels. So there are some boundaries where extra pixels have to be filled in to make it fill its full on-screen size. Here are some ways to fix this.
Use linear filtering. For the best appearance, use MipMapLinearLinear for the min filter. This is a quick and dirty fix. The results might look slightly blurry.
Draw your game to a FrameBuffer that is sized to the same aspect ratio as you screen, but shrunk down to a size where your sprites will be drawn pixel perfect to their original scale. Then draw that FrameBuffer to the screen using an upsampling shader. There are some good ones you can find by searching for pixel upscale shaders.
The best looking option is to write a custom Viewport class that sizes your world width and height such that you will be always be drawing the sprites pixel perfect or at a whole number multiple. The downside here is that your world size will be inconsistent across devices. Some devices will see more of the scene at once. I've used this method in a game where the player is always traveling in the same direction, so I position the camera to show the same amount of space in front of the character regardless of world size, which keeps it fair.
Edit:
I looked up my code where I did option 3. As a shortcut, rather than writing a custom Viewport class, I used a StretchViewport, and simply changed its world width and height right before updating it in the game's resize() method. Like this:
int pixelScale = Math.min(
height / MIN_WORLD_HEIGHT,
width / MIN_WORLD_WIDTH);
int worldWidth = width / pixelScale;
int worldHeight = height / pixelScale;
stretchViewport.setWorldWidth(worldWidth);
stretchViewport.setWorldHeight(worldHeight);
stretchViewport.update(width, height, true);
Now you may still have rounding artifacts if your pixel scale becomes something that isn't cleanly divisible for both the screen width and height. You might want to do a bit more in your calculations, like round pixelScale off to the nearest common integer factor between screen width and height. The tricky part is picking a value that won't result in a huge variation in amounts of "zoom" between different phone dimensions, but you can quickly test this by experimenting with resizing a desktop window.
In my case, I merged options 2 and 3. I rounded worldWidth and worldHeight up to the nearest even number and used that size for my FrameBuffer. Then I draw the FrameBuffer to the screen at just the right size to crop off any extra from the rounding. This eliminates the possibility of variations in common factors. Quite a bit more complicated, though. Maybe someday I'll clean up that code and publish it.

Tile Texture If Dimensions of Sprite Are Larger Than Texture

I have a sprite that acts as a wall in a game that I am building. I would like to have the brick texture repeat itself instead of stretch to fit the height of the screen. I tried:
Texture lSideTexture = new Texture(Gdx.files.internal("wall.png"));
lSideTexture.setWrap(Texture.TextureWrap.Repeat, Texture.TextureWrap.Repeat);
lSideSprite = new Sprite(lSideTexture);
lSideSprite.setPosition(-50, -100 * (height/width) / 2);
lSideSprite.setSize(5,100 * (height/width));
But I am still getting a texture that has been stretched to fit the dimensions rather than repeated.
Any Ideas?
You also have to change the texture region of the Sprite to be bigger than the texture. So if you are drawing the sprite 5 times bigger than normal, you'd do this:
lsideSprite.setRegion(0, 0, 5f, 5f);
One "gotcha" here is that this method is overloaded to take all ints or all floats. If you use ints, then you specify the size in pixel dimensions. If you use floats, then you're specifying how many times you want it to repeat.

Sprite width to fit all resolutions cocos2dx

Cocos2dx beginner here. Using Cocos2dx V3.10.
I've read lots of tutorials and documentation on Multi platform support across iOS/Android etc and in the main i get it. I'm using setDesignResolutionSize in combination with setContentScaleFactor and it's working out pretty well so far.
I do have one issue which i'm not sure of the best way to approach it.
My game is portrait and i'd like a particular sprite to be the same width on iphone4s and iphone5.
They both use the same design resolution size and content scale factor but on iphone4 the sprite is smaller than that on iphone4 (and iphone5).
I've attached two images to demonstrate what i mean.
As you can see on the iphone4 the sprite isn't quite the same distance away from the edges as the iphone5 is, which i assume is down to the difference in resolution.
Do i need to create another set of assets for this resolution and how would i go about setting those? As currently iphone4 and iphone5 both use the same scale and design size, ie:
glview->setDesignResolutionSize(designResolutionSize.width, designResolutionSize.height, ResolutionPolicy::NO_BORDER);
Size frameSize = glview->getFrameSize();
// if the frame's height is larger than the height of medium size.
if (frameSize.height > mediumResolutionSize.height)
{
director->setContentScaleFactor(MIN(largeResolutionSize.height/designResolutionSize.height, largeResolutionSize.width/designResolutionSize.width));
searchPaths.push_back("hd");
FileUtils::getInstance()->setSearchPaths(searchPaths);
}
Any help much appreciated.
This can be done in a way so that the game will look same no matter what device you use.
First of all, comment out all the following code in your AppDelegate.cpp
/* if (frameSize.height > mediumResolutionSize.height)
{
director->setContentScaleFactor(MIN(largeResolutionSize.height/designResolutionSize.height, largeResolutionSize.width/designResolutionSize.width));
}
// if the frame's height is larger than the height of small size.
else if (frameSize.height > smallResolutionSize.height)
{
director->setContentScaleFactor(MIN(mediumResolutionSize.height/designResolutionSize.height, mediumResolutionSize.width/designResolutionSize.width));
}
// if the frame's height is smaller than the height of medium sxize.
else
{
director->setContentScaleFactor(MIN(smallResolutionSize.height/designResolutionSize.height, smallResolutionSize.width/designResolutionSize.width));
}
*/
Now, make sure all of your assets have been developed in reference to a canvas size which is ideally the size of your background.
Let's say that size is customWidth x customHeight.
Now edit the following lines in AppDelegate.cpp as below:
glview->setDesignResolutionSize(customWidth, customHeight, ResolutionPolicy::EXACT_FIT);
Size frameSize = glview->getFrameSize();
Your game will now look same irrespective of the device, as long as aspect ratio is maintained(which is same for all the phones, but different for tablets).

Increasing the width of line drawn using Shape Renderer in LibGDX

I am drawing a line using Shape Renderer in LibGDX and i am using Orthographic Camera in my code, so to increase the width i used
camera = new OrthographicCamera();
int lineWidth = 8; // pixels
Gdx.gl10.glLineWidth(lineWidth / camera.zoom);
Now, I get a wider line. But the problem arises when the screen power goes off and then turns on, the line becomes the normal one again. How to keep the width constant?
ShapeRenderer has the method rectLine that is intended to be used to draw thick lines. It draws a rotated filled rectangle with the smaller opposite sides centered on the points passed to it (as coordinates or as Vector2 objects). The method has the parameter width to set the line width.
You can see the documentation here
Example:
shapeRenderer.rectLine(new Vector2(x1,y1),new Vector2(x2,y2),lineWidth);
As you can see here:
libgdx Shaperenderer line .. How to draw line with a specific width
And here:
Libgdx gl10.glLineWidth()
And here:
Why Libgdx Gdx.gl10.glLineWidth(width); does not react to change projection properities
Playing with the line width in the shaperenderer isn't the best way to do what you want to achieve.
Try using a 1x1 white TextureRegion (you can change the color the Batch draws it with later), and draw it with the width and height that you desire:
batch.draw(region, x, y, width, height);

How to make Sprites support different screen sizes?

I am using libgdx to work on a game but just came across that how will I implement it for various screen sizes? I figured out how to position images for different sizes and resolutions but how do we make sprites support different screen sizes ? My background on 320x480 goes fine but takes a very small place on 480 by 800, how to accomplish this that it works on all the screens?
You have various options depending on what you are happy to do,
a. You could use a set of HQ sprites scaled down to fit in each of the screens something like;
in resize()
width = arg0;
height = arg1;
then in your render()
batch.draw(textureRegion, -width/2, -height/2, width, height);
will draw a sprite across the whole screen (assuming orthographic camera centered at 0,0)
b. You could use different sets of sprites for different resolutions you would then load a set sprites based on the dimensions of the viewport.
You could use scene2d.
There you can inform the scene, that the window resized in application
#Override
public void resize(int width, int height) {
stage.setViewport(width, height, true);
...
}
Divide your screen into virtual units, for example grid 10x10.
Calculate your virtual units from actual screen size.
VIRTUAL_UNIT_WIDTH = Gdx.graphics.getWidth()/10;
VIRTUAL_UNIT_HEIGHT = Gdx.graphics.getHeight()/10;
And set your sprite size via those virtual units, and use virtual units when calling spriteBatch.draw();
Like this you will be able to keep the same aspect ratio of the game trough various screen resolutions.
Hope that this gives you an idea.
I am using below approach and it's works for almost all screen sizes with ignoble minor scaling issue.
I always uses graphics images for screen size 1920.0x1080.0
ScreenViewport screenViewport=new ScreenViewport(camera);
screenViewport.setUnitsPerPixel(Math.min(1920.0f/Gdx.graphics.getWidth(),1080.0f/Gdx.graphics.getHeight()));
stage = new Stage(screenViewport);
#Override
public void resize (int width, int height) {
ScreenViewport screenViewport= (ScreenViewport) stage.getViewport();
screenViewport.setUnitsPerPixel(Math.min(1920.0f/width,1080.0f/height));
screenViewport.update(width,height,false);
}
Here you can set your approach from Math.min() or Math.max().
It will result your camera view-port size near to 1920.0*1080.0
Device screen-size Math.max() Math.max()
800.0x480.0 1800.0x1080.0 1920.0x1152.0
1920.0x1080.0 1920.0x1080.0 1920.0x1080.0
2048.0x1440.0 1536.0x1080.0 1920.0x1350.0
Note: Always use camera.viewportWidth and camera.viewportHeight for set positions of Games UI screens.