pygame: how to display full-screen without cutting off edges - pygame

My game is designed to work with a 16:9 display ratio.
However, my computer monitor does not have a 16:9 display. So, I've tried various methods to tell pygame to stretch the game window to full-screen, And I've encountered various problems such as:
1- The screen goes black, and my monitor says: "resolution mismatch".
2- The game window gets stretched to fit, and this messes up the graphics.
3- The edges of the screen get cut off, this is VERY unacceptable as it would give some players a disadvantage concerning how much of the playing field they can see!
I want pygame to display the game in full-screen without cutting off edges...I want it to add black bars to ether the top and bottom, or the left and right edges of the screen when necessary-depending on the players monitor.
Thanks in advance!
(And honestly, I can't believe I'm having so much trouble with what should be just a simple command, but I can't find answers anywhere!)

This is how you would scale the screen to fit any monitor, while still keeping the aspect ratio.
First you would use this code (or similar) to calculate what the screen needs to be scaled to:
import pygame
pygame.init()
infostuffs = pygame.display.Info() # gets monitor info
monitorx, monitory = infostuffs.current_w, infostuffs.current_h # puts monitor length and height into variables
dispx, dispy = <insert what you want your display length to be>, <and height>
if dispx > monitorx: # scales screen down if too long
dispy /= dispx / monitorx
dispx = monitorx
if dispy > monitory: # scales screen down if too tall
dispx /= dispy / monitory
dispy = monitory
dispx = int(dispx) # So your resolution does not contain decimals
dispy = int(dispy)
This gives you dispx and dispy, which are the dimensions that you should scale your display to every loop before you update the display. Also, just to warn you, I have not been able to test this code. If there is anything wrong, please tell me in the comments so I can fix it.
EDIT: Added two more lines of code.

I have not tried it, but my approach would be:
1. 16 / 9 ~= 1.778
2. `pygame.init()` ; `scr = pygame.display.Info()` ; `win_size = width, height = scr.current_w, scr.current_h` should give the display width and height.
3. Multiply height by 1.778, `x = int(height * 1.778)`.
4. If x < width, then width = x.
5. If not, then divide width by 1.7788, `y = int(width / 1.778)`. Now, height = y
6. `win_size = width, height` ; `screen = pygame.display.set_mode(win_size, FULLSCREEN)`
7. Scale and center align your graphics to fit.

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

Cocos-2dx v3 centering background sprite problems

Here is my background image:
And here is some code that I would assume scales this image to fully fit the screen.
Size visibleSize = Director::getInstance()->getVisibleSize();
auto bg = Sprite::create("grad.png");
bg->setScale(visibleSize.width / bg->getContentSize().width, visibleSize.height / bg->getContentSize().height);
bg->setAnchorPoint(Vec2(0,0));
addChild(bg);
I would expect those 4 lines to create a background sprite that would cover the entire screen size. However, here's a screenshot of what I am actually getting on my iPhone6+:
If I change the first line to
Size visibleSize = Director::getInstance()->getWinSize();
Then this is what I get, which isn't quite right either:
Using VisibleSize is correct, you just need one more change:
bg->setPosition(director->getVisibleOrigin());
By default, cocos2d-x uses ResolutionPolicy::NO_BORDER, so the bottom part of winSize is likely to be cropped.
getVisibleSize() returns the visible origin in Point rather then pixel.

Offset with resolution policy = showall

When using ResolutionPolicy::SHOW_ALL as resolution policy, you get some black gaps on both right and left sides.
I used
Director* director = Director::getInstance();
offset = director->getVisibleOrigin();
for getting the offset (the width of the gaps), but offset.x and offset.y is giving always 0, so I wonder: How should I calculate the offset of my main screen?
Have you read this documentation, http://www.cocos2d-x.org/wiki/Multi_resolution_support.
I am not sure, but you don't want those gaps on screen, do you ?
Use relative coordinate, and you will be fine.
Also, if you want gap's width anyways, you can use getFrameSize() (Also on that doc) to get screen's actual display resolution , and do some calculations to get that width.

Collision box for AS3 + papervision3d + jiglib

I'm trying to recreate the "tutorial" explained on the site below. It's 5 dices bouncing around on the scene. But i'm stuck at the very beginning :)
papervision3d-jiglib-dice-demo
My problem is the bounding box. I want to create a box with a floor and 4 walls based on the size of the stage. I can get it the right size using zoom/focus on the camera. But the problem is the dices go through it.
How can i build 4 walls and make sure a dice doesnt go through it when i apply forces to it?
I tried the solution in the following source, but somehow the dices keep going through :(
throwing-dice-with-the-jiglib-physics-engine-and-away3d
Anybody knows how to do it? Or a better way to keep the dices on screen?
I solved the problem. Just to share with others who want to try the same:
Set camera zoom = 2
Set camera focus = distance / zoom
// now the scene width and height match the actual size of the stage.
add the planes for all sides and make sure you make the segments smaller then the dice size. (EG: dice size = 30; stage width = 300; segments = stage width/ dice size = 10).
make sure you ceil the results because segments require int
Ofcourse you can make it larger, but then it will be harder to render.
I made the height of the planes a little smaller then twice the dice size to make sure they never get on top of eachother.
And finally add a ceiling by placing another plane with small segments on top of the other planes