How to make Sprites support different screen sizes? - libgdx

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.

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.

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).

MovieClips scale down when StageScaleMode.NO_BORDER

I have my stage aligned to TOP_LEFT and scaled to StageScaleMode.NO_BORDER, the width and height of my SWF are : width = 1920 and height = 1080.
The thing is when my i change the SWF size to bigger (height/width) the movieClips on the stage scale up and that's a good thing for me, but when i reduce the size of my SWF to smaller values (smaller than the default size), the movieClips get reduced as well, aren't they supposed to stay the same, if not is there a way to make that happen ?
In fact the NO_BORDER scaleMode makes sure to not show the borders of the SWF and scale the center depending on the :
The ratios :
widthRatio = currentStageWidth/stageWidth
and
heightRatio = currentStageHeight/stageHeight.
The stageWidth and stageHeight are provided by AS3.
The currentStageWidth and currentStageHeight are supposed to be changing while resizing the browser window, the can be retrieved from the Flash Object (ie: $("#flashObjectId").width()).
Then we should compare the two ratios (widthRatio and heightRatio), the bigger one has the scale value for the stage and the other elements on the stage.

libGDX texture quality scaling down

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.

How to scale buffer images of the lwjgl Display

I wanted to know how I could change the scale of the buffer images so that I could render a resolution of say 320x240 as 640x480.
Ok, here is what to do:
For 2D games you can set the screen resolution with the 'setDisplayMode' method, but if you want the screen to be scaled to whatever you want, you have to change the width and height of the 'glOrtho' method to the scaled resolution you want.
Here is an example:
Display.setDisplayMode(new DisplayMode(width, height));
...
glOrtho(0, width/scale, height/scale, 0, 1, -1);