Testing resolution for pygame window on monitors

Joined
Dec 10, 2022
Messages
91
Reaction score
25
As the title says. Was just wondering if I could get some feedback on where the cyan square is placed on various screens.
On mine it's where I would expect. If the window is too big for the window close, pressing any key will close the window
I'll post the code and image of my screen

Python:
import pygame

pygame.init()



# Screen resolution and color
monitor = pygame.display.Info()
resolution = (monitor.current_w, monitor.current_h/1.1)
screen = pygame.display.set_mode(resolution)
screen_color = '#222222'

# Setup framerate
clock = pygame.time.Clock()
fps = 60

# Set some flags
running = True

player_sprite = pygame.sprite.Group()
allsprites = pygame.sprite.Group()

class Player(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.Surface((50,50))
        self.image.fill('cyan')
        self.rect = self.image.get_rect()
        self.rect.x = resolution[0]/2
        self.rect.y = resolution[1] - self.rect.height*1.5

        player_sprite.add(self)
        allsprites.add(self)

# Create the player
player = Player()

while running:
    screen.fill(screen_color)

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        if event.type == pygame.KEYDOWN:
            running = False

    allsprites.update()
    allsprites.draw(screen)

    pygame.display.update()
    clock.tick(fps)
 

Attachments

  • Kazam_screenshot_00000.png
    Kazam_screenshot_00000.png
    6.4 KB · Views: 5
Joined
Jul 4, 2023
Messages
463
Reaction score
56
pressing any key will close the window
BTW, no, you forgot to add pygame.quite() at the very bottom of your code. ;):cool:

Python:
import pygame

pygame.init()

#...

while running:
    screen.fill(screen_color)

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        if event.type == pygame.KEYDOWN:
            running = False

    allsprites.update()
    allsprites.draw(screen)

    pygame.display.update()
    clock.tick(fps)

pygame.quite()
 
Joined
Jul 4, 2023
Messages
463
Reaction score
56
the cyan square is placed on various screens.
On mine it's where I would expect
I guess your intention was to place it perfectly in the center relative to the x axis of the screen.

1723543152318.png

In the attached image, as you can see, it didn't quite work out, you forgot to include half the width of the cyan square in the calculations.
Python:
self.rect.x = (resolution[0] / 2) - (self.rect.width / 2)
1723543454481.png
 
Joined
Jul 4, 2023
Messages
463
Reaction score
56
BTW,
There is no direct scaling of the object in your code. The object's position is set statically relative to the screen resolution. This means that the object's size (50 x 50 pixels) remains the same, at different potential screen resolutions.

If you wanted to scale an object depending on the resolution, you could, for example, recalculate the object size based on the decision about the screen width or height, e.g. your code assumes working on a resolution of 1920 x 1080, after applying the object scaling, it should be seen "identically", proportionally, relative to the screen at other resolutions
Python:
# Define constants for base screen dimensions and player object size
BASE_SCREEN_WIDTH = 1920
BASE_SCREEN_HEIGHT = 1080
BASE_PLAYER_SIZE = 50

scale_width = monitor.current_w / BASE_SCREEN_WIDTH
scale_height = monitor.current_h / BASE_SCREEN_HEIGHT
self.image = pygame.Surface((BASE_PLAYER_SIZE * scale_width, BASE_PLAYER_SIZE * scale_height))

Such code would convey that the object will have a different size depending on the screen resolution, e.g. if the screen has a resolution of 3840 x 2160 (4K), then the object is twice as large as on a 1920 x 1080 (Full HD) screen.
1723548851806.png


If the screen resolution is 800 x 600, the object is almost twice as small as on a screen with a resolution of 1920 x 1080 (Full HD), while still maintaining the proportions relative to the screen and the base object size of 50 x 50 pixels
1723550852544.png


Python:
import pygame

pygame.init()

# Define constants for base screen dimensions and player object size
BASE_SCREEN_WIDTH = 1920
BASE_SCREEN_HEIGHT = 1080
BASE_PLAYER_SIZE = 50

# Screen resolution and color
monitor = pygame.display.Info()
resolution = (monitor.current_w, monitor.current_h / 1.1)
screen = pygame.display.set_mode(resolution)
screen_color = '#222222'

