How to limit resizability in pygame [duplicate] - python

I have a window in pygame set up like this:
screen = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT),pygame.RESIZABLE)
As you can see, it is resizable, and that aspect is working perfectly, but if it is too small, then you can not see everything, and so I would like to set up a limit, of for example, you can not resize the screen to have a width os less then 600, or a height of less then 400, is there a way to do that in pygame?
Thank you!

You can use the pygame.VIDEORESIZE event to check the new windows size on a resize.
What you do is on the event, you check the new windows size values, correct them according to your limits and then recreate the screen object with those values.
Here is a basic script:
import pygame
from pygame.locals import *
pygame.init()
screen = pygame.display.set_mode((640,480), HWSURFACE|DOUBLEBUF|RESIZABLE)
while True:
pygame.event.pump()
event = pygame.event.wait()
if event.type == QUIT: pygame.display.quit()
else if event.type == VIDEORESIZE:
width, height = event.size
if width < 600:
width = 600
if height < 400:
height = 400
screen = pygame.display.set_mode((width,height), HWSURFACE|DOUBLEBUF|RESIZABLE)
EDIT: Depending on how your game graphics are drawn, you may want to resize them according to the windows resize (haven't tested that, just going after this example: http://www.pygame.org/wiki/WindowResizing)

Related

How can I tell if my game works at other resolutions? [duplicate]

So in every Pygame example I've seen, there seems to be a resolution the game is designed to be played on and that's it. No options for setting higher or lower resolutions. If you do change the resolution via display.set_mode, then the scale of the game textures/graphics get out of whack and the game becomes unplayable.
In all the examples I've seen, it looks like you would have to actually create different sized texture sets for each target resolution... Which seems ridiculous. That leads me to my question.
If I design a game based on a standard resolution of 480x270, is it possible to simply scale the output of that surface to 1080p (or 1440p, 4k, etc) while still utilizing the game assets built for 480x270? If so, can anyone post an example of how this can be accomplished? Any tips or pointers would also be appreciated.
You could make a dummy surface at the design resolution and scale it to the resolution the game is running at:
window = pygame.set_mode([user_x, user_y])
w = pygame.Surface([design_x, design_y])
def draw():
frame = pygame.transform.scale(w, (user_x, user_y))
window.blit(frame, frame.get_rect())
pygame.display.flip()
Draw everything on the dummy surface and it will be scaled to the screen. This requires a fixed screen height to screen width ratio.
Spent some time tinkering and put together a demo showcasing how you could go about tackling this problem. Find yourself an image for testing and put the string path to that image in the script for the value of imagePath.
The functionality of this script is simple. As you hit either left or right on the arrow keys, the screen resolution cycles through a tuple of acceptable resolutions and the screen resizes accordingly while scaling your test image to the new resolution.
import pygame,sys
from pygame import *
from pygame.locals import *
displayIndex = 0
pygame.init()
##standard 16:9 display ratios
DISPLAYS = [(1024,576),(1152,648),(1280,720),(1600,900),(1920,1080),(2560,1440)]
screen = pygame.display.set_mode(DISPLAYS[displayIndex])
screen.fill((0,0,0))
### change image path to a string that names an image you'd like to load for testing. I just used a smiley face from google image search.
### Put it in the same place as this file or set up your paths appropriately
imagePath = "Smiley-icon.png"
class Icon(pygame.sprite.Sprite):
def __init__(self,x,y):
pygame.sprite.Sprite.__init__(self)
self.smileyImage = pygame.image.load(imagePath)
self.image = self.smileyImage.convert_alpha()
### need to assume a default scale, DISPLAYS[0] will be default for us
self.rect = self.image.get_rect()
self.posX = x
self.posY = y
self.rect.x = x
self.rect.y = y
self.defaultx = (float(self.rect[2])/DISPLAYS[0][0])*100
self.defaulty = (float(self.rect[3])/DISPLAYS[0][1])*100
## this is the percent of the screen that the image should take up in the x and y planes
def updateSize(self,):
self.image = ImageRescaler(self.smileyImage,(self.defaultx,self.defaulty))
self.rect = self.image.get_rect()
self.rect.x = self.posX
self.rect.y = self.posY
def ImageRescaler(image,originalScaleTuple): #be sure to restrict to only proper ratios
newImage = pygame.transform.scale(image,(int(DISPLAYS[displayIndex][0]*(originalScaleTuple[0]/100)),
int(DISPLAYS[displayIndex][1]*(originalScaleTuple[1]/100))))
return newImage
def resizeDisplay():
screen = pygame.display.set_mode(DISPLAYS[displayIndex])
## this is where you'd have'd probably want your sprite groups set to resize themselves
## Just gonna call it on icon here
icon.updateSize()
icon = Icon(100,100)
while True:
screen.fill((0,0,0))
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == KEYDOWN:
if event.key == K_LEFT:
displayIndex -=1
if displayIndex < 0:
displayIndex = 5
resizeDisplay()
elif event.key == K_RIGHT:
displayIndex+=1
if displayIndex > 5:
displayIndex = 0
resizeDisplay()
screen.blit(icon.image,(icon.rect.x,icon.rect.y))
pygame.display.update()
The best way to go about this is by downscaling images, in order to preserve image quality. Here are two options:
Option 1
This method is probably the fastest.
Create images to be compatible with the largest resolution you are intending to support.
Create a screen with the user's desired size.
screen = pygame.display.set_mode((user_x, user_y))
Downscale images at load time
image = pygame.image.load("a.png").convert_alpha()
pygame.transform.scale(image, (screen.width() / your_max_width, screen.height() / your_max_height), DestSurface=image)
Now, just blit them normally. It should run at normal speeds.
Option 2
Create a screen with the user's desired size.
screen = pygame.display.set_mode((user_x, user_y))
Next, create a pygame.Surface with the highest resolution you are intending to support.
surface = pygame.Surface((1920, 1080))
Then, blit everything to that surface.
surface.blit(image, rect)
# Etc...
After all blits are completed, downscale the surface (as necessary) to whatever resolution the user desires. Preferably, you would only allow resolutions with the same aspect ratio.
pygame.transform.scale(surface, ((screen.width() / your_max_width, screen.height() / your_max_height), DestSurface=surface)
Finally, blit the surface to the screen, and display it.
screen.blit(surface, (0, 0))
pygame.display.update()
This process (downscaling) allows you to preserve image quality while still allowing the user to choose their screen resolution. It will be slower because you are constantly manipulating images.

How to increase the visual quality of pygame [duplicate]

So in every Pygame example I've seen, there seems to be a resolution the game is designed to be played on and that's it. No options for setting higher or lower resolutions. If you do change the resolution via display.set_mode, then the scale of the game textures/graphics get out of whack and the game becomes unplayable.
In all the examples I've seen, it looks like you would have to actually create different sized texture sets for each target resolution... Which seems ridiculous. That leads me to my question.
If I design a game based on a standard resolution of 480x270, is it possible to simply scale the output of that surface to 1080p (or 1440p, 4k, etc) while still utilizing the game assets built for 480x270? If so, can anyone post an example of how this can be accomplished? Any tips or pointers would also be appreciated.
You could make a dummy surface at the design resolution and scale it to the resolution the game is running at:
window = pygame.set_mode([user_x, user_y])
w = pygame.Surface([design_x, design_y])
def draw():
frame = pygame.transform.scale(w, (user_x, user_y))
window.blit(frame, frame.get_rect())
pygame.display.flip()
Draw everything on the dummy surface and it will be scaled to the screen. This requires a fixed screen height to screen width ratio.
Spent some time tinkering and put together a demo showcasing how you could go about tackling this problem. Find yourself an image for testing and put the string path to that image in the script for the value of imagePath.
The functionality of this script is simple. As you hit either left or right on the arrow keys, the screen resolution cycles through a tuple of acceptable resolutions and the screen resizes accordingly while scaling your test image to the new resolution.
import pygame,sys
from pygame import *
from pygame.locals import *
displayIndex = 0
pygame.init()
##standard 16:9 display ratios
DISPLAYS = [(1024,576),(1152,648),(1280,720),(1600,900),(1920,1080),(2560,1440)]
screen = pygame.display.set_mode(DISPLAYS[displayIndex])
screen.fill((0,0,0))
### change image path to a string that names an image you'd like to load for testing. I just used a smiley face from google image search.
### Put it in the same place as this file or set up your paths appropriately
imagePath = "Smiley-icon.png"
class Icon(pygame.sprite.Sprite):
def __init__(self,x,y):
pygame.sprite.Sprite.__init__(self)
self.smileyImage = pygame.image.load(imagePath)
self.image = self.smileyImage.convert_alpha()
### need to assume a default scale, DISPLAYS[0] will be default for us
self.rect = self.image.get_rect()
self.posX = x
self.posY = y
self.rect.x = x
self.rect.y = y
self.defaultx = (float(self.rect[2])/DISPLAYS[0][0])*100
self.defaulty = (float(self.rect[3])/DISPLAYS[0][1])*100
## this is the percent of the screen that the image should take up in the x and y planes
def updateSize(self,):
self.image = ImageRescaler(self.smileyImage,(self.defaultx,self.defaulty))
self.rect = self.image.get_rect()
self.rect.x = self.posX
self.rect.y = self.posY
def ImageRescaler(image,originalScaleTuple): #be sure to restrict to only proper ratios
newImage = pygame.transform.scale(image,(int(DISPLAYS[displayIndex][0]*(originalScaleTuple[0]/100)),
int(DISPLAYS[displayIndex][1]*(originalScaleTuple[1]/100))))
return newImage
def resizeDisplay():
screen = pygame.display.set_mode(DISPLAYS[displayIndex])
## this is where you'd have'd probably want your sprite groups set to resize themselves
## Just gonna call it on icon here
icon.updateSize()
icon = Icon(100,100)
while True:
screen.fill((0,0,0))
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == KEYDOWN:
if event.key == K_LEFT:
displayIndex -=1
if displayIndex < 0:
displayIndex = 5
resizeDisplay()
elif event.key == K_RIGHT:
displayIndex+=1
if displayIndex > 5:
displayIndex = 0
resizeDisplay()
screen.blit(icon.image,(icon.rect.x,icon.rect.y))
pygame.display.update()
The best way to go about this is by downscaling images, in order to preserve image quality. Here are two options:
Option 1
This method is probably the fastest.
Create images to be compatible with the largest resolution you are intending to support.
Create a screen with the user's desired size.
screen = pygame.display.set_mode((user_x, user_y))
Downscale images at load time
image = pygame.image.load("a.png").convert_alpha()
pygame.transform.scale(image, (screen.width() / your_max_width, screen.height() / your_max_height), DestSurface=image)
Now, just blit them normally. It should run at normal speeds.
Option 2
Create a screen with the user's desired size.
screen = pygame.display.set_mode((user_x, user_y))
Next, create a pygame.Surface with the highest resolution you are intending to support.
surface = pygame.Surface((1920, 1080))
Then, blit everything to that surface.
surface.blit(image, rect)
# Etc...
After all blits are completed, downscale the surface (as necessary) to whatever resolution the user desires. Preferably, you would only allow resolutions with the same aspect ratio.
pygame.transform.scale(surface, ((screen.width() / your_max_width, screen.height() / your_max_height), DestSurface=surface)
Finally, blit the surface to the screen, and display it.
screen.blit(surface, (0, 0))
pygame.display.update()
This process (downscaling) allows you to preserve image quality while still allowing the user to choose their screen resolution. It will be slower because you are constantly manipulating images.

pygame wont draw my circle in my pymunk simulation [duplicate]

This question already has answers here:
Why is nothing drawn in PyGame at all?
(2 answers)
Closed 1 year ago.
I'm fairly new to pymunk and I wanted to make physics engine for my future games, there's just a small problem, My code won't draw the circle that pygame is trying to visualize. Here's my code.
import pygame
import pymunk
import sys
def create_item(space):
body = pymunk.Body(1, 100, body_type = pymunk.Body.DYNAMIC)
body.position = (450, 50)
shape = pymunk.Circle(body, 80)
space.add(body, shape)
return shape
def draw_items(items):
for item in items:
pygame.draw.circle(screen, item_color, item.body.position, 80)
def quit():
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
def display_update():
screen.fill(bg_color)
clock.tick(FPS)
space.step(1/60)
pygame.display.flip()
# Constructor
pygame.init()
# Constants and Variables
WIDTH = 900
HEIGHT = 600
screen = pygame.display.set_mode((WIDTH, HEIGHT))
FPS = 60
clock = pygame.time.Clock()
# Colors
bg_color = 30, 30, 40
item_color = 200, 200, 200
# Pymunk Variables
space = pymunk.Space()
space.gravity = (0, 500)
items = []
items.append(create_item(space))
# Loops
def main():
running = True
while running:
quit()
display_update()
draw_items(items)
main()
I don't really know what the problem is here, it doesn't give me an error or something like that and I only get a clean blank canvas with my bg color.(also sorry for the bad comments)
You have to draw the objects before updating the display
def main():
running = True
while running:
quit()
screen.fill(bg_color)
draw_items(items)
pygame.display.flip()
clock.tick(FPS)
space.step(1/60)
You are actually drawing on a Surface object. If you draw on the Surface associated to the PyGame display, this is not immediately visible in the display. The changes become visibel, when the display is updated with either pygame.display.update() or pygame.display.flip().
The typical PyGame application loop has to:
handle the events by either pygame.event.pump() or pygame.event.get().
update the game states and positions of objects dependent on the input events and time (respectively frames)
clear the entire display or draw the background
draw the entire scene (blit all the objects)
update the display by either pygame.display.update() or pygame.display.flip()
limit frames per second to limit CPU usage

Scaling up window in pygame causing lag [duplicate]

This question already has an answer here:
Set the width and height of a pygame surface
(1 answer)
Closed 2 years ago.
Recently I've been trying to build a game in pygame in a low res, pixel art style.
In order to make my game usable I have to scale up my window, so here's a basic example of the code I've developed to do that, where SCALE in the value by which the whole window is scaled up, and temp_surf is the surface I blit my graphics onto before the scale function scales them up.
import sys
import ctypes
import numpy as np
ctypes.windll.user32.SetProcessDPIAware()
FPS = 60
WIDTH = 150
HEIGHT = 50
SCALE = 2
pg.init()
screen = pg.display.set_mode((WIDTH*SCALE, HEIGHT*SCALE))
pg.display.set_caption("Example resizable window")
clock = pg.time.Clock()
pg.key.set_repeat(500, 100)
temp_surf = pg.Surface((WIDTH, HEIGHT))
def scale(temp_surf):
scaled_surf = pg.Surface((WIDTH*SCALE, HEIGHT*SCALE))
px = pg.surfarray.pixels2d(temp_surf)
scaled_array = []
for x in range(len(px)):
for i in range(SCALE):
tempar = []
for y in range(len(px[x])):
for i in range(SCALE):
tempar.append(px[x, y])
scaled_array.append(tempar)
scaled_array = np.array(scaled_array)
pg.surfarray.blit_array(scaled_surf, scaled_array)
return scaled_surf
while True:
clock.tick(FPS)
#events
for event in pg.event.get():
if event.type == pg.QUIT:
pg.quit()
sys.exit()
if event.type == pg.KEYDOWN:
if event.key == pg.K_ESCAPE:
pg.quit()
sys.exit()
#update
screen.fill((0,0,0))
temp_surf.fill ((255,255,255))
pg.draw.rect(temp_surf, (0,0,0), (0,0,10,20), 3)
pg.draw.rect(temp_surf, (255,0,0), (30,20,10,20), 4)
scaled_surf = scale(temp_surf)
#draw
pg.display.set_caption("{:.2f}".format(clock.get_fps()))
screen.blit(scaled_surf, (0,0))
pg.display.update()
pg.display.flip()
pg.quit()
For this example, there is very little lag. However when I try to implement this code in my game, the fps drops from 60 to more like 10.
Is there a more efficient way of scaling up a pygame window that I don't know about? Would there be a way for my code to run more efficiently? I'm open to any suggestions.
Do not recreate scaled_surf in every frame. Creating a pygame.Surface my be an time consuming operation. Create scaled_surf once and continuously use it.
Furthermore I recommend to use pygame.transform.scale() or pygame.transform.smoothscale(), which are designed for this task:
scaled_surf = pg.Surface((WIDTH*SCALE, HEIGHT*SCALE))
def scale(temp_surf):
pg.transform.scale(temp_surf, (WIDTH*SCALE, HEIGHT*SCALE), scaled_surf)
return scaled_surf

why do i keep getting "video system not initialized" my pygame game? [duplicate]

So i wrote this code:
# Pygame development 4
# Focus on making code object oriented
# Introduce classes and objects into our code
# Gain access to the pygame library
import pygame
# Size of the screen
SCREEN_TITLE = 'Crossy RPG'
SCREEN_WIDTH = 500
SCREEN_HEIGHT = 500
# Colors according to RGB codes
WHITE_COLOR = (255, 255, 255)
BLACK_COLOR = (0, 0 , 0)
# Clock used to update game events and frames
clock = pygame.time.Clock()
pygame.font.init()
font = pygame.font.SysFont('comicsans', 75)
class Game:
# Typical rate of 60, equivalent to fps
TICK_RATE = 60
# Initializer for the game class to set up the width, height, and title
def __init__(self, title, width, height):
self.title = title
self.width = width
self.height = height
# Create the window of specified size in white to display the game
self.game_screen = pygame.display.set_mode((width, height))
# Set the game window color to white
self.game_screen.fill(WHITE_COLOR)
pygame.display.set_caption(title)
def run_game_loop(self):
is_game_over = False
# Main game loop, used to update all gameplay suh as movement, check, and graphics
# Runs unit is_game_over = True
while not is_game_over:
# A loop to get a;l of the events occuring at any given time
# Events are most often mouse movement, mouse and button clicks, or eit events
for event in pygame.event.get():
# If we have a quite type event(exit out) then exit out of the game loop
if event.type == pygame.QUIT:
is_game_over = True
print(event)
# Update all game graphics
pygame.display.update()
# Tick the clock to update everything within the game
clock.tick(self.TICK_RATE)
pygame.init()
new_game = Game(SCREEN_TITLE, SCREEN_WIDTH, SCREEN_HEIGHT)
new_game.run_game_loop()
pygame.quit()
quit()
Right now I am learning to code with python so im following a course online and since I couldn't get help from the forums of that website I thought I might ask the question here! So I've looked at the code multiple times to check for spelling mistakes but I couldn't find any and anyway i think that it's' not about something missing but it has something to do with pygame.display.update ! Can somebody pls help me?
Without running your code or having a stack trace of where the problem happens, we need to debug the code for you first. So it would be beneficial to add a full stack trace to your questions. I'm pretty confident however that there's two issues that you should work out.
pygame.display.update() should be correctly indented to be in the while loop of your main game event loop. Secondly, the pygame.init() should be run before any other initialization (or at least so I've been taught over the years and every example points to)
Try this out, I think it solves your problem:
# Pygame development 4
# Focus on making code object oriented
# Introduce classes and objects into our code
# Gain access to the pygame library
import pygame
pygame.init()
# Size of the screen
SCREEN_TITLE = 'Crossy RPG'
SCREEN_WIDTH = 500
SCREEN_HEIGHT = 500
# Colors according to RGB codes
WHITE_COLOR = (255, 255, 255)
BLACK_COLOR = (0, 0 , 0)
# Clock used to update game events and frames
clock = pygame.time.Clock()
pygame.font.init()
font = pygame.font.SysFont('comicsans', 75)
class Game:
# Typical rate of 60, equivalent to fps
TICK_RATE = 60
# Initializer for the game class to set up the width, height, and title
def __init__(self, title, width, height):
self.title = title
self.width = width
self.height = height
# Create the window of specified size in white to display the game
self.game_screen = pygame.display.set_mode((width, height))
# Set the game window color to white
self.game_screen.fill(WHITE_COLOR)
pygame.display.set_caption(title)
def run_game_loop(self):
is_game_over = False
# Main game loop, used to update all gameplay suh as movement, check, and graphics
# Runs unit is_game_over = True
while not is_game_over:
# A loop to get a;l of the events occuring at any given time
# Events are most often mouse movement, mouse and button clicks, or eit events
for event in pygame.event.get():
# If we have a quite type event(exit out) then exit out of the game loop
if event.type == pygame.QUIT:
is_game_over = True
print(event)
# Update all game graphics
pygame.display.update()
# Tick the clock to update everything within the game
clock.tick(self.TICK_RATE)
new_game = Game(SCREEN_TITLE, SCREEN_WIDTH, SCREEN_HEIGHT)
new_game.run_game_loop()
pygame.quit()
This also seams to be a school assignment and not a online course (but I might be wrong here), never the less I'll leave this piece of advice if I'm right. I strongly suggest that if you bump into problems, ask your teacher for guidance. As there's always a reason for teachers giving you a challenge/problem to solve. It teaches you the latest techniques you've learned in class, and if you can't solve the problem with the tools that you've been given - you've most likely haven't learned the fundamentals that has been taught out - and you should really re-do some steps.

Categories

Resources