modnarrandom
modnarrandom

Reputation: 161

Pygame resizing a surface and window based on a rect size

I have a display area and a surface that is blitted on the display. On the surface is an image, in this case a rect. In the future it may be multiple rects or lines drawn on the surface keep that in mind.

I am trying to enlarge (by pressing x) the Rect named Sprite that is on SpriteSurface and SpriteSurface as well as the whole display window. The SpriteSurface image should be centered despite the resize. Currently the window will enlarge and the image stays centered, but if you uncomment the spritesizeX and Y lines the image gets larger but too big too fast and the window doesn't seem to enlarge big enough. Lowering the values shows that the offset of centering gets thrown off after the first resize. I feel like the solution should be relatively easy but im stumped. Any help would be appreciated.

Settings.py

spriteSizeX = 30
spriteSizeY = 30
SpHalfX = int(round(spriteSizeX / 2))
SpHalfY = int(round(spriteSizeY / 2))
multiplyer = 3
windowSizeX = int(round(spriteSizeX * multiplyer))
windowSizeY = int(round(spriteSizeY * multiplyer))
HalfWinX = int(round((windowSizeX / 2) - SpHalfX))
HalfWinY = int(round((windowSizeY / 2) - SpHalfY))

Orange = (238,154,0)
Gold = (255,215,0)
Black = (0,0,0)
Blue = (0,0,255)
Gray = (128,128,128)
DarkGray = (100,100,100)
Green = (0,128,0)
Lime = (0,255,0)
Purple = (128,0,128)
Red = (255,0,0)
Teal = (0,200, 128)
Yellow = (255,255,0)
White = (255,255,255)

run = True

SpriteCapture.py

#!/usr/local/bin/python3.6
import sys, pygame
from pygame.locals import *
from settings import *

pygame.init()
pygame.display.set_caption("Sprite Capture")
Screen = pygame.display.set_mode((windowSizeX, windowSizeY),RESIZABLE)
SpriteSurface = pygame.Surface((spriteSizeX,spriteSizeY))
Sprite = Rect(0,0,spriteSizeX,spriteSizeY)

while run == True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()

        if pygame.key.get_pressed()[pygame.K_s]:
            pygame.image.save(SpriteSurface, 'img1.png')
            run = False

        if pygame.key.get_pressed()[pygame.K_q]:
            run = False

        if pygame.key.get_pressed()[pygame.K_z]:
            #spriteSizeX += 10
            #spriteSizeY += 10
            windowSizeX += -10
            windowSizeY += -10
            HalfWinX = int(round(windowSizeX / 2 - SpHalfX))
            HalfWinY = int(round(windowSizeY / 2 - SpHalfY))
            Screen = pygame.display.set_mode((windowSizeX, windowSizeY),RESIZABLE)
            SpriteSurface = pygame.Surface((spriteSizeX,spriteSizeY))

        if pygame.key.get_pressed()[pygame.K_x]:
            #spriteSizeX += 10
            #spriteSizeY += 10
            windowSizeX += 10
            windowSizeY += 10
            HalfWinX = int(round(windowSizeX / 2 - SpHalfX))
            HalfWinY = int(round(windowSizeY / 2 - SpHalfY))
            Screen = pygame.display.set_mode((windowSizeX, windowSizeY),RESIZABLE)
            SpriteSurface = pygame.Surface((spriteSizeX,spriteSizeY))

    Sprite = Sprite = Rect(0,0,spriteSizeX,spriteSizeY)
    Screen.fill(Black)
    pygame.draw.rect(SpriteSurface,Orange,Sprite)
    Screen.blit(SpriteSurface, (HalfWinX,HalfWinY))
    pygame.display.flip()

Upvotes: 0

Views: 1910

Answers (1)

skrx
skrx

Reputation: 20438

If you want to scale your surfaces or rects according to the screen size, you can define a zoom_factor variable which you can just increase when a key gets pressed and then use it to scale the window and the surfaces. Multiply it by the original screen width and height to scale the window, and also scale your surfaces with pygame.transform.rotozoom and pass the zoom_factor as the scale argument.

import sys
import pygame
from pygame.locals import *


width = 30
height = 30
multiplyer = 3
window_width = round(width * multiplyer)
window_height = round(height * multiplyer)
zoom_factor = 1
ORANGE = (238,154,0)
BLACK = (0,0,0)

pygame.init()
screen = pygame.display.set_mode((window_width, window_height), RESIZABLE)
screen_rect = screen.get_rect()  # A rect with the size of the screen.
clock = pygame.time.Clock()
# Keep a reference to the original image to preserve the quality.
ORIG_SURFACE = pygame.Surface((width, height))
ORIG_SURFACE.fill(ORANGE)
surface = ORIG_SURFACE
# Center the rect on the screen's center.
rect = surface.get_rect(center=screen_rect.center)

run = True
while run:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False
        elif event.type == pygame.KEYDOWN:
            if event.key == pygame.K_q:
                run = False
            elif event.key == pygame.K_z:
                zoom_factor = round(zoom_factor-.1, 1)
                # Scale the screen.
                w, h = int(window_width*zoom_factor), int(window_height*zoom_factor)
                screen = pygame.display.set_mode((w, h), RESIZABLE)
                screen_rect = screen.get_rect()  # Get a new rect.
                # Scale the ORIG_SURFACE (the original won't be modified).
                surface = pygame.transform.rotozoom(ORIG_SURFACE, 0, zoom_factor)
                rect = surface.get_rect(center=screen_rect.center)  # Get a new rect.
            elif event.key == pygame.K_x:
                zoom_factor = round(zoom_factor+.1, 1)
                w, h = int(window_width*zoom_factor), int(window_height*zoom_factor)
                screen = pygame.display.set_mode((w, h), RESIZABLE)
                screen_rect = screen.get_rect()
                surface = pygame.transform.rotozoom(ORIG_SURFACE, 0, zoom_factor)
                rect = surface.get_rect(center=screen_rect.center)
            # Note that the rect.w/screen_rect.w ratio is not perfectly constant.
            print(zoom_factor, screen_rect.w, rect.w, rect.w/screen_rect.w)

    screen.fill(BLACK)
    screen.blit(surface, rect)  # Blit the surface at the rect.topleft coords.
    pygame.display.flip()
    clock.tick(60)

Alternatively, you could just blit all of your surfaces onto a background surface, then scale this background with pygame.transform.rotozoom each frame and blit it onto the screen. However, scaling a big background surface each frame will be bad for the performance.

Upvotes: 2

Related Questions