# Setup framerate
clock = pygame.time.Clock()
fps = 60

# Set some flags
running = True

player_sprite = pygame.sprite.Group()
allsprites = pygame.sprite.Group()

class Player(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        scale_width = resolution[0] / BASE_SCREEN_WIDTH
        scale_height = resolution[1] / BASE_SCREEN_HEIGHT
        self.image = pygame.Surface((BASE_PLAYER_SIZE * scale_width, BASE_PLAYER_SIZE * scale_height))
        self.image.fill('cyan')
        self.rect = self.image.get_rect()

        # Calculate Y position to be 1.5% of the screen height from the bottom
        offset_from_bottom = resolution[1] * 0.015
        self.rect.x = (resolution[0] / 2) - (self.rect.width / 2)
        self.rect.y = resolution[1] - self.rect.height - offset_from_bottom

        player_sprite.add(self)
        allsprites.add(self)

# Create the player
player = Player()

# Set up the font and text
BASE_FONT_SIZE = 32  # Base size for 2rem equivalent like in html
width_scale = resolution[0] / BASE_SCREEN_WIDTH  # Scale the font size based on screen width
font_size = int(BASE_FONT_SIZE * width_scale)  # Scaled font size
font = pygame.font.SysFont(None, font_size)

text = f"Current resolution: {int(resolution[0])} x {int(resolution[1])}"
text_surface = font.render(text, True, 'black', 'darkorange')

# Add padding to the text surface
padding = 10
text_rect = text_surface.get_rect()
text_rect.topleft = (20, 20)  # Position 20px from top-left corner
text_rect.inflate_ip(padding * 2, padding * 2)  # Add padding

while running:
    screen.fill(screen_color)

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        if event.type == pygame.KEYDOWN:
            running = False

    # Draw the red line in the center of the screen
    center_x = resolution[0] / 2
    pygame.draw.line(screen, 'red', (center_x, 0), (center_x, resolution[1]), 1)

    # Draw the text with information about: "Current resolution:"
    pygame.draw.rect(screen, 'darkorange', text_rect)
    screen.blit(text_surface, (text_rect.x + padding, text_rect.y + padding))

    allsprites.update()
    allsprites.draw(screen)

    pygame.display.update()
    clock.tick(fps)

pygame.quit()
 
Last edited:
Joined
Jul 4, 2023
Messages
463
Reaction score
56
Finally, IMHO,

1. Using Proportions Instead of Absolute Values

Instead of hard-coding object positions in pixels, developers use proportions relative to a base resolution. For example, if an object is meant to be placed 100 pixels from the right edge and 50 pixels from the bottom edge of the screen at a resolution of 1920x1080, its position is expressed as a percentage of that resolution:
  • X: 100 pixels is 100 / 1920 ≈ 0.052, or 5.2% of the width.
  • Y: 50 pixels is 50 / 1080 ≈ 0.046, or 4.6% of the height.
    When the window is launched on a different resolution, such as 1024 x 720, the object's position is calculated as:
  • X: 0.052 * 1024 ≈ 53 pixels from the right edge.
  • Y: 0.046 * 720 ≈ 33 pixels from the bottom edge.

2. Scaling Object Positions and Sizes

Developers often define a base resolution, such as 1920 x 1080, for which they create the game's layout. Then, when the game is launched on a different screen size, the positions and sizes of objects are scaled proportionally. For example, if an object is positioned at (1800, 800) in a 1920 x 1080 resolution, at 1024 x 720 it would be:
  • X: (1800/1920) * 1024 ≈ 960
  • Y: (800/1080) * 720 ≈ 533
    This way, the object will always be in the same proportional place on the screen.
1723552769059.png

Python:
import pygame

pygame.init()

# Define base resolution
BASE_RESOLUTION = (1920, 1080)
resolution_for_testing = ((800, 600), (1024, 720))
current_resolution = resolution_for_testing[0]
#current_resolution = resolution_for_testing[1]
screen = pygame.display.set_mode(current_resolution)
screen_color = '#222222'

# Set the window title with the current resolution
pygame.display.set_caption(f"Current resolution: {current_resolution[0]} x {current_resolution[1]}")

scale_x = current_resolution[0] / BASE_RESOLUTION[0]
scale_y = current_resolution[1] / BASE_RESOLUTION[1]

class Player(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        base_size = 50
        self.image = pygame.Surface((base_size * scale_x, base_size * scale_y))
        self.image.fill('cyan')
        self.rect = self.image.get_rect()

        # Set position proportionally to the bottom right corner
        self.rect.x = int(1800 * scale_x)
        self.rect.y = int(800 * scale_y)

player = Player()

# Main loop
running = True
while running:
    screen.fill(screen_color)
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False

    screen.blit(player.image, player.rect)
    pygame.display.update()

pygame.quit()

3. Centralizing Objects

If an object needs to be centered or placed in a specific part of the screen (e.g., the bottom-right corner), developers often calculate positions dynamically based on the screen resolution.
 
Joined
Jul 4, 2023
Messages
463
Reaction score
56

3. Centralizing Objects

If an object needs to be centered or placed in a specific part of the screen (e.g., the bottom-right corner), developers often calculate positions dynamically based on the screen resolution.
1723583025180.png


Python:
import pygame
from random import randint

pygame.init()


# Define base resolution
BASE_RESOLUTION = (1920, 1080)
resolution_for_testing = ((800, 600), (1024, 720))
current_resolution = resolution_for_testing[0]
#current_resolution = resolution_for_testing[1]
screen = pygame.display.set_mode(current_resolution)
screen_color = '#222222'

# Setup framerate
clock = pygame.time.Clock()
fps = 60

# Set the window title with the current resolution
pygame.display.set_caption(f'Current resolution: {current_resolution[0]} x {current_resolution[1]}')

scale_x = current_resolution[0] / BASE_RESOLUTION[0]
scale_y = current_resolution[1] / BASE_RESOLUTION[1]

# Define a Position class to store x and y coordinates
class Position:
    def __init__(self, x=0, y=0, named=''):
        self._x = x
        self._y = y
        self.named = named

class Player(pygame.sprite.Sprite):
    def __init__(self, position, color, z_index=0):
        pygame.sprite.Sprite.__init__(self)
        base_size = 50
        self.z_index = z_index
        self.image = pygame.Surface((base_size * scale_x, base_size * scale_y))
        self.image.fill(color)
        self.rect = self.image.get_rect()

        match position.named:
            case 'R1C1-Left-Top':
                self.rect.x = 0
                self.rect.y = 0
            case 'R1C1-Center-Center':
                self.rect.x = (current_resolution[0] / 4) - (self.rect.width / 2)
                self.rect.y = (current_resolution[1] / 4) - (self.rect.height / 2)
                
            case 'R1C2-Right-Top':
                self.rect.x = current_resolution[0] - self.rect.width
                self.rect.y = 0
            case 'R1C2-Right-Center':
                self.rect.x = current_resolution[0] - self.rect.width
                self.rect.y = (current_resolution[1] / 4) - (self.rect.height / 2)
            case 'R1C2-Right-Bottom':
                self.rect.x = current_resolution[0] - self.rect.width
                self.rect.y = (current_resolution[1] / 2) - self.rect.height
            case 'R1C2-Center-Bottom':
                self.rect.x = current_resolution[0] - (current_resolution[0] / 4) - (self.rect.width /2)
                self.rect.y = (current_resolution[1] / 2) - self.rect.height
            case 'R1C2-Center-Center':
                self.rect.x = current_resolution[0] - (current_resolution[0] / 4) - (self.rect.width / 2)
                self.rect.y = (current_resolution[1]  / 4) - (self.rect.height / 2)

            case 'R2C1-R2C2-Center-Center':
                self.rect.x = (current_resolution[0] / 2) - ((current_resolution[0] / 4) / 2) - (self.rect.width /2)
                self.rect.y = current_resolution[1] - ((current_resolution[1] / 4) * 1.5) - (self.rect.height /2)
                
            case 'Center-Center':
                self.rect.x = (current_resolution[0] / 2) - (self.rect.width / 2)
                self.rect.y = (current_resolution[1] / 2) - (self.rect.height / 2)
            case 'Center-Center-Left':
                self.rect.x = (current_resolution[0] / 2) - self.rect.width
                self.rect.y = (current_resolution[1] / 2) - (self.rect.height / 2)
            case 'Center-Center-Right':
                self.rect.x = (current_resolution[0] / 2)
                self.rect.y = (current_resolution[1] / 2) - (self.rect.height / 2)
                
            case _:
                # Set position proportionally to the screen resolution
                self.rect.x = int(position._x * scale_x)
                self.rect.y = int(position._y * scale_y)

        self.title = f'Square: {color} {self.rect.x} x {self.rect.y}'

    def check_hover(self, mouse_pos):
        return self.rect.collidepoint(mouse_pos)

    def draw_tooltip(self, screen, mouse_pos):
        font = pygame.font.SysFont(None, 24)
        text_surface = font.render(self.title, True, pygame.Color('white'))
        text_rect = text_surface.get_rect()

        if mouse_pos[0] > 3 * current_resolution[0] / 4:
            text_rect.x = mouse_pos[0] - text_rect.width - 10
        else:
            text_rect.x = mouse_pos[0] + 10

        if mouse_pos[1] > current_resolution[1] - (text_rect.height * 2):
            text_rect.y = mouse_pos[1] - text_rect.height - 10
        else:
            text_rect.y = mouse_pos[1] + 10

        screen.blit(text_surface, text_rect)


def draw_grid_lines():
    # Draw the red, vertical line in the center of the screen (top to bottom)
    center_x = current_resolution[0] / 2
    pygame.draw.line(screen, 'red', (center_x, 0), (center_x, current_resolution[1]), 1)
    # Draw the red, horizontal line in the center of the screen (left to right)
    center_y = current_resolution[1] / 2
    pygame.draw.line(screen, 'red', (0, center_y), (current_resolution[0], center_y), 1)
    # Draw the red, vertical line in the third quarter of the screen (top to bottom)
    center_x = current_resolution[0] / 4
    center_y = current_resolution[1] / 2
    pygame.draw.line(screen, 'red', (center_x, center_y), (center_x, current_resolution[1]), 1)
    # Draw the red, horizontal line in the third quarter of the screen (left to right)
    center_x = current_resolution[0] / 2
    center_y = current_resolution[1] - (current_resolution[1] / 4)
    pygame.draw.line(screen, 'red', (0, center_y), (center_x, center_y), 1)   


# Create player objects with the given position
players = []
players.append(Player(Position(x=1800, y=800), 'Cyan'))
players.append(Player(Position(x=randint(0, 1920), y=randint(0, 1080)), 'Blue'))

players.append(Player(Position(named='R1C1-Left-Top'), 'Yellow'))
players.append(Player(Position(named='R1C1-Center-Center'), 'Yellow'))

players.append(Player(Position(named='R1C2-Right-Top'), 'Green'))
players.append(Player(Position(named='R1C2-Right-Center'), 'Green'))
players.append(Player(Position(named='R1C2-Right-Bottom'), 'Green'))
players.append(Player(Position(named='R1C2-Center-Bottom'), 'Green'))
players.append(Player(Position(named='R1C2-Center-Center'), 'Green'))

players.append(Player(Position(named='R2C1-R2C2-Center-Center'), 'Red'))

players.append(Player(Position(named='Center-Center'), 'Orange', 1))
players.append(Player(Position(named='Center-Center-Right'), 'Purple'))
players.append(Player(Position(named='Center-Center-Left'), 'Brown'))

# Sorting player by z-index value
players = sorted(players, key=lambda p: p.z_index)


# Main loop
running = True
while running:
    screen.fill(screen_color)
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
            
    draw_grid_lines()
    
    mouse_pos = pygame.mouse.get_pos()
    tooltip_drawn = False
    for player in players:
        screen.blit(player.image, player.rect)
        if player.check_hover(mouse_pos) and not tooltip_drawn:
            player.draw_tooltip(screen, mouse_pos)
            tooltip_drawn = True
    
    pygame.display.update()
    clock.tick(fps)

pygame.quit()
 
Joined
Dec 10, 2022
Messages
91
Reaction score
25
Thanks for the input. Very educational. You have taught me something new to work with. :)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,919
Messages
2,570,037
Members
46,444
Latest member
MadeleineH

Latest Threads

Top